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-2023 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  // Double data
6217  unsigned nflat_double_send = flat_double_send_packed_data.size();
6218  MPI_Isend(&nflat_double_send,
6219  1,
6220  MPI_DOUBLE,
6221  send_proc,
6222  3,
6223  comm_pt->mpi_comm(),
6224  &request);
6225 
6226  unsigned nflat_double_receive = 0;
6227  MPI_Recv(&nflat_double_receive,
6228  1,
6229  MPI_DOUBLE,
6230  receive_proc,
6231  3,
6232  comm_pt->mpi_comm(),
6233  &status);
6234 
6235  MPI_Wait(&request, MPI_STATUS_IGNORE);
6236 
6237  if (nflat_double_send != 0)
6238  {
6239  MPI_Isend(&flat_double_send_packed_data[0],
6240  nflat_double_send,
6241  MPI_DOUBLE,
6242  send_proc,
6243  4,
6244  comm_pt->mpi_comm(),
6245  &request);
6246  }
6247 
6248  if (nflat_double_receive != 0)
6249  {
6250  flat_double_receive_packed_data.resize(nflat_double_receive);
6251  MPI_Recv(&flat_double_receive_packed_data[0],
6252  nflat_double_receive,
6253  MPI_DOUBLE,
6254  receive_proc,
6255  4,
6256  comm_pt->mpi_comm(),
6257  &status);
6258  }
6259 
6260  if (nflat_double_send != 0)
6261  {
6262  MPI_Wait(&request, MPI_STATUS_IGNORE);
6263  }
6264  // --------------
6265 
6266 #ifdef PARANOID
6267  if (nflat_unsigned_receive != nflat_double_receive)
6268  {
6269  std::ostringstream error_message;
6270  error_message << "The number of unsigned received data ("
6271  << nflat_unsigned_receive << ") is different from the "
6272  << "number\nof double received data ("
6273  << nflat_double_receive << ")!!!\n\n";
6274  throw OomphLibError(
6275  error_message.str(),
6276  "TriangleMesh::synchronize_boundary_coordinates()",
6277  OOMPH_EXCEPTION_LOCATION);
6278  }
6279 #endif
6280 
6281  // With the received info. establish the boundary coordinates
6282  // for the face nodes that this processor is in charge (haloed
6283  // nodes)
6284  for (unsigned iflat_packed = 0; iflat_packed < nflat_unsigned_receive;
6285  iflat_packed++)
6286  {
6287  // Get the haloed id for the node
6288  const unsigned haloed_id =
6289  flat_unsigned_receive_packed_data[iflat_packed];
6290  // Get the boundary coordinates
6291  Vector<double> zeta(1);
6292  zeta[0] = flat_double_receive_packed_data[iflat_packed];
6293 
6294  // Get the haloed node
6295  Node* haloed_face_node_pt = this->haloed_node_pt(ip, haloed_id);
6296 
6297  // If the node has already set the boundary coordinates then
6298  // do not establish it. This is the case for the nodes that
6299  // lie on the boundary, for those nodes not identified on the
6300  // boundary since no elements lie on the boundary but the node
6301  // is on the boundary (a corner of an element lies on the
6302  // boundary) set boundary coordinates and register them to
6303  // send their info. to the processors with a halo counterpart
6304 
6305  // If the node is not haloed face in the procesor in charge
6306  // then set the boundary coordinates and register the node to
6307  // send back the boundary coordinates to the processors with a
6308  // halo counterpart
6309  if (!done_haloed_face_node[haloed_face_node_pt])
6310  {
6311  // Establish the boundary coordinates
6312  haloed_face_node_pt->set_coordinates_on_boundary(b, zeta);
6313 
6314  // Look in all processors where the node could be halo
6315  for (unsigned iiproc = 0; iiproc < nproc; iiproc++)
6316  {
6317  // Only work with processors different than the current one
6318  if (iiproc != my_rank)
6319  {
6320  // Get the number of haloed nodes with processor iiproc
6321  const unsigned nhaloed_node_iiproc = this->nhaloed_node(iiproc);
6322  for (unsigned ihdn = 0; ihdn < nhaloed_node_iiproc; ihdn++)
6323  {
6324  Node* compare_haloed_node_pt =
6325  this->haloed_node_pt(iiproc, ihdn);
6326  if (haloed_face_node_pt == compare_haloed_node_pt)
6327  {
6328  // Store the node on the haloed node vector for the
6329  // corresponding processor
6330  face_haloed_node_pt[iiproc].push_back(haloed_face_node_pt);
6331  // Now store the halo id of the node with the current
6332  // processor
6333  face_haloed_node_id[iiproc].push_back(ihdn);
6334  // Break searching in the current processor, search in
6335  // the next one
6336  break;
6337  } // if (haloed_face_node_pt==compare_haloed_face_node_pt)
6338  } // for (ihdn < nhaloed_node_iproc)
6339  } // if (iiproc != my_rank)
6340  } // for (iiproc < nproc)
6341  } // if (!done_haloed_face_node[haloed_face_node_pt])
6342  } // for (iflat_packed < nflat_unsigned_receive)
6343  } // if (ip != my_rank)
6344  } // for (ip < nproc)
6345 
6346  // -----------------------------------------------------------------
6347  // Fifth: The boundary coordinates have been established in the
6348  // processors in charge of the nodes. Now each processor send back
6349  // the boundary coordinates to all the processors where there is a
6350  // halo representation of the node
6351  // -----------------------------------------------------------------
6352 
6353  // Go through all processors
6354  for (unsigned ip = 0; ip < nproc; ip++)
6355  {
6356  // Only work with processors different than the current one
6357  if (ip != my_rank)
6358  {
6359  // Container to send the info. of the haloed nodes to all the
6360  // processors
6361  Vector<unsigned> flat_unsigned_send_packed_data;
6362  Vector<double> flat_double_send_packed_data;
6363 
6364  // Get the total number of haloed face nodes with the "ip"
6365  // processor
6366  const unsigned nhaloed_face_nodes = face_haloed_node_pt[ip].size();
6367  // Go through the haloed face nodes in the "ip" processor
6368  for (unsigned ihdfn = 0; ihdfn < nhaloed_face_nodes; ihdfn++)
6369  {
6370  // Get the "ihdfn"-th face node with the "ip" processor
6371  Node* haloed_face_node_pt = face_haloed_node_pt[ip][ihdfn];
6372  // Get the haloed id with the "ip" processor
6373  const unsigned haloed_id = face_haloed_node_id[ip][ihdfn];
6374  // Get the boundary coordinate of the node
6375  Vector<double> zeta(1);
6376  haloed_face_node_pt->get_coordinates_on_boundary(b, zeta);
6377  // Store the info. in the containers
6378  flat_unsigned_send_packed_data.push_back(haloed_id);
6379  flat_double_send_packed_data.push_back(zeta[0]);
6380  }
6381 
6382  // Send the info.
6383  MPI_Status status;
6384  MPI_Request request;
6385 
6386  // Processor to which send the info
6387  int send_proc = static_cast<int>(ip);
6388  // Processor from which receive the info
6389  int receive_proc = static_cast<int>(ip);
6390 
6391  // Storage to receive the info.
6392  Vector<unsigned> flat_unsigned_receive_packed_data;
6393  Vector<double> flat_double_receive_packed_data;
6394 
6395  // --------------
6396  // Unsigned data
6397  unsigned nflat_unsigned_send = flat_unsigned_send_packed_data.size();
6398  MPI_Isend(&nflat_unsigned_send,
6399  1,
6400  MPI_UNSIGNED,
6401  send_proc,
6402  1,
6403  comm_pt->mpi_comm(),
6404  &request);
6405 
6406  unsigned nflat_unsigned_receive = 0;
6407  MPI_Recv(&nflat_unsigned_receive,
6408  1,
6409  MPI_UNSIGNED,
6410  receive_proc,
6411  1,
6412  comm_pt->mpi_comm(),
6413  &status);
6414 
6415  MPI_Wait(&request, MPI_STATUS_IGNORE);
6416 
6417  if (nflat_unsigned_send != 0)
6418  {
6419  MPI_Isend(&flat_unsigned_send_packed_data[0],
6420  nflat_unsigned_send,
6421  MPI_UNSIGNED,
6422  send_proc,
6423  2,
6424  comm_pt->mpi_comm(),
6425  &request);
6426  }
6427 
6428  if (nflat_unsigned_receive != 0)
6429  {
6430  flat_unsigned_receive_packed_data.resize(nflat_unsigned_receive);
6431  MPI_Recv(&flat_unsigned_receive_packed_data[0],
6432  nflat_unsigned_receive,
6433  MPI_UNSIGNED,
6434  receive_proc,
6435  2,
6436  comm_pt->mpi_comm(),
6437  &status);
6438  }
6439 
6440  if (nflat_unsigned_send != 0)
6441  {
6442  MPI_Wait(&request, MPI_STATUS_IGNORE);
6443  }
6444 
6445  // --------------
6446  // Double data
6447  unsigned nflat_double_send = flat_double_send_packed_data.size();
6448  MPI_Isend(&nflat_double_send,
6449  1,
6450  MPI_DOUBLE,
6451  send_proc,
6452  3,
6453  comm_pt->mpi_comm(),
6454  &request);
6455 
6456  unsigned nflat_double_receive = 0;
6457  MPI_Recv(&nflat_double_receive,
6458  1,
6459  MPI_DOUBLE,
6460  receive_proc,
6461  3,
6462  comm_pt->mpi_comm(),
6463  &status);
6464 
6465  MPI_Wait(&request, MPI_STATUS_IGNORE);
6466 
6467  if (nflat_double_send != 0)
6468  {
6469  MPI_Isend(&flat_double_send_packed_data[0],
6470  nflat_double_send,
6471  MPI_DOUBLE,
6472  send_proc,
6473  4,
6474  comm_pt->mpi_comm(),
6475  &request);
6476  }
6477 
6478  if (nflat_double_receive != 0)
6479  {
6480  flat_double_receive_packed_data.resize(nflat_double_receive);
6481  MPI_Recv(&flat_double_receive_packed_data[0],
6482  nflat_double_receive,
6483  MPI_DOUBLE,
6484  receive_proc,
6485  4,
6486  comm_pt->mpi_comm(),
6487  &status);
6488  }
6489 
6490  if (nflat_double_send != 0)
6491  {
6492  MPI_Wait(&request, MPI_STATUS_IGNORE);
6493  }
6494  // --------------
6495 
6496 #ifdef PARANOID
6497  if (nflat_unsigned_receive != nflat_double_receive)
6498  {
6499  std::ostringstream error_message;
6500  error_message << "The number of unsigned received data ("
6501  << nflat_unsigned_receive << ") is different from the "
6502  << "number\nof double received data ("
6503  << nflat_double_receive << ")!!!\n\n";
6504  throw OomphLibError(
6505  error_message.str(),
6506  "TriangleMesh::synchronize_boundary_coordinates()",
6507  OOMPH_EXCEPTION_LOCATION);
6508  }
6509 #endif
6510 
6511  // With the received info. establish the boundary coordinates
6512  // received for the face nodes that this processor is not in
6513  // charge (halo nodes)
6514  for (unsigned iflat_packed = 0; iflat_packed < nflat_unsigned_receive;
6515  iflat_packed++)
6516  {
6517  // Get the halo id for the node
6518  const unsigned halo_id =
6519  flat_unsigned_receive_packed_data[iflat_packed];
6520  // Get the boundary coordinates
6521  Vector<double> zeta(1);
6522  zeta[0] = flat_double_receive_packed_data[iflat_packed];
6523 
6524  // Get the halo node
6525  Node* halo_face_node_pt = this->halo_node_pt(ip, halo_id);
6526 
6527  // It could be possible that the node has been already
6528  // established boundary coordinates since it is a halo face
6529  // node. However, for those elements not on the boundary, but
6530  // having a corner node on the boundary this procedure will
6531  // establish boundary coordinates for those nodes
6532 
6533  // this->add_boundary_node(b, halo_face_node_pt);
6534 
6535  // Establish the boundary coordinates
6536  halo_face_node_pt->set_coordinates_on_boundary(b, zeta);
6537  } // for (iflat_packed < nflat_unsigned_receive)
6538  } // if (ip != my_rank)
6539  } // for (ip < nproc)
6540 
6541  // Clean all the created face elements
6542  for (unsigned ie = 0; ie < nbound_ele; ie++)
6543  {
6544  delete tmp_face_ele_pt[ie];
6545  tmp_face_ele_pt[ie] = 0;
6546  }
6547 
6548  // Now get a new face mesh representation and fill the data for those
6549  // processors with halo segments
6550  if (is_internal_boundary)
6551  {
6552  re_scale_re_assigned_initial_zeta_values_for_internal_boundary(b);
6553  }
6554  }
6555 
6556  //======================================================================
6557  /// Re-assign the boundary segments initial zeta (arclength)
6558  /// for those internal boundaries that were splited during the
6559  /// distribution process (only apply for internal boundaries that
6560  /// have one face element at each side of the boundary)
6561  //======================================================================
6562  template<class ELEMENT>
6565  const unsigned& b)
6566  {
6567  // ------------------------------------------------------------------
6568  // First: Get the face elements associated with the current boundary
6569  // Only include nonhalo face elements
6570  // ------------------------------------------------------------------
6571  // Temporary storage for face elements
6572  Vector<FiniteElement*> face_el_pt;
6573 
6574  // Temporary storage for the number of elements adjacent to the
6575  // boundary
6576  unsigned nele = 0;
6577 
6578  // Temporary storage for elements adjacent to the boundary that have
6579  // a common edge (related with internal boundaries)
6580  unsigned n_repeated_ele = 0;
6581 
6582  const unsigned n_regions = this->nregion();
6583 
6584  // Temporary storage for already done nodes
6585  Vector<std::pair<Node*, Node*>> done_nodes_pt;
6586 
6587  // If there is more than one region then only use boundary
6588  // coordinates from the bulk side (region 0)
6589  if (n_regions > 1)
6590  {
6591  for (unsigned rr = 0; rr < n_regions; rr++)
6592  {
6593  const unsigned region_id =
6594  static_cast<unsigned>(this->Region_attribute[rr]);
6595 
6596  // Loop over all elements on boundaries in region i_r
6597  const unsigned nel_in_region =
6598  this->nboundary_element_in_region(b, region_id);
6599 
6600  unsigned nel_repetead_in_region = 0;
6601 
6602  // Only bother to do anything else, if there are elements
6603  // associated with the boundary and the current region
6604  if (nel_in_region > 0)
6605  {
6606  bool repeated = false;
6607 
6608  // Loop over the bulk elements adjacent to boundary b
6609  for (unsigned e = 0; e < nel_in_region; e++)
6610  {
6611  // Get pointer to the bulk element that is adjacent to
6612  // boundary b
6613  FiniteElement* bulk_elem_pt =
6614  this->boundary_element_in_region_pt(b, region_id, e);
6615 
6616  // Remember only to work with nonhalo elements
6617  if (bulk_elem_pt->is_halo())
6618  {
6619  n_repeated_ele++;
6620  continue;
6621  }
6622 
6623  // Find the index of the face of element e along boundary b
6624  int face_index =
6625  this->face_index_at_boundary_in_region(b, region_id, e);
6626 
6627  // Before adding the new element we need to be sure that the
6628  // edge that this element represent has not been already
6629  // added
6630  FiniteElement* tmp_ele_pt =
6631  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
6632 
6633  const unsigned n_nodes = tmp_ele_pt->nnode();
6634 
6635  std::pair<Node*, Node*> tmp_pair = std::make_pair(
6636  tmp_ele_pt->node_pt(0), tmp_ele_pt->node_pt(n_nodes - 1));
6637 
6638  std::pair<Node*, Node*> tmp_pair_inverse = std::make_pair(
6639  tmp_ele_pt->node_pt(n_nodes - 1), tmp_ele_pt->node_pt(0));
6640 
6641  // Search for repeated nodes
6642  const unsigned n_done_nodes = done_nodes_pt.size();
6643  for (unsigned l = 0; l < n_done_nodes; l++)
6644  {
6645  if (tmp_pair == done_nodes_pt[l] ||
6646  tmp_pair_inverse == done_nodes_pt[l])
6647  {
6648  nel_repetead_in_region++;
6649  repeated = true;
6650  break;
6651  }
6652  }
6653 
6654  // Create new face element
6655  if (!repeated)
6656  {
6657  // Add the pair of nodes (edge) to the node dones
6658  done_nodes_pt.push_back(tmp_pair);
6659  // Add the element to the face elements
6660  face_el_pt.push_back(tmp_ele_pt);
6661  }
6662  else
6663  {
6664  // Clean up
6665  delete tmp_ele_pt;
6666  tmp_ele_pt = 0;
6667  }
6668 
6669  // Re-start
6670  repeated = false;
6671 
6672  } // for nel
6673 
6674  nele += nel_in_region;
6675 
6676  n_repeated_ele += nel_repetead_in_region;
6677 
6678  } // if (nel_in_region > 0)
6679  } // for (rr < n_regions)
6680  } // if (n_regions > 1)
6681  // Otherwise it's just the normal boundary functions
6682  else
6683  {
6684  // Loop over all elements on boundaries
6685  nele = this->nboundary_element(b);
6686 
6687  // Only bother to do anything else, if there are elements
6688  if (nele > 0)
6689  {
6690  // Check for repeated ones
6691  bool repeated = false;
6692 
6693  // Loop over the bulk elements adjacent to boundary b
6694  for (unsigned e = 0; e < nele; e++)
6695  {
6696  // Get pointer to the bulk element that is adjacent to
6697  // boundary b
6698  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
6699 
6700  // Remember only to work with nonhalo elements
6701  if (bulk_elem_pt->is_halo())
6702  {
6703  n_repeated_ele++;
6704  // Skip the halo element
6705  continue;
6706  }
6707 
6708  // Find the index of the face of element e along boundary b
6709  int face_index = this->face_index_at_boundary(b, e);
6710 
6711  // Before adding the new element we need to be sure that the
6712  // edge that this element represents has not been already
6713  // added (only applies for internal boundaries)
6714  FiniteElement* tmp_ele_pt =
6715  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
6716 
6717  const unsigned n_nodes = tmp_ele_pt->nnode();
6718 
6719  std::pair<Node*, Node*> tmp_pair = std::make_pair(
6720  tmp_ele_pt->node_pt(0), tmp_ele_pt->node_pt(n_nodes - 1));
6721 
6722  std::pair<Node*, Node*> tmp_pair_inverse = std::make_pair(
6723  tmp_ele_pt->node_pt(n_nodes - 1), tmp_ele_pt->node_pt(0));
6724 
6725  // Search for repeated nodes
6726  const unsigned n_done_nodes = done_nodes_pt.size();
6727  for (unsigned l = 0; l < n_done_nodes; l++)
6728  {
6729  if (tmp_pair == done_nodes_pt[l] ||
6730  tmp_pair_inverse == done_nodes_pt[l])
6731  {
6732  // Increase the number of repeated elements
6733  n_repeated_ele++;
6734  // Mark the element as repeated
6735  repeated = true;
6736  break;
6737  }
6738  }
6739 
6740  // Create new face element
6741  if (!repeated)
6742  {
6743  // Add the pair of nodes (edge) to the node dones
6744  done_nodes_pt.push_back(tmp_pair);
6745  // Add the element to the face elements
6746  face_el_pt.push_back(tmp_ele_pt);
6747  }
6748  else
6749  {
6750  // Free the repeated bulk element!!
6751  delete tmp_ele_pt;
6752  tmp_ele_pt = 0;
6753  }
6754 
6755  // Re-start
6756  repeated = false;
6757 
6758  } // for (e < nel)
6759  } // if (nel > 0)
6760 
6761  } // else (n_regions > 1)
6762 
6763  // Do not consider the repeated elements
6764  nele -= n_repeated_ele;
6765 
6766 #ifdef PARANOID
6767  if (nele != face_el_pt.size())
6768  {
6769  std::ostringstream error_message;
6770  error_message
6771  << "The independet counting of face elements (" << nele << ") for "
6772  << "boundary (" << b << ") is different\n"
6773  << "from the real number of face elements in the container ("
6774  << face_el_pt.size() << ")\n";
6775  //<< "Possible memory leak\n"
6776  throw OomphLibError(error_message.str(),
6777  "TriangleMesh::re_scale_re_assigned_initial_zeta_"
6778  "values_for_internal_boundary()",
6779  OOMPH_EXCEPTION_LOCATION);
6780  }
6781 #endif
6782 
6783  // ----------------------------------------------------------------
6784  // Second: Sort the face elements (to create segments), only
6785  // consider nonhalo elements
6786  // ----------------------------------------------------------------
6787 
6788  // Get the total number of nonhalo face elements
6789  const unsigned nnon_halo_face_elements = face_el_pt.size();
6790 
6791  // The vector of list to store the "segments" that compound the
6792  // boundary (segments may appear only in a distributed mesh)
6793  Vector<std::list<FiniteElement*>> segment_sorted_ele_pt;
6794 
6795  // Number of already sorted face elements
6796  unsigned nsorted_face_elements = 0;
6797 
6798  // Keep track of who's done
6799  std::map<FiniteElement*, bool> done_el;
6800 
6801  // Keep track of which element is inverted
6802  std::map<FiniteElement*, bool> is_inverted;
6803 
6804  // Iterate until all possible segments have been created
6805  while (nsorted_face_elements < nnon_halo_face_elements)
6806  {
6807  // The ordered list of face elements (in a distributed mesh a
6808  // collection of contiguous face elements define a segment)
6809  std::list<FiniteElement*> sorted_el_pt;
6810 
6811 #ifdef PARANOID
6812  // Select an initial element for the segment
6813  bool found_initial_face_element = false;
6814 #endif
6815 
6816  FiniteElement* ele_face_pt = 0;
6817 
6818  unsigned iface = 0;
6819  for (iface = 0; iface < nele; iface++)
6820  {
6821  ele_face_pt = face_el_pt[iface];
6822  // If not done then take it as initial face element
6823  if (!done_el[ele_face_pt])
6824  {
6825 #ifdef PARANOID
6826  found_initial_face_element = true;
6827 #endif
6828  nsorted_face_elements++;
6829  iface++; // The next element number
6830  sorted_el_pt.push_back(ele_face_pt);
6831  // Mark as done
6832  done_el[ele_face_pt] = true;
6833  break;
6834  }
6835  } // for (iface < nele)
6836 
6837 #ifdef PARANOID
6838  if (!found_initial_face_element)
6839  {
6840  std::ostringstream error_message;
6841  error_message
6842  << "Could not find an initial face element for the current segment\n";
6843  // << "----- Possible memory leak -----\n";
6844  throw OomphLibError(error_message.str(),
6845  "TriangleMesh::re_scale_re_assigned_initial_zeta_"
6846  "values_for_internal_boundary()",
6847  OOMPH_EXCEPTION_LOCATION);
6848  }
6849 #endif
6850 
6851  // Number of nodes
6852  const unsigned nnod = ele_face_pt->nnode();
6853 
6854  // Left and rightmost nodes (the left and right nodes of the
6855  // current face element)
6856  Node* left_node_pt = ele_face_pt->node_pt(0);
6857  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
6858 
6859  // Continue iterating if a new face element has been added to the
6860  // list
6861  bool face_element_added = false;
6862 
6863  // While a new face element has been added to the set of sorted
6864  // face elements then re-iterate
6865  do
6866  {
6867  // Start from the next face element since we have already added
6868  // the previous one as the initial face element (any previous
6869  // face element had to be added on previous iterations)
6870  for (unsigned iiface = iface; iiface < nele; iiface++)
6871  {
6872  // Re-start flag
6873  face_element_added = false;
6874 
6875  // Get the candidate element
6876  ele_face_pt = face_el_pt[iiface];
6877 
6878  // Check that the candidate element has not been done
6879  if (!(done_el[ele_face_pt]))
6880  {
6881  // Get the left and right nodes of the current element
6882  Node* local_left_node_pt = ele_face_pt->node_pt(0);
6883  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
6884 
6885  // New element fits at the left of segment and is not inverted
6886  if (left_node_pt == local_right_node_pt)
6887  {
6888  left_node_pt = local_left_node_pt;
6889  sorted_el_pt.push_front(ele_face_pt);
6890  is_inverted[ele_face_pt] = false;
6891  face_element_added = true;
6892  }
6893  // New element fits at the left of segment and is inverted
6894  else if (left_node_pt == local_left_node_pt)
6895  {
6896  left_node_pt = local_right_node_pt;
6897  sorted_el_pt.push_front(ele_face_pt);
6898  is_inverted[ele_face_pt] = true;
6899  face_element_added = true;
6900  }
6901  // New element fits on the right of segment and is not inverted
6902  else if (right_node_pt == local_left_node_pt)
6903  {
6904  right_node_pt = local_right_node_pt;
6905  sorted_el_pt.push_back(ele_face_pt);
6906  is_inverted[ele_face_pt] = false;
6907  face_element_added = true;
6908  }
6909  // New element fits on the right of segment and is inverted
6910  else if (right_node_pt == local_right_node_pt)
6911  {
6912  right_node_pt = local_left_node_pt;
6913  sorted_el_pt.push_back(ele_face_pt);
6914  is_inverted[ele_face_pt] = true;
6915  face_element_added = true;
6916  }
6917 
6918  if (face_element_added)
6919  {
6920  done_el[ele_face_pt] = true;
6921  nsorted_face_elements++;
6922  break;
6923  }
6924 
6925  } // if (!(done_el[ele_face_pt]))
6926  } // for (iiface<nnon_halo_face_element)
6927  } while (face_element_added &&
6928  (nsorted_face_elements < nnon_halo_face_elements));
6929 
6930  // Store the created segment in the vector of segments
6931  segment_sorted_ele_pt.push_back(sorted_el_pt);
6932 
6933  } // while(nsorted_face_elements < nnon_halo_face_elements);
6934 
6935  // --------------------------------------------------------------
6936  // Third: We have the face elements sorted, now assign boundary
6937  // coordinates to the nodes in the segments and compute the
6938  // arclength of the segment
6939  // --------------------------------------------------------------
6940 
6941  // Vector of sets that stores the nodes of each segment based on a
6942  // lexicographically order starting from the bottom left node of
6943  // each segment
6944  Vector<std::set<Node*>> segment_all_nodes_pt;
6945 
6946  // The number of segments in this processor
6947  const unsigned nsegments = segment_sorted_ele_pt.size();
6948 
6949 #ifdef PARANOID
6950  if (nnon_halo_face_elements > 0 && nsegments == 0)
6951  {
6952  std::ostringstream error_message;
6953  error_message
6954  << "The number of segments is zero, but the number of nonhalo\n"
6955  << "elements is: (" << nnon_halo_face_elements << ")\n";
6956  throw OomphLibError(error_message.str(),
6957  "TriangleMesh::re_scale_re_assigned_initial_zeta_"
6958  "values_for_internal_boundary()",
6959  OOMPH_EXCEPTION_LOCATION);
6960  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
6961 #endif
6962 
6963  // The arclength of each segment in the current processor
6964  Vector<double> segment_arclength(nsegments);
6965 
6966  // The initial zeta for the segment
6967  Vector<double> initial_zeta_segment(nsegments);
6968 
6969  // The final zeta for the segment
6970  Vector<double> final_zeta_segment(nsegments);
6971 
6972  // Go through all the segments and compute the LOCAL boundary
6973  // coordinates
6974  for (unsigned is = 0; is < nsegments; is++)
6975  {
6976 #ifdef PARANOID
6977  if (segment_sorted_ele_pt[is].size() == 0)
6978  {
6979  std::ostringstream error_message;
6980  error_message << "The (" << is << ")-th segment has no elements\n";
6981  throw OomphLibError(error_message.str(),
6982  "TriangleMesh::re_scale_re_assigned_initial_zeta_"
6983  "values_for_internal_boundary()",
6984  OOMPH_EXCEPTION_LOCATION);
6985  } // if (segment_sorted_ele_pt[is].size() == 0)
6986 #endif
6987 
6988  // Get access to the first element on the segment
6989  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
6990 
6991  // Number of nodes
6992  const unsigned nnod = first_ele_pt->nnode();
6993 
6994  // Get the first node of the current segment
6995  Node* first_node_pt = first_ele_pt->node_pt(0);
6996  if (is_inverted[first_ele_pt])
6997  {
6998  first_node_pt = first_ele_pt->node_pt(nnod - 1);
6999  }
7000 
7001  // Get access to the last element on the segment
7002  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
7003 
7004  // Get the last node of the current segment
7005  Node* last_node_pt = last_ele_pt->node_pt(nnod - 1);
7006  if (is_inverted[last_ele_pt])
7007  {
7008  last_node_pt = last_ele_pt->node_pt(0);
7009  }
7010 
7011  // Coordinates of left node
7012  double x_left = first_node_pt->x(0);
7013  double y_left = first_node_pt->x(1);
7014 
7015  // Initialise boundary coordinate (local boundary coordinate for
7016  // boundaries with more than one segment)
7017  Vector<double> zeta(1, 0.0);
7018 
7019  // If we have associated a GeomObject then it is not necessary to
7020  // compute the arclength, only read the values from the nodes at
7021  // the edges
7022  if (this->boundary_geom_object_pt(b) != 0)
7023  {
7024  first_node_pt->get_coordinates_on_boundary(b, zeta);
7025  initial_zeta_segment[is] = zeta[0];
7026  last_node_pt->get_coordinates_on_boundary(b, zeta);
7027  final_zeta_segment[is] = zeta[0];
7028  }
7029 
7030  // Lexicographically bottom left node
7031  std::set<Node*> local_nodes_pt;
7032  local_nodes_pt.insert(first_node_pt);
7033 
7034  // Now loop over nodes in order
7035  for (std::list<FiniteElement*>::iterator it =
7036  segment_sorted_ele_pt[is].begin();
7037  it != segment_sorted_ele_pt[is].end();
7038  it++)
7039  {
7040  // Get element
7041  FiniteElement* el_pt = *it;
7042 
7043  // Start node and increment
7044  unsigned k_nod = 1;
7045  int nod_diff = 1;
7046  if (is_inverted[el_pt])
7047  {
7048  k_nod = nnod - 2;
7049  nod_diff = -1;
7050  }
7051 
7052  // Loop over nodes
7053  for (unsigned j = 1; j < nnod; j++)
7054  {
7055  Node* nod_pt = el_pt->node_pt(k_nod);
7056  k_nod += nod_diff;
7057 
7058  // Coordinates of right node
7059  double x_right = nod_pt->x(0);
7060  double y_right = nod_pt->x(1);
7061 
7062  // Increment boundary coordinate
7063  zeta[0] += sqrt((x_right - x_left) * (x_right - x_left) +
7064  (y_right - y_left) * (y_right - y_left));
7065 
7066  // Increment reference coordinate
7067  x_left = x_right;
7068  y_left = y_right;
7069 
7070  // Get lexicographically bottom left node but only
7071  // use vertex nodes as candidates
7072  local_nodes_pt.insert(nod_pt);
7073 
7074  } // for (j < nnod)
7075  } // iterator over the elements in the segment
7076 
7077  // Store the arclength of the segment
7078  segment_arclength[is] = zeta[0];
7079 
7080  // Add the nodes for the corresponding segment in the container
7081  segment_all_nodes_pt.push_back(local_nodes_pt);
7082 
7083  } // for (is < nsegments)
7084 
7085  // ------------------------------------------------------------------
7086  // Fourth: Now we have the segments sorted, with arclength and with
7087  // LOCAL arclength assigned to the nodes. Procced to re-scale the
7088  // coordinates on the nodes based on the arclength
7089  // ------------------------------------------------------------------
7090 
7091  // ------------------------------------------------------------------
7092  // Clear the original storages
7093  Boundary_segment_inverted[b].clear();
7094  Boundary_segment_initial_coordinate[b].clear();
7095  Boundary_segment_final_coordinate[b].clear();
7096 
7097  Boundary_segment_initial_zeta[b].clear();
7098  Boundary_segment_final_zeta[b].clear();
7099 
7100  Boundary_segment_initial_arclength[b].clear();
7101  Boundary_segment_final_arclength[b].clear();
7102 
7103  // Get the zeta values for the first and last node in the boundary
7104  Vector<double> first_node_zeta_coordinate(1, 0.0);
7105  Vector<double> last_node_zeta_coordinate(1, 0.0);
7106  first_node_zeta_coordinate = boundary_initial_zeta_coordinate(b);
7107  last_node_zeta_coordinate = boundary_final_zeta_coordinate(b);
7108 
7109  // Get the boundary arclength
7110  const double boundary_arclength =
7111  std::max(first_node_zeta_coordinate[0], last_node_zeta_coordinate[0]);
7112 
7113  // Go through the segments and get the first and last node for each
7114  // segment
7115  for (unsigned is = 0; is < nsegments; is++)
7116  {
7117  // Get the first face element of the segment
7118  FiniteElement* first_face_ele_pt = segment_sorted_ele_pt[is].front();
7119 
7120  // The number of nodes
7121  const unsigned nnod = first_face_ele_pt->nnode();
7122 
7123  // ... and the first node of the segment
7124  Node* first_node_pt = first_face_ele_pt->node_pt(0);
7125  if (is_inverted[first_face_ele_pt])
7126  {
7127  first_node_pt = first_face_ele_pt->node_pt(nnod - 1);
7128  }
7129 
7130  // Get the bound coordinates of the node
7131  Vector<double> zeta_first(1);
7132  first_node_pt->get_coordinates_on_boundary(b, zeta_first);
7133 
7134  // Get the last face element of the segment
7135  FiniteElement* last_face_ele_pt = segment_sorted_ele_pt[is].back();
7136 
7137  // ... and the last node of the segment
7138  Node* last_node_pt = last_face_ele_pt->node_pt(nnod - 1);
7139  if (is_inverted[last_face_ele_pt])
7140  {
7141  last_node_pt = last_face_ele_pt->node_pt(0);
7142  }
7143 
7144  // Get the bound coordinates of the node
7145  Vector<double> zeta_last(1);
7146  last_node_pt->get_coordinates_on_boundary(b, zeta_last);
7147 
7148  // Now that we have the first and last node of the segment, get
7149  // the coordinates of the nodes
7150  Vector<double> first_node_coord(2);
7151  Vector<double> last_node_coord(2);
7152  for (unsigned i = 0; i < 2; i++)
7153  {
7154  first_node_coord[i] = first_node_pt->x(i);
7155  last_node_coord[i] = last_node_pt->x(i);
7156  }
7157 
7158  // Re-assign the values to identify the segments on the new mesh
7159  Boundary_segment_inverted[b].push_back(0);
7160  Boundary_segment_initial_coordinate[b].push_back(first_node_coord);
7161  Boundary_segment_final_coordinate[b].push_back(last_node_coord);
7162 
7163  // Check if the boudary has an associated GeomObject
7164  if (this->boundary_geom_object_pt(b) != 0)
7165  {
7166  Boundary_segment_initial_zeta[b].push_back(zeta_first[0]);
7167  Boundary_segment_final_zeta[b].push_back(zeta_last[0]);
7168  }
7169  else
7170  {
7171  // Re-assign the values and re-scale them
7172  Boundary_segment_initial_arclength[b].push_back(zeta_first[0] *
7173  boundary_arclength);
7174  Boundary_segment_final_arclength[b].push_back(zeta_last[0] *
7175  boundary_arclength);
7176  }
7177 
7178  } // for (is < nsegments)
7179 
7180  // Clean all the created face elements
7181  for (unsigned i = 0; i < nele; i++)
7182  {
7183  delete face_el_pt[i];
7184  face_el_pt[i] = 0;
7185  }
7186  }
7187 
7188 #endif // OOMPH_HAS_MPI
7189 
7190 
7191 #ifdef OOMPH_HAS_TRIANGLE_LIB
7192 
7193  //========================================================================
7194  /// Create TriangulateIO object via the .poly file
7195  //========================================================================
7196  template<class ELEMENT>
7198  const std::string& poly_file_name,
7199  TriangulateIO& triangulate_io,
7200  bool& use_attributes)
7201  {
7202  // Process poly file
7203  // -----------------
7204  std::ifstream poly_file(poly_file_name.c_str(), std::ios_base::in);
7205  if (!poly_file)
7206  {
7207  throw OomphLibError("Error opening .poly file\n",
7208  OOMPH_CURRENT_FUNCTION,
7209  OOMPH_EXCEPTION_LOCATION);
7210  }
7211 
7212  // Initialize triangulateio structure
7213  TriangleHelper::initialise_triangulateio(triangulate_io);
7214 
7215  // Ignore the first line with structure description
7216  poly_file.ignore(80, '\n');
7217 
7218  // Read and store number of nodes
7219  unsigned invertices;
7220  poly_file >> invertices;
7221  triangulate_io.numberofpoints = invertices;
7222 
7223  // Initialisation of the point list
7224  triangulate_io.pointlist =
7225  (double*)malloc(triangulate_io.numberofpoints * 2 * sizeof(double));
7226 
7227  // Read and store spatial dimension of nodes
7228  unsigned mesh_dim;
7229  poly_file >> mesh_dim;
7230 
7231  if (mesh_dim == 0)
7232  {
7233  mesh_dim = 2;
7234  }
7235 
7236 #ifdef PARANOID
7237  if (mesh_dim != 2)
7238  {
7239  throw OomphLibError("The dimension must be 2\n",
7240  OOMPH_CURRENT_FUNCTION,
7241  OOMPH_EXCEPTION_LOCATION);
7242  }
7243 #endif
7244 
7245  // Read and check the flag for attributes
7246  unsigned nextras;
7247  poly_file >> nextras;
7248 
7249  triangulate_io.numberofpointattributes = 0;
7250  triangulate_io.pointattributelist = (double*)NULL;
7251 
7252  // Read and check the flag for boundary markers
7253  unsigned nodemarkers;
7254  poly_file >> nodemarkers;
7255  triangulate_io.pointmarkerlist = (int*)NULL;
7256 
7257 #ifdef PARANOID
7258  // Reading the .poly with the oomph.lib we need
7259  // to set the point attribute and markers to 0
7260  if (nextras != 0 || nodemarkers != 0)
7261  {
7262  oomph_info << "===================================================="
7263  << std::endl
7264  << std::endl;
7265  oomph_info << "Reading the .poly file via oomph_lib \n"
7266  << "point's attribute and point's markers \n"
7267  << "are automatically set to 0" << std::endl;
7268  oomph_info << "===================================================="
7269  << std::endl;
7270  }
7271 #endif
7272 
7273  // Dummy for node number (and attribute or markers if included)
7274  unsigned dummy_value;
7275  unsigned count_point = 0;
7276  std::string test_string;
7277 
7278  // Skip line with commentary
7279  getline(poly_file, test_string, '#');
7280  poly_file.ignore(80, '\n');
7281 
7282  // Read and store all the nodes coordinates
7283  // (hole's vertices as well)
7284  for (unsigned count = 0; count < invertices; count++)
7285  {
7286  poly_file >> dummy_value;
7287  poly_file >> triangulate_io.pointlist[count_point];
7288  poly_file >> triangulate_io.pointlist[count_point + 1];
7289  if (nextras != 0 || nodemarkers != 0)
7290  {
7291  for (unsigned j = 0; j < nextras; j++)
7292  {
7293  poly_file >> dummy_value;
7294  }
7295  }
7296  else if (nextras != 0 && nodemarkers != 0)
7297  {
7298  for (unsigned j = 0; j < nextras; j++)
7299  {
7300  poly_file >> dummy_value;
7301  poly_file >> dummy_value;
7302  }
7303  }
7304  // Read the next line
7305  poly_file.ignore(80, '\n');
7306 
7307  // Skip line with commentary for internal box whether found
7308  if (poly_file.get() == '#')
7309  {
7310  poly_file.ignore(80, '\n');
7311  }
7312  // If read the char should be put back in the string
7313 
7314  else
7315  {
7316  poly_file.unget();
7317  }
7318  count_point += 2;
7319  }
7320 
7321  // The line with the segment's commentary has been skipped
7322  // by the command of the last loop
7323 
7324  // Read and store the number of segments
7325  unsigned dummy_seg;
7326  unsigned inelements;
7327  poly_file >> inelements;
7328 
7329  unsigned segment_markers;
7330  poly_file >> segment_markers;
7331 
7332  // Marker list should be provided by the user to assign
7333  // each segment to a boundary
7334 #ifdef PARANOID
7335  if (segment_markers != 1)
7336  {
7337  std::ostringstream error_stream;
7338  error_stream << "The segment marker should be provided \n"
7339  << "In order to assign each segment to a boundary \n "
7340  << std::endl;
7341 
7342  throw OomphLibError(
7343  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
7344  }
7345 #endif
7346 
7347  triangulate_io.numberofsegments = inelements;
7348  triangulate_io.segmentlist =
7349  (int*)malloc(triangulate_io.numberofsegments * 2 * sizeof(int));
7350  triangulate_io.segmentmarkerlist =
7351  (int*)malloc(triangulate_io.numberofsegments * sizeof(int));
7352 
7353  // Read all the segments edges and markers
7354  for (unsigned i = 0; i < 2 * inelements; i += 2)
7355  {
7356  poly_file >> dummy_seg;
7357  poly_file >> triangulate_io.segmentlist[i];
7358  poly_file >> triangulate_io.segmentlist[i + 1];
7359  if (segment_markers != 0)
7360  {
7361  poly_file >> triangulate_io.segmentmarkerlist[i / 2];
7362  }
7363 
7364  // Skip line with commentary
7365  poly_file.ignore(80, '\n');
7366  }
7367 
7368  // Read and store the number of holes if given
7369  // Skip line with commentary
7370  if (getline(poly_file, test_string, '#'))
7371  {
7372  poly_file.ignore(80, '\n');
7373 
7374  unsigned dummy_hole;
7375  unsigned nhole;
7376  poly_file >> nhole;
7377 
7378  triangulate_io.numberofholes = nhole;
7379  triangulate_io.holelist =
7380  (double*)malloc(triangulate_io.numberofholes * 2 * sizeof(double));
7381 
7382  // Loop over the holes to get centre coords and store value onto the
7383  // TriangulateIO object
7384  for (unsigned i = 0; i < 2 * nhole; i += 2)
7385  {
7386  poly_file >> dummy_hole;
7387  poly_file >> triangulate_io.holelist[i];
7388  poly_file >> triangulate_io.holelist[i + 1];
7389  }
7390  }
7391 
7392  // Read and store the number of regions if given
7393  // Skip line with commentary
7394  if (getline(poly_file, test_string, '#'))
7395  {
7396  poly_file.ignore(80, '\n');
7397 
7398  unsigned dummy_region;
7399  unsigned nregion;
7400  poly_file >> nregion;
7401  std::cerr << "Regions: " << nregion << std::endl;
7402  getchar();
7403 
7404  triangulate_io.numberofregions = nregion;
7405  triangulate_io.regionlist =
7406  (double*)malloc(triangulate_io.numberofregions * 4 * sizeof(double));
7407 
7408  // Check for using regions
7409  if (nregion > 0)
7410  {
7411  use_attributes = true;
7412  }
7413 
7414  // Loop over the regions to get coords and store value onto the
7415  // TriangulateIO object
7416  for (unsigned i = 0; i < nregion; i++)
7417  {
7418  poly_file >> dummy_region;
7419  poly_file >> triangulate_io.regionlist[4 * i];
7420  poly_file >> triangulate_io.regionlist[4 * i + 1];
7421  poly_file >> triangulate_io.regionlist[4 * i + 2];
7422  triangulate_io.regionlist[4 * i + 3] = 0.0;
7423  }
7424  }
7425  }
7426 
7427 #endif
7428 
7429 #ifdef OOMPH_HAS_TRIANGLE_LIB
7430 #ifdef OOMPH_HAS_MPI
7431 
7432  //======================================================================
7433  /// Used to dump info. related with distributed triangle meshes
7434  //======================================================================
7435  template<class ELEMENT>
7437  std::ostream& dump_file)
7438  {
7439  // First check that the mesh is distributed
7440  if (this->is_mesh_distributed())
7441  {
7442  // Save the original number of boundaries
7443  const unsigned nboundary = this->nboundary();
7444  dump_file << nboundary << " # number of original boundaries" << std::endl;
7445 
7446  // Save the number of shared boundaries
7447  const unsigned nshared_boundaries = this->nshared_boundaries();
7448  dump_file << nshared_boundaries << " # number of shared boundaries"
7449  << std::endl;
7450 
7451  // Save the initial and final shared boundaries ids
7452  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
7453  dump_file << init_shd_bnd_id << " # initial shared boundaries id"
7454  << std::endl;
7455 
7456  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
7457  dump_file << final_shd_bnd_id << " # final shared boundaries id"
7458  << std::endl;
7459 
7460  // Save the number of processors
7461  const unsigned nprocs = this->shared_boundaries_ids().size();
7462  dump_file << nprocs << " # number of processors" << std::endl;
7463 
7464  // Now save the processors ids and the shared boundary created
7465  // by them
7466  for (unsigned ip = 0; ip < nprocs; ip++)
7467  {
7468  for (unsigned jp = 0; jp < nprocs; jp++)
7469  {
7470  if (ip != jp)
7471  {
7472  // Get the number of shared boundaries with it these two
7473  // processors
7474  const unsigned nshared_boundaries_iproc_jproc =
7475  this->shared_boundaries_ids(ip, jp).size();
7476 
7477  // Save the number of shared boundaries with in these two
7478  // processors
7479  dump_file << nshared_boundaries_iproc_jproc
7480  << " # number of shared boundaries with in two "
7481  << "processors" << std::endl;
7482  for (unsigned is = 0; is < nshared_boundaries_iproc_jproc; is++)
7483  {
7484  const unsigned shared_boundary_id =
7485  this->shared_boundaries_ids(ip, jp, is);
7486  dump_file << ip << " " << jp << " " << shared_boundary_id
7487  << " # ip jp shared_boundary of processors ip and jp"
7488  << std::endl;
7489 
7490  } // for (is < nshared_boundaries_iproc_jproc)
7491  }
7492  } // for (jp < nprocs)
7493  } // for (ip < nprocs)
7494 
7495  // Now save the info. that states which shared boundary overlaps
7496  // an internal boundary
7497 
7498  // First check if there are shared boundaries overlapping internal
7499  // boundaries
7500  const unsigned nshared_boundaries_overlap_internal_boundaries =
7501  this->nshared_boundary_overlaps_internal_boundary();
7502  dump_file << nshared_boundaries_overlap_internal_boundaries
7503  << " # number of shared boundaries that overlap internal "
7504  << "boundaries" << std::endl;
7505 
7506  if (nshared_boundaries_overlap_internal_boundaries > 0)
7507  {
7508  for (unsigned isb = init_shd_bnd_id; isb < final_shd_bnd_id; isb++)
7509  {
7510  // Check if the current shared boundary overlaps an internal
7511  // boundary
7512  if (this->shared_boundary_overlaps_internal_boundary(isb))
7513  {
7514  // Which internal boundary is overlapped by the shared
7515  // boundary
7516  const unsigned overlapped_internal_boundary =
7517  shared_boundary_overlapping_internal_boundary(isb);
7518  // Save the shared boundary that overlaps the internal boundary
7519  dump_file << isb << " " << overlapped_internal_boundary
7520  << " # the shared boundary overlaps the internal "
7521  << "boundary " << std::endl;
7522 
7523  } // if (this->shared_boundary_overlaps_internal_boundary(isb))
7524  } // for (isb < final_shd_bnd_id)
7525  } // if (nshared_boundaries_overlap_internal_boundaries > 0)
7526 
7527  // Now save the info. related with the initial and final
7528  // boundary coordinates for each original boundary
7529 
7530  // Go through all the (original) boundaries to update the initial
7531  // and final boundary coordinates
7532  for (unsigned b = 0; b < nboundary; b++)
7533  {
7534  // Check if the boundary zeta coordinates for this boundary have
7535  // been already assigned, if that is the case then state the
7536  // flag to know that info. should be read
7537  if (Assigned_segments_initial_zeta_values[b])
7538  {
7539  // The boundary coordinates have been computed then state
7540  // the flag and save the info.
7541  dump_file << "1 # assigned boundary coordinates initial zeta values"
7542  << std::endl;
7543 
7544  // Save the initial and final boundary coordinates, same as
7545  // the initial and final zeta values for each boundary
7546 
7547  // First the vertices coordinates
7548  Vector<double> initial_coordinates =
7549  this->boundary_initial_coordinate(b);
7550 
7551  Vector<double> final_coordinates = this->boundary_final_coordinate(b);
7552 
7553  dump_file << std::setprecision(14) << initial_coordinates[0] << " "
7554  << initial_coordinates[1]
7555  << " # initial coordinates for the current boundary"
7556  << std::endl;
7557 
7558  dump_file << std::setprecision(14) << final_coordinates[0] << " "
7559  << final_coordinates[1]
7560  << " # final coordinates for the current boundary"
7561  << std::endl;
7562 
7563  // ... then the zeta values
7564 
7565 #ifdef PARANOID
7566  // Get the number of zeta coordinates (should be one)
7567  const unsigned zeta_size =
7568  this->boundary_initial_zeta_coordinate(b).size();
7569 
7570  if (zeta_size != 1)
7571  {
7572  std::ostringstream error_message;
7573  error_message
7574  << "The dimension for the zeta values container is different\n"
7575  << "from 1, the current implementation only supports\n"
7576  << "one-dimensioned zeta containers\n\n";
7577  throw OomphLibError(
7578  error_message.str(),
7579  "TriangleMesh::dump_distributed_info_for_restart()",
7580  OOMPH_EXCEPTION_LOCATION);
7581  }
7582 #endif
7583 
7584  Vector<double> zeta_initial =
7585  this->boundary_initial_zeta_coordinate(b);
7586  Vector<double> zeta_final = this->boundary_final_zeta_coordinate(b);
7587 
7588  dump_file << std::setprecision(14) << zeta_initial[0]
7589  << " # initial zeta value for the current boundary"
7590  << std::endl;
7591 
7592  dump_file << std::setprecision(14) << zeta_final[0]
7593  << " # final zeta value for the current boundary"
7594  << std::endl;
7595 
7596  // Get the number of segments of the current boundary
7597  const unsigned nsegments = this->nboundary_segment(b);
7598  // Save the number of segments of the current boundary
7599  dump_file << b << " " << nsegments
7600  << " # of segments for the current boundary" << std::endl;
7601 
7602  // ... and then save that info for each segments
7603  for (unsigned is = 0; is < nsegments; is++)
7604  {
7605  // First the vertices coordinates
7606  Vector<double> initial_segment_coordinates =
7607  this->boundary_segment_initial_coordinate(b)[is];
7608  Vector<double> final_segment_coordinates =
7609  this->boundary_segment_final_coordinate(b)[is];
7610 
7611  dump_file
7612  << std::setprecision(14) << initial_segment_coordinates[0] << " "
7613  << initial_segment_coordinates[1]
7614  << " # initial segment coordinates for the current boundary"
7615  << std::endl;
7616 
7617  dump_file << std::setprecision(14) << final_segment_coordinates[0]
7618  << " " << final_segment_coordinates[1]
7619  << " # final segment coordinates for the current boundary"
7620  << std::endl;
7621 
7622  // ... then the zeta values
7623 
7624  if (this->boundary_geom_object_pt(b) != 0)
7625  {
7626  const double zeta_segment_initial =
7627  this->boundary_segment_initial_zeta(b)[is];
7628  const double zeta_segment_final =
7629  this->boundary_segment_final_zeta(b)[is];
7630 
7631  dump_file
7632  << std::setprecision(14) << zeta_segment_initial
7633  << " # initial segment zeta value for the current boundary"
7634  << std::endl;
7635 
7636  dump_file
7637  << std::setprecision(14) << zeta_segment_final
7638  << " # final segment zeta value for the current boundary"
7639  << std::endl;
7640  }
7641  else
7642  {
7643  const double arclength_segment_initial =
7644  this->boundary_segment_initial_arclength(b)[is];
7645  const double arclength_segment_final =
7646  this->boundary_segment_final_arclength(b)[is];
7647 
7648  dump_file
7649  << std::setprecision(14) << arclength_segment_initial
7650  << " # initial segment arclength for the current boundary"
7651  << std::endl;
7652 
7653  dump_file << std::setprecision(14) << arclength_segment_final
7654  << " # final segment arclength for the current boundary"
7655  << std::endl;
7656 
7657  } // else if (this->boundary_geom_object_pt(b)!=0)
7658 
7659  } // for (is < nsegments)
7660 
7661  } // if (Assigned_segments_initial_zeta_values[b])
7662  else
7663  {
7664  // The boundary coordinates have NOT been computed then state
7665  // the flag and save the info.
7666  dump_file << "0 # assigned boundary coordinates initial zeta values"
7667  << std::endl;
7668  }
7669 
7670  } // for (b < nboundary)
7671 
7672  } // if (this->is_mesh_distributed())
7673  }
7674 
7675  //======================================================================
7676  /// Used to read info. related with distributed triangle meshes
7677  //======================================================================
7678  template<class ELEMENT>
7680  std::istream& restart_file)
7681  {
7682  // First check that the mesh is distributed
7683  if (this->is_mesh_distributed())
7684  {
7685  // Read the number of original boundaries
7686  const unsigned n_boundary = read_unsigned_line_helper(restart_file);
7687 
7688 #ifdef PARANOID
7689  if (n_boundary != this->nboundary())
7690  {
7691  std::ostringstream error_message;
7692  error_message
7693  << "The number of boundaries (" << n_boundary << ") on the "
7694  << "file used for restarting is different\nfrom the number of "
7695  << "boundaries (" << this->nboundary() << ") on the current "
7696  << "mesh!!!\n\n\n";
7697  throw OomphLibError(error_message.str(),
7698  "TriangleMesh::read_distributed_info_for_restart()",
7699  OOMPH_EXCEPTION_LOCATION);
7700  }
7701 #endif
7702 
7703  // Read the number of shared boundaries
7704  unsigned n_shared_boundaries = read_unsigned_line_helper(restart_file);
7705  // We need to read the data because it comes in the file (add and
7706  // substract to avoid compilation warning)
7707  n_shared_boundaries++;
7708  n_shared_boundaries--;
7709 
7710  // Read the initial and final shared boundaries ids
7711  unsigned init_shd_bnd_id = read_unsigned_line_helper(restart_file);
7712  // We need to read the data because it comes in the file (add and
7713  // substract to avoid compilation warning)
7714  init_shd_bnd_id++;
7715  init_shd_bnd_id--;
7716  // Add and substract to avoid compilation warning
7717  unsigned final_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  final_shd_bnd_id++;
7721  final_shd_bnd_id--;
7722 
7723  // Read the number of processors involved in the generation of
7724  // mesh before restart
7725  const unsigned n_procs = read_unsigned_line_helper(restart_file);
7726 
7727 #ifdef PARANOID
7728  if (static_cast<int>(n_procs) != this->communicator_pt()->nproc())
7729  {
7730  std::ostringstream error_message;
7731  error_message
7732  << "The number of previously used processors (" << n_procs
7733  << ") (read from the restart file) is different\nfrom the "
7734  << "number of current used processors ("
7735  << this->communicator_pt()->nproc() << ")\n\n";
7736  throw OomphLibError(error_message.str(),
7737  "TriangleMesh::read_distributed_info_for_restart()",
7738  OOMPH_EXCEPTION_LOCATION);
7739  }
7740 #endif
7741 
7742  // Clear all previuos info. related with shared boundaries
7743  this->shared_boundaries_ids().clear();
7744  this->shared_boundary_from_processors().clear();
7745  this->shared_boundary_overlaps_internal_boundary().clear();
7746 
7747  // Create the storage for the shared boundaries ids related with
7748  // the processors
7749  this->shared_boundaries_ids().resize(n_procs);
7750 
7751  // Now read the processors ids and the shared boundary created
7752  // by them
7753  for (unsigned ip = 0; ip < n_procs; ip++)
7754  {
7755  // Create the storage for the shared boundaries ids related with
7756  // the processors
7757  this->shared_boundaries_ids(ip).resize(n_procs);
7758  for (unsigned jp = 0; jp < n_procs; jp++)
7759  {
7760  if (ip != jp)
7761  {
7762  // Read the number of shared boundaries with in these two
7763  // processors
7764  const unsigned nshared_boundaries_iproc_jproc =
7765  read_unsigned_line_helper(restart_file);
7766  for (unsigned is = 0; is < nshared_boundaries_iproc_jproc; is++)
7767  {
7768  // Get the processors
7769  unsigned tmp_ip;
7770  restart_file >> tmp_ip;
7771  unsigned tmp_jp;
7772  restart_file >> tmp_jp;
7773 
7774  // Get the shared boundary id created by these two
7775  // processors
7776  const unsigned shared_boundary_id =
7777  read_unsigned_line_helper(restart_file);
7778 
7779  // Update the info. of the processors that give rise to
7780  // the shared boundaries
7781  this->shared_boundaries_ids(ip, jp).push_back(shared_boundary_id);
7782 
7783  // Update the structure that states the processors that
7784  // gave rise to the shared boundary
7785  Vector<unsigned> processors(2);
7786  processors[0] = ip;
7787  processors[1] = jp;
7788  this->shared_boundary_from_processors()[shared_boundary_id] =
7789  processors;
7790 
7791  } // for (is < nshared_boundaries_iproc_jproc)
7792  }
7793  } // for (jp < n_procs)
7794  } // for (ip < n_procs)
7795 
7796  // Now read the info. that states which shared boundary overlaps
7797  // an internal boundary
7798 
7799  // First check if there are shared boundaries overlapping internal
7800  // boundaries
7801  const unsigned nshared_boundaries_overlap_internal_boundaries =
7802  read_unsigned_line_helper(restart_file);
7803 
7804  for (unsigned isb = 0;
7805  isb < nshared_boundaries_overlap_internal_boundaries;
7806  isb++)
7807  {
7808  // Read the shared boundary that overlaps an internal boundary
7809  unsigned shared_boundary_overlapping;
7810  restart_file >> shared_boundary_overlapping;
7811  // ... and read the internal boundary that overlaps
7812  const unsigned overlapped_internal_boundary =
7813  read_unsigned_line_helper(restart_file);
7814 
7815  // Re-establish the info. of the shared boundaries overlapped
7816  // by internal boundaries
7817  this->shared_boundary_overlaps_internal_boundary()
7818  [shared_boundary_overlapping] = overlapped_internal_boundary;
7819  } // for (isb < nshared_boundaries_overlap_internal_boundaries)
7820 
7821  // Now read the info. related with the initial and final
7822  // boundary coordinates for each original boundary
7823 
7824  // Go through all the (original) boundaries to update the initial
7825  // and final boundary coordinates
7826  for (unsigned b = 0; b < n_boundary; b++)
7827  {
7828  // For each boundary check if the boundary coordinates initial
7829  // and final zeta vales were assigned in the restart file
7830  const unsigned boundary_coordinates_initial_zeta_values_assigned =
7831  read_unsigned_line_helper(restart_file);
7832 
7833  if (boundary_coordinates_initial_zeta_values_assigned)
7834  {
7835  // Clear any previous stored info. There should not be
7836  // info. already stored but better clear the info. for the
7837  // boundary
7838  Boundary_initial_coordinate[b].clear();
7839  Boundary_final_coordinate[b].clear();
7840 
7841  Boundary_initial_zeta_coordinate[b].clear();
7842  Boundary_final_zeta_coordinate[b].clear();
7843 
7844  // The info. for the segments
7845  Boundary_segment_inverted[b].clear();
7846  Boundary_segment_initial_coordinate[b].clear();
7847  Boundary_segment_final_coordinate[b].clear();
7848 
7849  Boundary_segment_initial_zeta[b].clear();
7850  Boundary_segment_final_zeta[b].clear();
7851 
7852  Boundary_segment_initial_arclength[b].clear();
7853  Boundary_segment_final_arclength[b].clear();
7854 
7855  // Read the initial and final boundary coordinates, same as
7856  // the initial and final zeta values for each boundary
7857 
7858  // First the vertices coordinates
7859  Vector<double> initial_coordinates(2);
7860 
7861  // Read the initial coordinates
7862  restart_file >> initial_coordinates[0] >> initial_coordinates[1];
7863 
7864  // Ignore rest of line
7865  restart_file.ignore(80, '\n');
7866 
7867  Vector<double> final_coordinates(2);
7868 
7869  // Read the final coordinates
7870  restart_file >> final_coordinates[0] >> final_coordinates[1];
7871 
7872  // Ignore rest of line
7873  restart_file.ignore(80, '\n');
7874 
7875  // Set the values in the containers
7876 
7877 
7878  this->boundary_initial_coordinate(b) = initial_coordinates;
7879  this->boundary_final_coordinate(b) = final_coordinates;
7880 
7881  // ... now read the zeta values
7882  Vector<double> zeta_initial(1);
7883  restart_file >> zeta_initial[0];
7884 
7885  // Ignore rest of line
7886  restart_file.ignore(80, '\n');
7887 
7888  Vector<double> zeta_final(1);
7889  restart_file >> zeta_final[0];
7890 
7891  // Ignore rest of line
7892  restart_file.ignore(80, '\n');
7893 
7894  // Set the values in the containers
7895  this->boundary_initial_zeta_coordinate(b) = zeta_initial;
7896  this->boundary_final_zeta_coordinate(b) = zeta_final;
7897 
7898  // Get the curent boundary id from the restart file
7899  unsigned current_boundary;
7900  restart_file >> current_boundary;
7901 
7902 #ifdef PARANOID
7903  if (current_boundary != b)
7904  {
7905  std::ostringstream error_message;
7906  error_message
7907  << "The current boundary id from the restart file ("
7908  << current_boundary << ") is different from\nthe boundary id "
7909  << b << "currently used to re-establish the initial and\nfinal "
7910  << "segment's zeta values\n\n";
7911  throw OomphLibError(
7912  error_message.str(),
7913  "TriangleMesh::read_distributed_info_for_restart()",
7914  OOMPH_EXCEPTION_LOCATION);
7915  }
7916 #endif
7917 
7918  // ... and its number of segments
7919  unsigned nsegments;
7920  restart_file >> nsegments;
7921 
7922  // Ignore rest of line
7923  restart_file.ignore(80, '\n');
7924 
7925  // Now read all the segments info.
7926 
7927  // ... and then save that info for each segments
7928  for (unsigned is = 0; is < nsegments; is++)
7929  {
7930  // First the vertices coordinates
7931  Vector<double> initial_segment_coordinates(2);
7932 
7933  // Read the initial coordinates
7934  restart_file >> initial_segment_coordinates[0] >>
7935  initial_segment_coordinates[1];
7936 
7937  // Ignore rest of line
7938  restart_file.ignore(80, '\n');
7939 
7940  Vector<double> final_segment_coordinates(2);
7941 
7942  // Read the final coordinates
7943  restart_file >> final_segment_coordinates[0] >>
7944  final_segment_coordinates[1];
7945 
7946  // Ignore rest of line
7947  restart_file.ignore(80, '\n');
7948 
7949  // Set the values in the containers
7950  this->boundary_segment_initial_coordinate(b).push_back(
7951  initial_segment_coordinates);
7952  this->boundary_segment_final_coordinate(b).push_back(
7953  final_segment_coordinates);
7954 
7955  // ... then the zeta values for the segment
7956  if (this->boundary_geom_object_pt(b) != 0)
7957  {
7958  Vector<double> zeta_segment_initial(1);
7959  restart_file >> zeta_segment_initial[0];
7960 
7961  // Ignore rest of line
7962  restart_file.ignore(80, '\n');
7963 
7964  Vector<double> zeta_segment_final(1);
7965  restart_file >> zeta_segment_final[0];
7966 
7967  // Ignore rest of line
7968  restart_file.ignore(80, '\n');
7969 
7970  // Set the values in the containers for the segment
7971  this->boundary_segment_initial_zeta(b).push_back(
7972  zeta_segment_initial[0]);
7973  this->boundary_segment_final_zeta(b).push_back(
7974  zeta_segment_final[0]);
7975  }
7976  else
7977  {
7978  Vector<double> arclength_segment_initial(1);
7979  restart_file >> arclength_segment_initial[0];
7980 
7981  // Ignore rest of line
7982  restart_file.ignore(80, '\n');
7983 
7984  Vector<double> arclength_segment_final(1);
7985  restart_file >> arclength_segment_final[0];
7986 
7987  // Ignore rest of line
7988  restart_file.ignore(80, '\n');
7989 
7990  // Set the values in the containers for the segment
7991  this->boundary_segment_initial_arclength(b).push_back(
7992  arclength_segment_initial[0]);
7993  this->boundary_segment_final_arclength(b).push_back(
7994  arclength_segment_final[0]);
7995  } // else if (this->boundary_geom_object_pt(b)!=0)
7996 
7997  } // for (is < nsegments)
7998 
7999  } // if (boundary_coordinates_initial_zeta_values_assigned)
8000 
8001  } // for (b < n_boundary)
8002 
8003  } // if (this->is_mesh_distributed())
8004  }
8005 
8006 #endif // #ifdef OOMPH_HAS_MPI
8007 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB
8008 
8009  //===================================================================
8010  // Output the nodes on the boundaries and their / respective boundary
8011  // coordinates(into separate tecplot / zones)
8012  //===================================================================
8013  template<class ELEMENT>
8015  std::ostream& outfile)
8016  {
8017  // First get all the elements adjacent to the given boundary, then
8018  // the face elements and extract the nodes on the boundaries using
8019  // the face elements. We can not use the data structure
8020  // Boundary_node_pt since the multi_domain functions add nodes there
8021  // without assigning the required boundary coordinate
8022 
8023  // Store the nodes in a set so we do not have repeated nodes
8024  std::set<Node*> boundary_nodes_pt;
8025  const unsigned n_boundary_ele = this->nboundary_element(b);
8026  for (unsigned e = 0; e < n_boundary_ele; e++)
8027  {
8028  // Get the boundary bulk element
8029  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
8030 #ifdef OOMPH_HAS_MPI
8031  // Only work with nonhalo elements if the mesh is distributed
8032  if (!bulk_ele_pt->is_halo())
8033  {
8034 #endif
8035  // Get the face index
8036  int face_index = this->face_index_at_boundary(b, e);
8037  // Create the face element
8038  FiniteElement* face_ele_pt =
8039  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
8040 
8041  // Get the number of nodes on the face element
8042  const unsigned n_nodes = face_ele_pt->nnode();
8043  for (unsigned i = 0; i < n_nodes; i++)
8044  {
8045  // Get the nodes in the face elements
8046  Node* tmp_node_pt = face_ele_pt->node_pt(i);
8047  // Add the nodes to the set of boundary nodes
8048  boundary_nodes_pt.insert(tmp_node_pt);
8049  } // for (i < n_nodes)
8050 
8051  // Free the memory allocated for the face element
8052  delete face_ele_pt;
8053  face_ele_pt = 0;
8054 #ifdef OOMPH_HAS_MPI
8055  } // if (!bulk_ele_pt->is_halo())
8056 #endif
8057 
8058  } // for (e < n_boundary_ele)
8059 
8060  outfile << "ZONE T=\"Boundary nodes" << b << "\"\n";
8061  // Set to store the boundary nodes in order
8062  std::set<Vector<double>> set_node_coord;
8063  // Loop over the nodes on the boundary and store them in the set
8064  for (std::set<Node*>::iterator it = boundary_nodes_pt.begin();
8065  it != boundary_nodes_pt.end();
8066  it++)
8067  {
8068  Node* inode_pt = (*it);
8069 
8070  // Get the node coordinates
8071  const unsigned n_dim = inode_pt->ndim();
8072  Vector<double> node_coord(n_dim + 1);
8073 
8074  // Get the boundary coordinate
8075  Vector<double> zeta(1);
8076  inode_pt->get_coordinates_on_boundary(b, zeta);
8077  node_coord[0] = zeta[0];
8078  for (unsigned j = 0; j < n_dim; j++)
8079  {
8080  node_coord[j + 1] = inode_pt->x(j);
8081  }
8082  set_node_coord.insert(node_coord);
8083  }
8084 
8085  for (std::set<Vector<double>>::iterator it = set_node_coord.begin();
8086  it != set_node_coord.end();
8087  it++)
8088  {
8089  // Get the node coordinates
8090  Vector<double> node_coord = (*it);
8091 
8092  // Output the node coordinates
8093  const unsigned n_dim = node_coord.size() - 1;
8094  for (unsigned j = 0; j < n_dim; j++)
8095  {
8096  outfile << node_coord[j + 1] << " ";
8097  }
8098  // ... add an extra coordinate to avoid error with tecplot
8099  outfile << "0.0" << std::endl;
8100  }
8101 
8102  // ... loop again to plot the bound coordinates
8103  outfile << "ZONE T=\"Boundary coordinates " << b << "\"\n";
8104  for (std::set<Vector<double>>::iterator it = set_node_coord.begin();
8105  it != set_node_coord.end();
8106  it++)
8107  {
8108  // Get the node coordinates
8109  Vector<double> node_coord = (*it);
8110 
8111  // Output the node coordinates
8112  const unsigned n_dim = node_coord.size() - 1;
8113  for (unsigned j = 0; j < n_dim; j++)
8114  {
8115  outfile << node_coord[j + 1] << " ";
8116  }
8117 
8118  // Output the boundary coordinate
8119  outfile << node_coord[0] << std::endl;
8120  }
8121  }
8122 
8123 #ifdef OOMPH_HAS_MPI
8124  //====================================================================
8125  // Creates the distributed domain representation. Joins the
8126  // original boundaires, shared boundaries and creates connections among
8127  // them to create the new polygons that represent the distributed
8128  // domain
8129  //====================================================================
8130  template<class ELEMENT>
8132  Vector<TriangleMeshPolygon*>& polygons_pt,
8133  Vector<TriangleMeshOpenCurve*>& open_curves_pt)
8134  {
8135  // Get the outer polygons, internal polygons, internal open curves
8136  // and join them with the shared polylines to create the distributed
8137  // domain representation (the new outer, internal polygons, and new
8138  // internal open curves)
8139 
8140  // Get the rank of the current processor
8141  const unsigned my_rank = this->communicator_pt()->my_rank();
8142 
8143  // *********************************************************************
8144  // Step (2) Get the outer, internal and shared boundaries to create the
8145  // new polygons
8146  // *********************************************************************
8147 
8148  // *********************************************************************
8149  // Step (2.1) Get the outer boundaries and check if it is necessary to use
8150  // a new representation (for example when the boundary was splitted in
8151  // the distribution process)
8152  // *********************************************************************
8153 
8154  // Storage for new created polylines, non sorted
8155  Vector<TriangleMeshPolyLine*> unsorted_outer_polyline_pt;
8156 
8157  // Storing for the polylines on the boundaries
8158  // The first index is for a set of connected polylines
8159  // The second index is for a polyline on a set of connected polylines
8160  Vector<Vector<TriangleMeshPolyLine*>> sorted_outer_curves_pt;
8161 
8162  // Copy the outer boundaries to the vector of polylines
8163  const unsigned nouter = this->Outer_boundary_pt.size();
8164  for (unsigned i = 0; i < nouter; i++)
8165  {
8166  const unsigned npolylines = this->Outer_boundary_pt[i]->npolyline();
8167  for (unsigned p = 0; p < npolylines; p++)
8168  {
8169  // Pointer to the current polyline
8170  TriangleMeshPolyLine* tmp_polyline_pt =
8171  this->Outer_boundary_pt[i]->polyline_pt(p);
8172  const unsigned nvertex = tmp_polyline_pt->nvertex();
8173  if (nvertex > 0)
8174  {
8175  // Get the boundary id of the polyline and check if that boundary
8176  // needs a new representation (for example when the boundary was
8177  // splitted in the distribution process)
8178  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8179  if (!boundary_was_splitted(bound_id))
8180  {
8181  unsorted_outer_polyline_pt.push_back(tmp_polyline_pt);
8182  } // if (!boundary_was_splitted(bound_id))
8183  else
8184  {
8185  // Get the polylines that will represent this boundary
8186  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8187  boundary_subpolylines(bound_id);
8188  const unsigned nsub_poly = tmp_vector_polylines.size();
8189 #ifdef PARANOID
8190  if (nsub_poly <= 1)
8191  {
8192  std::ostringstream error_message;
8193  error_message << "The boundary (" << bound_id
8194  << ") was marked to be splitted but\n"
8195  << "there are only (" << nsub_poly
8196  << ") polylines to represent it.\n";
8197  throw OomphLibError(error_message.str(),
8198  OOMPH_CURRENT_FUNCTION,
8199  OOMPH_EXCEPTION_LOCATION);
8200  }
8201 #endif
8202  // Add the new representation of the polylines (sub-polylines)
8203  // to represent this boundary
8204  for (unsigned isub = 0; isub < nsub_poly; isub++)
8205  {
8206  unsorted_outer_polyline_pt.push_back(tmp_vector_polylines[isub]);
8207 #ifdef PARANOID
8208  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8209  if (nsvertex == 0)
8210  {
8211  std::ostringstream error_message;
8212  error_message
8213  << "The current chunk (" << isub << ") of the polyline with\n"
8214  << "boundary id (" << bound_id << ") has no vertices\n";
8215  throw OomphLibError(error_message.str(),
8216  OOMPH_CURRENT_FUNCTION,
8217  OOMPH_EXCEPTION_LOCATION);
8218  } // if (nsvertex == 0)
8219 #endif // #ifdef PARANOID
8220  } // for (isub < nsub_poly)
8221  } // else if (!boundary_was_splitted(bound_id))
8222  } // if (nvertex > 0)
8223  } // for (p < npolylines)
8224  } // for (i < nouter)
8225 
8226  // Get the number of unsorted polylines
8227  unsigned nunsorted_outer_polyline = unsorted_outer_polyline_pt.size();
8228  if (nunsorted_outer_polyline > 0)
8229  {
8230  // Now that we have all the new unsorted polylines it is time to sort them
8231  // so they be all contiguous
8232  sort_polylines_helper(unsorted_outer_polyline_pt, sorted_outer_curves_pt);
8233 
8234  } // if (nunsorted_outer_polyline > 0)
8235 
8236  // *********************************************************************
8237  // Step (2.2) Get the internal closed boundaries and check if it is
8238  // necessary to use a new representation (for example when the boundary
8239  // was splitted in the distribution process)
8240  // *********************************************************************
8241 
8242  // Storage for new created polylines, non sorted
8243  Vector<TriangleMeshPolyLine*> unsorted_internal_closed_polyline_pt;
8244 
8245  // Storing for the polylines on the boundaries
8246  // The first index is for a set of connected polylines
8247  // The second index is for a polyline on a set of connected polylines
8248  Vector<Vector<TriangleMeshPolyLine*>> sorted_internal_closed_curves_pt;
8249 
8250  // Copy the internal closed boundaries to the vector of polylines
8251  const unsigned ninternal_closed = this->Internal_polygon_pt.size();
8252  for (unsigned i = 0; i < ninternal_closed; i++)
8253  {
8254  const unsigned npolylines = this->Internal_polygon_pt[i]->npolyline();
8255  for (unsigned p = 0; p < npolylines; p++)
8256  {
8257  // Pointer to the current polyline
8258  TriangleMeshPolyLine* tmp_polyline_pt =
8259  this->Internal_polygon_pt[i]->polyline_pt(p);
8260  const unsigned nvertex = tmp_polyline_pt->nvertex();
8261  if (nvertex > 0)
8262  {
8263  // Get the boundary id of the polyline and check if that boundary
8264  // needs a new representation (for example when the boundary was
8265  // splitted in the distribution process)
8266  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8267  if (!boundary_was_splitted(bound_id))
8268  {
8269  unsorted_internal_closed_polyline_pt.push_back(tmp_polyline_pt);
8270  } // if (!boundary_was_splitted(bound_id))
8271  else
8272  {
8273  // Get the polylines that will represent this boundary
8274  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8275  boundary_subpolylines(bound_id);
8276  const unsigned nsub_poly = tmp_vector_polylines.size();
8277 #ifdef PARANOID
8278  if (nsub_poly <= 1)
8279  {
8280  std::ostringstream error_message;
8281  error_message << "The boundary (" << bound_id
8282  << ") was marked to be splitted but\n"
8283  << "there are only (" << nsub_poly
8284  << ") polylines to represent it.\n";
8285  throw OomphLibError(error_message.str(),
8286  OOMPH_CURRENT_FUNCTION,
8287  OOMPH_EXCEPTION_LOCATION);
8288  }
8289 #endif
8290  // Add the new representation of the polylines (sub-polylines)
8291  // to represent this boundary
8292  for (unsigned isub = 0; isub < nsub_poly; isub++)
8293  {
8294  unsorted_internal_closed_polyline_pt.push_back(
8295  tmp_vector_polylines[isub]);
8296 #ifdef PARANOID
8297  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8298  if (nsvertex == 0)
8299  {
8300  std::ostringstream error_message;
8301  error_message
8302  << "The current chunk (" << isub << ") of the polyline with\n"
8303  << "boundary id (" << bound_id << ") has no vertices\n";
8304  throw OomphLibError(error_message.str(),
8305  OOMPH_CURRENT_FUNCTION,
8306  OOMPH_EXCEPTION_LOCATION);
8307  } // if (nsvertex == 0)
8308 #endif // #ifdef PARANOID
8309  } // for (isub < nsub_poly)
8310  } // else if (!boundary_was_splitted(bound_id))
8311  } // if (nvertex > 0)
8312  } // for (p < npolylines)
8313  } // for (i < ninternal_closed)
8314 
8315  const unsigned nunsorted_internal_closed_polyline =
8316  unsorted_internal_closed_polyline_pt.size();
8317 
8318  if (nunsorted_internal_closed_polyline > 0)
8319  {
8320  // Now that we have all the new unsorted polylines it is time to sort them
8321  // so they be all contiguous
8322  sort_polylines_helper(unsorted_internal_closed_polyline_pt,
8323  sorted_internal_closed_curves_pt);
8324  }
8325 
8326  // *********************************************************************
8327  // Step (2.3) Get the internal open boundaries and check if it is
8328  // necessary to use a new representation (for example when the boundary
8329  // was splitted in the distribution process)
8330  // *********************************************************************
8331 
8332  // Storage for new created polylines, non sorted
8333  Vector<TriangleMeshPolyLine*> unsorted_internal_open_polyline_pt;
8334 
8335  // Storing for the polylines on the boundaries
8336  // The first index is for a set of connected polylines
8337  // The second index is for a polyline on a set of connected polylines
8338  Vector<Vector<TriangleMeshPolyLine*>> sorted_internal_open_curves_pt;
8339 
8340  // Copy the internal open boundaries to the vector of polylines
8341  const unsigned ninternal_open = this->Internal_open_curve_pt.size();
8342  for (unsigned i = 0; i < ninternal_open; i++)
8343  {
8344  const unsigned ncurve_section =
8345  this->Internal_open_curve_pt[i]->ncurve_section();
8346  for (unsigned p = 0; p < ncurve_section; p++)
8347  {
8348  // Pointer to the current polyline
8349  TriangleMeshPolyLine* tmp_polyline_pt =
8350  this->Internal_open_curve_pt[i]->polyline_pt(p);
8351  const unsigned nvertex = tmp_polyline_pt->nvertex();
8352  if (nvertex > 0)
8353  {
8354  // Get the boundary id of the polyline and check if that boundary
8355  // needs a new representation (for example when the boundary was
8356  // splitted in the distribution process)
8357  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8358  if (!boundary_was_splitted(bound_id))
8359  {
8360  // Only include as internal boundaries those not marked as
8361  // shared boundaries
8362  if (!boundary_marked_as_shared_boundary(bound_id, 0))
8363  {
8364  unsorted_internal_open_polyline_pt.push_back(tmp_polyline_pt);
8365  }
8366  } // if (!boundary_was_splitted(bound_id))
8367  else
8368  {
8369  // Get the polylines that will represent this boundary
8370  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8371  boundary_subpolylines(bound_id);
8372  const unsigned nsub_poly = tmp_vector_polylines.size();
8373 #ifdef PARANOID
8374  if (nsub_poly <= 1)
8375  {
8376  std::ostringstream error_message;
8377  error_message << "The boundary (" << bound_id
8378  << ") was marked to be splitted but\n"
8379  << "there are only (" << nsub_poly
8380  << ") polylines to represent it.\n";
8381  throw OomphLibError(error_message.str(),
8382  OOMPH_CURRENT_FUNCTION,
8383  OOMPH_EXCEPTION_LOCATION);
8384  }
8385 #endif
8386  // Add the new representation of the polylines (sub-polylines)
8387  // to represent this boundary
8388  for (unsigned isub = 0; isub < nsub_poly; isub++)
8389  {
8390  // Only include as internal boundaries those not marked as
8391  // shared boundaries
8392  if (!boundary_marked_as_shared_boundary(bound_id, isub))
8393  {
8394  unsorted_internal_open_polyline_pt.push_back(
8395  tmp_vector_polylines[isub]);
8396  }
8397 #ifdef PARANOID
8398  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8399  if (nsvertex == 0)
8400  {
8401  std::ostringstream error_message;
8402  error_message
8403  << "The current chunk (" << isub << ") of the polyline with\n"
8404  << "boundary id (" << bound_id << ") has no vertices\n";
8405  throw OomphLibError(error_message.str(),
8406  OOMPH_CURRENT_FUNCTION,
8407  OOMPH_EXCEPTION_LOCATION);
8408  } // if (nsvertex == 0)
8409 #endif // #ifdef PARANOID
8410  } // for (isub < nsub_poly)
8411  } // else if (!boundary_was_splitted(bound_id))
8412  } // if (nvertex > 0)
8413  } // for (p < npolylines)
8414  } // for (i < ninternal_open)
8415 
8416  const unsigned nunsorted_internal_open_polyline =
8417  unsorted_internal_open_polyline_pt.size();
8418 
8419  if (nunsorted_internal_open_polyline > 0)
8420  {
8421  // Now that we have all the new unsorted polylines it is time to sort them
8422  // so they be all contiguous
8423  sort_polylines_helper(unsorted_internal_open_polyline_pt,
8424  sorted_internal_open_curves_pt);
8425  }
8426 
8427  // ********************************************************************
8428  // Step (2.4) Sort the polylines on the shared boundaries
8429  // ********************************************************************
8430 
8431  // Storage for new created polylines, non sorted
8432  Vector<TriangleMeshPolyLine*> unsorted_shared_polyline_pt;
8433 
8434  // Special storage for the shared polylines that will be also used
8435  // to connect with the internal boundaries
8436  Vector<TriangleMeshPolyLine*> unsorted_shared_to_internal_polyline_pt;
8437 
8438  // Storing for the polylines on the shared boundaries
8439  // The first index is for a set of connected polylines
8440  // The second index is for a polyline on a set of connected polylines
8441  Vector<Vector<TriangleMeshPolyLine*>> sorted_shared_curves_pt;
8442 
8443  // Copy the shared boudaries to the vector of polylines
8444  const unsigned ncurves = nshared_boundary_curves(my_rank);
8445  for (unsigned i = 0; i < ncurves; i++)
8446  {
8447  const unsigned npolylines = nshared_boundary_polyline(my_rank, i);
8448  for (unsigned p = 0; p < npolylines; p++)
8449  {
8450  const unsigned nvertex =
8451  shared_boundary_polyline_pt(my_rank, i, p)->nvertex();
8452  if (nvertex > 0)
8453  {
8454  TriangleMeshPolyLine* tmp_shared_poly_pt =
8455  shared_boundary_polyline_pt(my_rank, i, p);
8456 
8457  // First check if there are shared boundaries overlapping
8458  // internal boundaries
8459  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
8460  {
8461  // Get the boundary id of the shared polyline
8462  const unsigned shd_bnd_id = tmp_shared_poly_pt->boundary_id();
8463  // If the shared polyline is marked as internal boundary
8464  // then include it in the special storage to look for
8465  // connection with internal boundaries
8466  if (this->shared_boundary_overlaps_internal_boundary(shd_bnd_id))
8467  {
8468  unsorted_shared_to_internal_polyline_pt.push_back(
8469  tmp_shared_poly_pt);
8470  }
8471  }
8472  unsorted_shared_polyline_pt.push_back(tmp_shared_poly_pt);
8473  }
8474  }
8475  }
8476 
8477  // Get the total number of shared polylines
8478  const unsigned nunsorted_shared_polyline =
8479  unsorted_shared_polyline_pt.size();
8480 
8481  if (nunsorted_shared_polyline > 0)
8482  {
8483  // Now that we have all the new unsorted polylines it is time to
8484  // sort them so they be all contiguous
8485  sort_polylines_helper(unsorted_shared_polyline_pt,
8486  sorted_shared_curves_pt);
8487  }
8488 
8489  // ********************************************************************
8490  // Step (3) Join the boundaries (shared, internal and outer to
8491  // create the new polygons)
8492  // ********************************************************************
8493 
8494  // Create the set of curves that will be used to create the new polygons
8495  // Get the total number of curves
8496  const unsigned nouter_curves = sorted_outer_curves_pt.size();
8497  const unsigned ninternal_closed_curves =
8498  sorted_internal_closed_curves_pt.size();
8499  const unsigned nshared_curves = sorted_shared_curves_pt.size();
8500  const unsigned ntotal_curves =
8501  nouter_curves + ninternal_closed_curves + nshared_curves;
8502 
8503  // Add all the polylines to a container
8504  unsigned counter = 0;
8505  Vector<Vector<TriangleMeshPolyLine*>> all_curves_pt(ntotal_curves);
8506 
8507  // Add the shared curves first, this ensure the generation of
8508  // internal polygons defined by the shared boundaries
8509  for (unsigned i = 0; i < nshared_curves; i++, counter++)
8510  {
8511  all_curves_pt[counter] = sorted_shared_curves_pt[i];
8512  }
8513 
8514  // Add the internal polygons (if any)
8515  for (unsigned i = 0; i < ninternal_closed_curves; i++, counter++)
8516  {
8517  all_curves_pt[counter] = sorted_internal_closed_curves_pt[i];
8518  }
8519 
8520  // Add the outer polygons
8521  for (unsigned i = 0; i < nouter_curves; i++, counter++)
8522  {
8523  all_curves_pt[counter] = sorted_outer_curves_pt[i];
8524  }
8525 
8526  // Create the temporary version of the domain by joining the new
8527  // polylines
8528  this->create_tmp_polygons_helper(all_curves_pt, polygons_pt);
8529  // Create the new open curves
8530  this->create_tmp_open_curves_helper(sorted_internal_open_curves_pt,
8531  unsorted_shared_to_internal_polyline_pt,
8532  open_curves_pt);
8533 
8534  // ********************************************************************
8535  // Step (4) Create connections among the outer boundaries
8536  // (intersections with themselves)
8537  // ********************************************************************
8538 
8539  // After creating the new boundaries representation (polylines)
8540  // establish the connections of the shared boundaries (with
8541  // themselves or with the original boundaries). This avoids the
8542  // multiple definition of vertices in the domain which cause
8543  // problems when calling Triangle
8544 
8545  this->create_shared_polylines_connections();
8546 
8547  // ------------------------------------------------------------------
8548  // Compute the new holes information. Those from the
8549  // extra_holes_coordinates container, and those from the original
8550  // closed boundaries. Add the holes created by the halo elements
8551  // adjacent to the shared boundaries
8552 
8553  // The storage for the new holes, get those from the
8554  // extra_holes_coordinates container and those from the internal
8555  // closed boundaries that are defined as holes
8556  Vector<Vector<double>> new_holes_coordinates;
8557 
8558  // Copy the holes (those defined by the original internal closed
8559  // boundaries and those in the extra holes container)
8560 
8561  // The holes defined by the original internal closed boundaries
8562  const unsigned n_holes = this->Internal_polygon_pt.size();
8563  for (unsigned h = 0; h < n_holes; h++)
8564  {
8565  Vector<double> hole_coordinates =
8566  this->Internal_polygon_pt[h]->internal_point();
8567  // If the closed boundary is a hole, then copy its hole
8568  if (!hole_coordinates.empty())
8569  {
8570  new_holes_coordinates.push_back(hole_coordinates);
8571  }
8572  } // for (h < n_holes)
8573 
8574  // Is this the first time we are going to copy the extra holes
8575  // coordinates
8576  if (First_time_compute_holes_left_by_halo_elements)
8577  {
8578  // The holes in the extra holes container
8579  const unsigned n_extra_holes = Extra_holes_coordinates.size();
8580  for (unsigned h = 0; h < n_extra_holes; h++)
8581  {
8582  Vector<double> hole_coordinates = Extra_holes_coordinates[h];
8583  new_holes_coordinates.push_back(hole_coordinates);
8584  } // for (h < n_extra_holes)
8585 
8586  // Copy the extra holes coordinates
8587  Original_extra_holes_coordinates = Extra_holes_coordinates;
8588 
8589  // Set the flag to false
8590  First_time_compute_holes_left_by_halo_elements = false;
8591 
8592  } // if (First_time_compute_holes_left_by_halo_elements)
8593  else
8594  {
8595  // Not the first time, then only copy the original extra holes
8596  // coordinates
8597  const unsigned n_original_extra_holes =
8598  Original_extra_holes_coordinates.size();
8599  for (unsigned h = 0; h < n_original_extra_holes; h++)
8600  {
8601  Vector<double> hole_coordinates = Original_extra_holes_coordinates[h];
8602  new_holes_coordinates.push_back(hole_coordinates);
8603  } // for (h < n_original_extra_holes)
8604  }
8605 
8606  // Add the holes created by the halo elements adjacent to the shared
8607  // boundaries
8608  compute_holes_left_by_halo_elements_helper(new_holes_coordinates);
8609 
8610  // Update the holes information, only use the coordinate inside the
8611  // poylgons that define the new domain
8612  update_holes_information_helper(polygons_pt, new_holes_coordinates);
8613 
8614  // tachidok Clear the storage by now
8615  // new_holes_coordinates.clear();
8616 
8617  // Now copy the info. in the extra holes coordinates container
8618  Extra_holes_coordinates = new_holes_coordinates;
8619 
8620  // Do not delete halo(ed) info., this will be "deleted"
8621  // automatically by not passing that information to the new adapted
8622  // mesh. Once the transfer of target areas is performed the halo(ed)
8623  // information is no longer required
8624  }
8625 
8626  //======================================================================
8627  // Take the polylines from the shared boundaries and the boundaries
8628  // to create polygons
8629  //======================================================================
8630  template<class ELEMENT>
8632  Vector<Vector<TriangleMeshPolyLine*>>& polylines_pt,
8633  Vector<TriangleMeshPolygon*>& polygons_pt)
8634  {
8635  // Each vector of polylines (curve) is already sorted, it means that
8636  // all the polylines on the vector polylines_pt[i] point to the same
8637  // direction
8638 
8639  // --- Using this fact we should compare the first and last points from
8640  // these arrays of polylines (curves) and compare with the others
8641  // vectors of polylines (curves) end points
8642  // --- Once created a closed curve create a polygon
8643 
8644  // The number of curves
8645  const unsigned ncurves = polylines_pt.size();
8646 
8647  // The number of non sorted curves
8648  const unsigned nunsorted_curves = ncurves;
8649  // The number of sorted curves
8650  unsigned nsorted_curves = 0;
8651 
8652  // Vector to know which ncurve is already done
8653  std::vector<bool> done_curve(ncurves);
8654 
8655  do
8656  {
8657  // The list where to add the curves so that they be contiguous
8658  std::list<Vector<TriangleMeshPolyLine*>> list_building_polygon_pt;
8659 #ifdef PARANOID
8660  // Flag to indicate that a root curve was found
8661  bool root_curve_found = false;
8662 #endif
8663 
8664  // The index for the root_curve (we use it in further iterations as the
8665  // starting index so we dont need to search in already done curves)
8666  unsigned root_curve_idx = 0;
8667 
8668  // Get the root curve
8669  for (unsigned ic = 0; ic < ncurves; ic++)
8670  {
8671  if (!done_curve[ic])
8672  {
8673  root_curve_idx = ic;
8674  nsorted_curves++;
8675 #ifdef PARANOID
8676  root_curve_found = true;
8677 #endif
8678  done_curve[ic] = true;
8679  // ... break the loop
8680  break;
8681  }
8682  }
8683 
8684 #ifdef PARANOID
8685  if (!root_curve_found)
8686  {
8687  std::stringstream err;
8688  err << "The root curve to create a polygon from the shared and "
8689  << "original boundaries was not found!!!\n";
8690  throw OomphLibError(err.str(),
8691  "TriangleMesh::create_tmp_polygons_helper()",
8692  OOMPH_EXCEPTION_LOCATION);
8693  }
8694 #endif
8695 
8696  // Get the root curve
8697  Vector<TriangleMeshPolyLine*> root_curve_pt =
8698  polylines_pt[root_curve_idx];
8699 
8700  // Add the root curve to the list
8701  list_building_polygon_pt.push_back(root_curve_pt);
8702 
8703  // Get the initial and final vertices from the root curve
8704  Vector<double> root_curve_initial_vertex(2);
8705  Vector<double> root_curve_final_vertex(2);
8706 
8707  // We need to get the number of polylines that compose the root curve
8708  const unsigned nroot_curve_polyline = root_curve_pt.size();
8709  // ... and now get the initial and final vertex
8710  root_curve_pt[0]->initial_vertex_coordinate(root_curve_initial_vertex);
8711  root_curve_pt[nroot_curve_polyline - 1]->final_vertex_coordinate(
8712  root_curve_final_vertex);
8713 
8714  // First check if it already create a polygon
8715  double diff =
8716  ((root_curve_initial_vertex[0] - root_curve_final_vertex[0]) *
8717  (root_curve_initial_vertex[0] - root_curve_final_vertex[0])) +
8718  ((root_curve_initial_vertex[1] - root_curve_final_vertex[1]) *
8719  (root_curve_initial_vertex[1] - root_curve_final_vertex[1]));
8720  diff = sqrt(diff);
8721  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8722  {
8723  // The polyline already create a Polygon, then create it!!!
8724  // Create the curve section representation of the current root curve
8725  Vector<TriangleMeshCurveSection*> curve_section_pt(
8726  nroot_curve_polyline);
8727 
8728  // Copy the polylines into its curve section representation
8729  for (unsigned i = 0; i < nroot_curve_polyline; i++)
8730  {
8731  curve_section_pt[i] = root_curve_pt[i];
8732  }
8733 
8734  // ... and create the Polygon
8735  TriangleMeshPolygon* new_polygon_pt =
8736  new TriangleMeshPolygon(curve_section_pt);
8737 
8738  // Mark the polygon for deletion (in the destructor)
8739  this->Free_polygon_pt.insert(new_polygon_pt);
8740 
8741  // Add the polygon to the output polygons
8742  polygons_pt.push_back(new_polygon_pt);
8743  } // (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8744  // when the curve creates a Polygon by itself
8745  else
8746  {
8747  // Flag to continue iterating while curves be added to the left
8748  // or right of the list of curves
8749  bool added_curve = false;
8750 #ifdef PARANOID
8751  // Flag to know if the "loop" finish because a polygon was
8752  // created or because no more curves can be added to the left or
8753  // right
8754  bool polygon_created = false;
8755 #endif
8756  do
8757  {
8758  added_curve = false;
8759  // If the root curve does not create a closed polygon then add curves
8760  // to the left or right until the curves create a closed polygon
8761  for (unsigned ic = root_curve_idx + 1; ic < ncurves; ic++)
8762  {
8763  if (!done_curve[ic])
8764  {
8765  // Get the current curve
8766  Vector<TriangleMeshPolyLine*> current_curve_pt = polylines_pt[ic];
8767 
8768  // We need to get the number of polylines that compose the
8769  // current curve
8770  const unsigned ncurrent_curve_polyline = current_curve_pt.size();
8771 
8772  // ... and get the initial and final coordinates for the current
8773  // curve
8774  Vector<double> current_curve_initial_vertex(2);
8775  Vector<double> current_curve_final_vertex(2);
8776 
8777  current_curve_pt[0]->initial_vertex_coordinate(
8778  current_curve_initial_vertex);
8779  current_curve_pt[ncurrent_curve_polyline - 1]
8780  ->final_vertex_coordinate(current_curve_final_vertex);
8781 
8782  // ---------------------------------------------------------------
8783  // Start adding curves to the left or right
8784  // ---------------------------------------------------------------
8785  diff = ((current_curve_final_vertex[0] -
8786  root_curve_initial_vertex[0]) *
8787  (current_curve_final_vertex[0] -
8788  root_curve_initial_vertex[0])) +
8789  ((current_curve_final_vertex[1] -
8790  root_curve_initial_vertex[1]) *
8791  (current_curve_final_vertex[1] -
8792  root_curve_initial_vertex[1]));
8793  diff = sqrt(diff);
8794  // CURRENT curve to the LEFT of the ROOT curve
8795  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8796  {
8797  // Add the current curve to the left
8798  list_building_polygon_pt.push_front(current_curve_pt);
8799  // Mark the curve as done
8800  done_curve[ic] = true;
8801  // Update the initial vertex values
8802  root_curve_initial_vertex[0] = current_curve_initial_vertex[0];
8803  root_curve_initial_vertex[1] = current_curve_initial_vertex[1];
8804  // Increase the number of sorted curves
8805  nsorted_curves++;
8806  // Set the flag to indicate that a curve was added to the list
8807  added_curve = true;
8808  break;
8809  }
8810 
8811  diff = ((current_curve_initial_vertex[0] -
8812  root_curve_initial_vertex[0]) *
8813  (current_curve_initial_vertex[0] -
8814  root_curve_initial_vertex[0])) +
8815  ((current_curve_initial_vertex[1] -
8816  root_curve_initial_vertex[1]) *
8817  (current_curve_initial_vertex[1] -
8818  root_curve_initial_vertex[1]));
8819  diff = sqrt(diff);
8820  // CURRENT curve to the LEFT of the ROOT curve but INVERTED
8821  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8822  {
8823  Vector<TriangleMeshPolyLine*> tmp_curve_pt(
8824  ncurrent_curve_polyline);
8825  // Reverse each polyline and back them up
8826  for (unsigned it = 0; it < ncurrent_curve_polyline; it++)
8827  {
8828  current_curve_pt[it]->reverse();
8829  tmp_curve_pt[it] = current_curve_pt[it];
8830  }
8831  // Now copy them back but in reverse order
8832  unsigned count = 0;
8833  for (int i = ncurrent_curve_polyline - 1; i >= 0; i--, count++)
8834  {
8835  current_curve_pt[count] = tmp_curve_pt[i];
8836  }
8837  // Add the current curve to the left
8838  list_building_polygon_pt.push_front(current_curve_pt);
8839  // Mark the curve as done
8840  done_curve[ic] = true;
8841  // Update the initial vertex values
8842  root_curve_initial_vertex[0] = current_curve_final_vertex[0];
8843  root_curve_initial_vertex[1] = current_curve_final_vertex[1];
8844  // Increase the number of sorted curves
8845  nsorted_curves++;
8846  // Set the flag to indicate that a curve was added to the list
8847  added_curve = true;
8848  break;
8849  }
8850 
8851  diff = ((current_curve_initial_vertex[0] -
8852  root_curve_final_vertex[0]) *
8853  (current_curve_initial_vertex[0] -
8854  root_curve_final_vertex[0])) +
8855  ((current_curve_initial_vertex[1] -
8856  root_curve_final_vertex[1]) *
8857  (current_curve_initial_vertex[1] -
8858  root_curve_final_vertex[1]));
8859  diff = sqrt(diff);
8860  // CURRENT curve to the RIGHT of the ROOT curve
8861  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8862  {
8863  // Add the current curve to the right
8864  list_building_polygon_pt.push_back(current_curve_pt);
8865  // Mark the curve as done
8866  done_curve[ic] = true;
8867  // Update the initial vertex values
8868  root_curve_final_vertex[0] = current_curve_final_vertex[0];
8869  root_curve_final_vertex[1] = current_curve_final_vertex[1];
8870  // Increase the number of sorted curves
8871  nsorted_curves++;
8872  // Set the flag to indicate that a curve was added to the list
8873  added_curve = true;
8874  break;
8875  }
8876 
8877  diff =
8878  ((current_curve_final_vertex[0] - root_curve_final_vertex[0]) *
8879  (current_curve_final_vertex[0] - root_curve_final_vertex[0])) +
8880  ((current_curve_final_vertex[1] - root_curve_final_vertex[1]) *
8881  (current_curve_final_vertex[1] - root_curve_final_vertex[1]));
8882  diff = sqrt(diff);
8883  // CURRENT curve to the RIGHT of the ROOT curve but INVERTED
8884  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8885  {
8886  Vector<TriangleMeshPolyLine*> tmp_curve_pt(
8887  ncurrent_curve_polyline);
8888  // Reverse each polyline and back them up
8889  for (unsigned it = 0; it < ncurrent_curve_polyline; it++)
8890  {
8891  current_curve_pt[it]->reverse();
8892  tmp_curve_pt[it] = current_curve_pt[it];
8893  }
8894  // Now copy them back but in reverse order
8895  unsigned count = 0;
8896  for (int i = ncurrent_curve_polyline - 1; i >= 0; i--, count++)
8897  {
8898  current_curve_pt[count] = tmp_curve_pt[i];
8899  }
8900  // Add the current curve to the right
8901  list_building_polygon_pt.push_back(current_curve_pt);
8902  // Mark the curve as done
8903  done_curve[ic] = true;
8904  // Update the initial vertex values
8905  root_curve_final_vertex[0] = current_curve_initial_vertex[0];
8906  root_curve_final_vertex[1] = current_curve_initial_vertex[1];
8907  // Increase the number of sorted curves
8908  nsorted_curves++;
8909  // Set the flag to indicate that a curve was added to the list
8910  added_curve = true;
8911  break;
8912  }
8913 
8914  } // if (!done_curve[ic])
8915 
8916  } // for (ic < ncurves)
8917 
8918  // After adding a curve check if it is possible to create a polygon
8919  double diff =
8920  ((root_curve_initial_vertex[0] - root_curve_final_vertex[0]) *
8921  (root_curve_initial_vertex[0] - root_curve_final_vertex[0])) +
8922  ((root_curve_initial_vertex[1] - root_curve_final_vertex[1]) *
8923  (root_curve_initial_vertex[1] - root_curve_final_vertex[1]));
8924  diff = sqrt(diff);
8925  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8926  {
8927  // If the curves already create a Polygon then go out of the
8928  // loop and create the Polygon
8929  added_curve = false;
8930 #ifdef PARANOID
8931  // Set the flag to indicate that a Polygon has been created
8932  polygon_created = true;
8933 #endif
8934  } // (diff <
8935  // ToleranceForVertexMismatchInPolygons::Tolerable_error)
8936  // when the curve creates a Polygon by itself
8937 
8938  } while (added_curve);
8939 
8940 #ifdef PARANOID
8941  if (!polygon_created)
8942  {
8943  std::stringstream error_message;
8944  error_message
8945  << "It was no possible to create a TriangleMeshPolygon with "
8946  << "the input set of curves\n"
8947  << "These are the initial and final vertices in the current "
8948  << "sorted list of\nTriangleMeshPolyLines\n\n";
8949  Vector<double> init_vertex(2);
8950  Vector<double> final_vertex(2);
8951  unsigned icurve = 0;
8952  for (std::list<Vector<TriangleMeshPolyLine*>>::iterator it =
8953  list_building_polygon_pt.begin();
8954  it != list_building_polygon_pt.end();
8955  it++, icurve++)
8956  {
8957  const unsigned ncurrent_curve_polyline = (*it).size();
8958  error_message << "TriangleMeshCurve #" << icurve << "\n"
8959  << "-----------------------------------\n";
8960  for (unsigned ip = 0; ip < ncurrent_curve_polyline; ip++)
8961  {
8962  Vector<double> init_vertex(2);
8963  Vector<double> final_vertex(2);
8964  (*it)[ip]->initial_vertex_coordinate(init_vertex);
8965  (*it)[ip]->final_vertex_coordinate(final_vertex);
8966  error_message << "TriangleMeshPolyLine #" << ip << "\n"
8967  << "Initial vertex: (" << init_vertex[0] << ","
8968  << init_vertex[1] << ")\n"
8969  << "Final vertex: (" << final_vertex[0] << ","
8970  << final_vertex[1] << ")\n";
8971  } // for (ip < ncurrent_curve_polyline)
8972  } // for (it != list_building_polygon_pt.end())
8973 
8974  throw OomphLibError(error_message.str(),
8975  "TriangleMesh::create_tmp_polygons_helper()",
8976  OOMPH_EXCEPTION_LOCATION);
8977 
8978  } // if (!polygon_created)
8979 #endif
8980 
8981  // Create the polygon after joining the curves
8982  unsigned ntotal_polylines = 0;
8983  // Get the total number of polylines
8984  for (std::list<Vector<TriangleMeshPolyLine*>>::iterator it =
8985  list_building_polygon_pt.begin();
8986  it != list_building_polygon_pt.end();
8987  it++)
8988  {
8989  ntotal_polylines += (*it).size();
8990  }
8991 
8992  // Create the curve section representation of the curves on the list
8993  Vector<TriangleMeshCurveSection*> curve_section_pt(ntotal_polylines);
8994 
8995  // Copy the polylines into its curve section representation
8996  unsigned counter = 0;
8997  for (std::list<Vector<TriangleMeshPolyLine*>>::iterator it =
8998  list_building_polygon_pt.begin();
8999  it != list_building_polygon_pt.end();
9000  it++)
9001  {
9002  const unsigned ncurrent_curve_polyline = (*it).size();
9003  for (unsigned ip = 0; ip < ncurrent_curve_polyline; ip++, counter++)
9004  {
9005  curve_section_pt[counter] = (*it)[ip];
9006  } // for (ip < ncurrent_curve_polyline)
9007  } // Loop over the list of polylines
9008 
9009  // ... and create the Polygon
9010  TriangleMeshPolygon* new_polygon_pt =
9011  new TriangleMeshPolygon(curve_section_pt);
9012 
9013  // Mark the polygon for deletion (in the destructor)
9014  this->Free_polygon_pt.insert(new_polygon_pt);
9015 
9016  // Add the polygon to the output polygons
9017  polygons_pt.push_back(new_polygon_pt);
9018 
9019  } // else
9020  // (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
9021 
9022  } while (nsorted_curves < nunsorted_curves);
9023  }
9024 
9025  //======================================================================
9026  // Take the polylines from the original open curves and created
9027  // new temporaly representations of open curves with the bits of
9028  // original curves not overlapped by shared boundaries
9029  //======================================================================
9030  template<class ELEMENT>
9032  Vector<Vector<TriangleMeshPolyLine*>>& sorted_open_curves_pt,
9033  Vector<TriangleMeshPolyLine*>& unsorted_shared_to_internal_poly_pt,
9034  Vector<TriangleMeshOpenCurve*>& open_curves_pt)
9035  {
9036  // Here search for the connections of the open curves remaining as
9037  // open curves with the shared boundaries markes as internal
9038  const unsigned ninternal_open_curves = sorted_open_curves_pt.size();
9039 
9040  // Once identified the connections created with the new internal
9041  // boundaries representations add them to the open curves container
9042  for (unsigned i = 0; i < ninternal_open_curves; i++)
9043  {
9044  // Create the curve section representation of the polylines
9045  const unsigned npoly = sorted_open_curves_pt[i].size();
9046  Vector<TriangleMeshCurveSection*> tmp_curve_section(npoly);
9047  for (unsigned j = 0; j < npoly; j++)
9048  {
9049  tmp_curve_section[j] = sorted_open_curves_pt[i][j];
9050  }
9051  // ... and create the Open Curve
9052  TriangleMeshOpenCurve* new_open_curve_pt =
9053  new TriangleMeshOpenCurve(tmp_curve_section);
9054 
9055  // Mark the open curve for deletion (in the destructor)
9056  this->Free_open_curve_pt.insert(new_open_curve_pt);
9057 
9058  // Add the open curve to the output open curves
9059  open_curves_pt.push_back(new_open_curve_pt);
9060 
9061  } // (i < ninternal_open_curves)
9062  }
9063 
9064  //======================================================================
9065  // Check for any possible connections that the array of sorted
9066  // nodes have with original boundary nodes, previous shared polyline
9067  // nodes or with itself polyline nodes. In case that there is a
9068  // connection, get the boundary id to which connects
9069  //======================================================================
9070  template<class ELEMENT>
9072  std::set<FiniteElement*>& element_in_processor_pt,
9073  const int& root_edge_bnd_id,
9074  std::map<std::pair<Node*, Node*>, bool>& overlapped_face,
9075  std::map<unsigned, std::map<Node*, bool>>&
9076  node_on_bnd_not_overlapped_by_shd_bnd,
9077  std::list<Node*>& current_polyline_nodes,
9078  std::map<unsigned, std::list<Node*>>& shared_bnd_id_to_sorted_list_node_pt,
9079  const unsigned& node_degree,
9080  Node*& new_node_pt,
9081  const bool called_from_load_balance)
9082  {
9083  // Initialize the flag to return
9084  int flag_to_return = -1;
9085 
9086  // --------------------------------------------------------------------
9087  // First try to find a connection with any original boundary (keep
9088  // in mind the case when internal boundaries may be overlapped by
9089  // shared boundaries)
9090  // --------------------------------------------------------------------
9091 
9092  // Check if the shared boundary is overlapping an internal boundary
9093  bool overlapping_internal_boundary = false;
9094  // The boundary id overlapped by the current shared boundary
9095  unsigned internal_overlaping_bnd_id = 0;
9096  if (root_edge_bnd_id != -1)
9097  {
9098  // Set the flat to true
9099  overlapping_internal_boundary = true;
9100  // Set the bnd id of the overlapped internal boundary
9101  internal_overlaping_bnd_id = static_cast<unsigned>(root_edge_bnd_id);
9102  } // if (root_edge_bnd_id != -1)
9103 
9104  // ---------------------------------------------------------------
9105  // Check if the connection is with an original boundary by checking
9106  // if the new node is a boundary node, and it lives in an element
9107  // that is part of the domain
9108  // ---------------------------------------------------------------
9109  if (new_node_pt->is_on_boundary())
9110  {
9111  // Flag to indicate if the node lives in a non overlapped boundary
9112  bool is_node_living_in_non_overlapped_boundary = false;
9113 
9114  // If the node is a boundary node then check in which boundary it
9115  // is
9116  const unsigned noriginal_bnd = this->initial_shared_boundary_id();
9117  for (unsigned bb = 0; bb < noriginal_bnd; bb++)
9118  {
9119  // If the shared boundary overlaps an internal boundary it will
9120  // be indicated by (root_edge_bnd_id != -1), the original
9121  // internal boundary that overlaps is given by the
9122  // root_edge_bnd_id value. We skip that original internal
9123  // boundary because the new node will be obviously ON the
9124  // internal boundary
9125  if (overlapping_internal_boundary)
9126  {
9127  // Is the node on boundary bb?
9128  if (new_node_pt->is_on_boundary(bb))
9129  {
9130  // If overlaping then check that the boundary is different
9131  // from the one that is being overlapped, or if overlapped
9132  // then check that the node is on an edge on the bb
9133  // boundary not overlapped by a shared boundary
9134  const bool on_bnd_edge_not_overlapped_by_shd_bnd =
9135  node_on_bnd_not_overlapped_by_shd_bnd[bb][new_node_pt];
9136  if (bb != internal_overlaping_bnd_id ||
9137  ((bb == internal_overlaping_bnd_id) &&
9138  (on_bnd_edge_not_overlapped_by_shd_bnd)))
9139  {
9140  // Is the node living in a non overlapped boundary
9141  if (bb != internal_overlaping_bnd_id)
9142  {
9143  is_node_living_in_non_overlapped_boundary = true;
9144  }
9145 
9146  // Now we need to check that the node lies on a boundary
9147  // that still exist (the elements associated to the
9148  // boundary may have been removed at the mesh distribution
9149  // stage). The node may be still marked as a boundary node
9150  // but the boundary may not have elements associated.
9151 
9152  // Get the number of elements in the boundary
9153  const unsigned n_bound_ele = this->nboundary_element(bb);
9154  if (n_bound_ele > 0)
9155  {
9156  // Check that node lies on a nonhalo element, those are
9157  // the elements used to update the domain representation
9158  for (unsigned e = 0; e < n_bound_ele; e++)
9159  {
9160  // Get the boundary bulk element
9161  FiniteElement* bulk_ele_pt = this->boundary_element_pt(bb, e);
9162  // Check if the element will be retained, it means it
9163  // is a nonhalo element
9164  std::set<FiniteElement*>::iterator it =
9165  element_in_processor_pt.find(bulk_ele_pt);
9166  // If found then check if the node live in the element
9167  if (it != element_in_processor_pt.end())
9168  {
9169  // Found the node in the nonhalo face element
9170  bool found_node = false;
9171  // Get the face index
9172  int face_index = this->face_index_at_boundary(bb, e);
9173  // Create the face element
9174  FiniteElement* face_ele_pt =
9175  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
9176  // Get the number of nodes in the face element
9177  const unsigned n_node_face = face_ele_pt->nnode();
9178  // Get the first and last node of the face element
9179  Node* first_node_pt = face_ele_pt->node_pt(0);
9180  Node* last_node_pt = face_ele_pt->node_pt(n_node_face - 1);
9181  // Create the edge with the pair of nodes
9182  std::pair<Node*, Node*> tmp_edge =
9183  std::make_pair(first_node_pt, last_node_pt);
9184  // Check if the face element edge is overlapped by a
9185  // shared boundary
9186  // Is the face not overlapped?
9187  if (!overlapped_face[tmp_edge])
9188  {
9189  // Look for the node in the current face element
9190  for (unsigned n = 0; n < n_node_face; n++)
9191  {
9192  // Check for every individual node
9193  if (face_ele_pt->node_pt(n) == new_node_pt)
9194  {
9195  found_node = true;
9196  break;
9197  } // if (face_ele_pt->node_pt(n) == new_node_pt)
9198  } // for (n < n_node_face)
9199  } // if (!overlapped_face[tmp_edge])
9200  // Free the memory of the face element
9201  delete face_ele_pt;
9202  if (found_node)
9203  {
9204  // return the first original boundary id found,
9205  // does not matter if the node lies on more than
9206  // one original boundary (with boundary
9207  // elements). This is the original boundary id
9208  // that will be used to create the connection
9209  flag_to_return = bb;
9210  return flag_to_return;
9211  } // if (found_node)
9212 
9213  } // if (it!=element_in_processor_pt.end())
9214 
9215  } // for (e < n_bound_ele)
9216 
9217  } // if (n_bound_ele > 0)
9218 
9219  } // if (bb != internal_overlaping_bnd_id ||
9220  // ((bb == internal_overlaping_bnd_id) &&
9221  // (on_bnd_edge_not_overlapped_by_shd_bnd)))
9222 
9223  } // if (nod_pt->is_on_boundary(bb))
9224 
9225  } // if (overlapping_internal_boundary)
9226  else
9227  {
9228  // Is the node on boundary bb?
9229  if (new_node_pt->is_on_boundary(bb))
9230  {
9231  // Now we need to check that the node lies on a boundary
9232  // that still exist (the elements associated to the boundary
9233  // may have been removed at the mesh distribution
9234  // stage). The node may be still marked as a boundary node
9235  // but the boundary may not have elements associated.
9236 
9237  // Get the number of elements in the boundary
9238  const unsigned n_bound_ele = this->nboundary_element(bb);
9239  if (n_bound_ele > 0)
9240  {
9241  // Check that node lies on a nonhalo element, those are
9242  // the elements used to update the domain representation
9243  for (unsigned e = 0; e < n_bound_ele; e++)
9244  {
9245  // Get the boundary bulk element
9246  FiniteElement* bulk_ele_pt = this->boundary_element_pt(bb, e);
9247  // Check if the element will be retained, it means it is
9248  // a nonhalo element
9249  std::set<FiniteElement*>::iterator it =
9250  element_in_processor_pt.find(bulk_ele_pt);
9251  // If found then check if the node live in the element
9252  if (it != element_in_processor_pt.end())
9253  {
9254  // Found the node in the nonhalo face element
9255  bool found_node = false;
9256  // Get the face index
9257  int face_index = this->face_index_at_boundary(bb, e);
9258  // Create the face element
9259  FiniteElement* face_ele_pt =
9260  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
9261  // Get the number of nodes in the face element
9262  const unsigned n_node_face = face_ele_pt->nnode();
9263  // Get the first and last node of the face element
9264  Node* first_node_pt = face_ele_pt->node_pt(0);
9265  Node* last_node_pt = face_ele_pt->node_pt(n_node_face - 1);
9266  // Create the edge with the pair of nodes
9267  std::pair<Node*, Node*> tmp_edge =
9268  std::make_pair(first_node_pt, last_node_pt);
9269  // Check if the face element edge is overlapped by a
9270  // shared boundary
9271  // Is the face not overlapped?
9272  if (!overlapped_face[tmp_edge])
9273  {
9274  // Look for the node in the current face element
9275  for (unsigned n = 0; n < n_node_face; n++)
9276  {
9277  // Check for every individual node
9278  if (face_ele_pt->node_pt(n) == new_node_pt)
9279  {
9280  found_node = true;
9281  break;
9282  } // if (face_ele_pt->node_pt(n) == new_node_pt)
9283  } // for (n < n_node_face)
9284  } // if (!overlapped_face[tmp_edge])
9285  // Free the memory of the face element
9286  delete face_ele_pt;
9287  if (found_node)
9288  {
9289  // return the first original boundary id found, does
9290  // not matter if the node lies on more than one
9291  // original boundary (with boundary elements). This
9292  // is the original boundary id that will be used to
9293  // create the connection
9294  flag_to_return = bb;
9295  return flag_to_return;
9296  } // if (found_node)
9297 
9298  } // if (it!=element_in_processor_pt.end())
9299 
9300  } // for (e < n_bound_ele)
9301 
9302  } // if (n_bound_ele > 0)
9303 
9304  } // if (nod_pt->is_on_boundary(bb))
9305  } // else if (overlapping_internal_boundary)
9306  } // for (bb < noriginal_bnd)
9307 
9308  // We will only reach this stage when the node was found to be
9309  // connected to an original boundary but the element(s) on that
9310  // boundary where the node should live are not part of the domain.
9311  // Think in a corner of a triangle which touches the boundary
9312  // which elements will not be part of the domain
9313 
9314  // We need to break the currently forming polyline
9315  // flag_to_return = -3;
9316 
9317  // We need to break the currently forming polyline if and only if
9318  // the boundary(ies) in which the node is living is(are) not an
9319  // overlapped boundary
9320  if (!overlapping_internal_boundary)
9321  {
9322  // If the boundary(ies) in which the node is living is(are) an
9323  // overlapped boundary then break the break the formation of the
9324  // polyline
9325  flag_to_return = -3;
9326  }
9327  else
9328  {
9329  // The boundary is overlapped, if the node lives in a non
9330  // overlapped boundary then we can break the formation of the
9331  // polyline
9332  if (is_node_living_in_non_overlapped_boundary)
9333  {
9334  flag_to_return = -3;
9335  } // if (is_node_living_in_non_overlapped_boundar)y
9336 
9337  } // if (!overlapping_internal_boundary)
9338 
9339  } // if (new_node_pt->is_on_boundary())
9340 
9341  // Return inmediately if the connection is with an original boundary
9342  // whose elements are still part of the domain
9343  if (flag_to_return >= 0)
9344  {
9345  return flag_to_return;
9346  }
9347 
9348  // ----------------------------------------------------------------------
9349  // Secondly, if there is not a connection with any original
9350  // boundary, or if there is connection but with an original boundary
9351  // whose elements are not part of the domain, then check for
9352  // connections with previously created shared polylines
9353  // ----------------------------------------------------------------------
9354  // Store all the previous shared polylines to which the current
9355  // found is found to be connected
9356  Vector<unsigned> candidate_shared_bnd_to_connect;
9357  // Check for all the previous polylines except the current one
9358  for (std::map<unsigned, std::list<Node*>>::iterator it =
9359  shared_bnd_id_to_sorted_list_node_pt.begin();
9360  it != shared_bnd_id_to_sorted_list_node_pt.end();
9361  it++)
9362  {
9363  // Get the boundary id of the list of nodes that created the
9364  // polyline (the shared boundary id associated with the list of
9365  // nodes)
9366  const unsigned i_bnd_id = (*it).first;
9367  // Get an iterator pointer to the list of nodes of the shared
9368  // polyline
9369  std::list<Node*>::iterator it_list = (*it).second.begin();
9370  // Get the total number of nodes associated to the boundary
9371  const unsigned n_nodes = (*it).second.size();
9372  // Search for connections in the list of nodes
9373  for (unsigned i = 0; i < n_nodes; i++, it_list++)
9374  {
9375  // Is the node already part of any other shared boundary
9376  if ((*it_list) == new_node_pt)
9377  {
9378  // Include the i-th boundary id in the list of candidate
9379  // shared boundaries to connect
9380  candidate_shared_bnd_to_connect.push_back(i_bnd_id);
9381  // Break the look with the i-th shared boundary, check with
9382  // the others shared boundaries
9383  break;
9384  } // if ((*it_list) == new_node_pt)
9385 
9386  } // for (i < nnodes)
9387 
9388  } // Loop over the shared boundaries and associated nodes
9389 
9390  // Get the number of candidate shared boundaries to connect
9391  const unsigned n_candidate_shared_bnd_to_connect =
9392  candidate_shared_bnd_to_connect.size();
9393 
9394  // Is there a connection with any previous shared polyline
9395  if (n_candidate_shared_bnd_to_connect > 0)
9396  {
9397  // If called from load balance we do not need to check if the
9398  // shared boundary is part of the processor since it certanily is,
9399  // only the shared boundaries that are pare of the processor are
9400  // used to created connection when creating the new shared
9401  // boundaries in the load balance rutine
9402  if (called_from_load_balance)
9403  {
9404  return candidate_shared_bnd_to_connect[0];
9405  }
9406 
9407  // We need to ensure that the shared boundary to which we are
9408  // connecting is part of the current processor, if none of the
9409  // found shared bundaries is in the current processor then return
9410  // the flag for "connection with boundary not in the current
9411  // processor"
9412 
9413  // Store the shared boundaries associated with the current processor
9414  Vector<unsigned> shared_bound_in_this_proc;
9415 
9416  // Get the shared boundaries associated with the current processor
9417  shared_boundaries_in_this_processor(shared_bound_in_this_proc);
9418 
9419  // If any of the candidate shared boundaries to connect is in the
9420  // current processor then return that shared boundary id
9421 
9422  // The number of shared boundaries in the current processor
9423  const unsigned n_shared_bound_in_this_proc =
9424  shared_bound_in_this_proc.size();
9425 
9426  // Loop over the candidate shared boundaries to connect
9427  for (unsigned i = 0; i < n_candidate_shared_bnd_to_connect; i++)
9428  {
9429  // Get the i-th candidate shared boundary to connect
9430  const unsigned i_candidate_shared_bnd =
9431  candidate_shared_bnd_to_connect[i];
9432 
9433  // Loop over the shared boundaries in the current processor
9434  for (unsigned j = 0; j < n_shared_bound_in_this_proc; j++)
9435  {
9436  // Is the candidate boundary a shared boundary in this processor?
9437  if (i_candidate_shared_bnd == shared_bound_in_this_proc[j])
9438  {
9439  // Return the candidate shared boundary
9440  flag_to_return = i_candidate_shared_bnd;
9441  return flag_to_return;
9442  } // The candidate shared boundary is a boundary in the
9443  // current processor
9444 
9445  } // for (j < n_shared_bound_in_this_proc)
9446 
9447  } // for (i < n_candidate_shared_bnd_to_connect)
9448 
9449  // If non of the candidate shared boundaries to connect is in the
9450  // current processor the mark that we need to stop the addition of
9451  // vertices at this side of the polyline
9452  flag_to_return = -3;
9453 
9454  } // if (n_candidate_shared_bnd_to_connect > 0)
9455 
9456  // Return inmediately if the connection is with a previuos shared
9457  // boundary
9458  if (flag_to_return >= 0)
9459  {
9460  return flag_to_return;
9461  }
9462 
9463  // ------------------------------------------------------------------
9464  // Finally,check for connections with the same polyline (the shared
9465  // boundary that is being constructed). We are trying to avoid loops
9466  // or connections with the same shared boundary that is why this is
9467  // checked at the end
9468  // ------------------------------------------------------------------
9469  unsigned nrepeated = 0;
9470  for (std::list<Node*>::iterator it_list = current_polyline_nodes.begin();
9471  it_list != current_polyline_nodes.end();
9472  it_list++)
9473  {
9474  // There must be at least one repeated node (the one that we have
9475  // just added, and it should be the first or last node)
9476  if ((*it_list) == new_node_pt)
9477  {
9478  nrepeated++;
9479  }
9480  }
9481  // If the number of repeated nodes is greater than one then the
9482  // polyline has a connection with itself
9483  if (nrepeated > 1)
9484  {
9485  // Return the flag value to indicate connection with itself, we
9486  // can not return the boundary id of the current polyline since it
9487  // has not been already assigned
9488  flag_to_return = -2;
9489  }
9490 
9491  // If there is no connection at all check the degree of the node, if
9492  // it is greater than 2 then return the flag to stop adding nodes
9493  // after this one
9494  if (node_degree > 2)
9495  {
9496  flag_to_return = -3;
9497  }
9498 
9499  // Return the flag
9500  return flag_to_return;
9501  }
9502 
9503  //======================================================================
9504  // Establish the connections of the polylines previously
9505  // marked as having connections. This connections were created in the
9506  // function TriangleMesh::create_polylines_from_halo_elements_helper().
9507  // In case of doing load balancing the connections were created by the
9508  // function RefineableTriangleMesh::create_new_shared_boundaries()
9509  // ======================================================================
9510  template<class ELEMENT>
9512  {
9513  // Get the rank of the current processor
9514  const unsigned my_rank = this->communicator_pt()->my_rank();
9515 
9516  // Get the shared curves associated with this processor
9517  Vector<Vector<TriangleMeshPolyLine*>> shared_curves_pt =
9518  this->Shared_boundary_polyline_pt[my_rank];
9519 
9520  // Loop through the shared boundaries on the current processor and
9521  // check if they are marked to create a connection
9522  const unsigned ncurves = shared_curves_pt.size();
9523  for (unsigned icurve = 0; icurve < ncurves; icurve++)
9524  {
9525  // Get the number of polylines in the current shared curve
9526  const unsigned npoly = shared_curves_pt[icurve].size();
9527  for (unsigned ipoly = 0; ipoly < npoly; ipoly++)
9528  {
9529  // Get the polyline representation of the shared boundary
9530  TriangleMeshPolyLine* shd_poly_pt = shared_curves_pt[icurve][ipoly];
9531 
9532  // Get the boundary id of the current polyline
9533  const unsigned bound_id = shd_poly_pt->boundary_id();
9534 
9535  // Is the left vertex connected
9536  const bool is_connected_to_the_left =
9537  shd_poly_pt->is_initial_vertex_connected();
9538 
9539  // Is the right vertex connected
9540  const bool is_connected_to_the_right =
9541  shd_poly_pt->is_final_vertex_connected();
9542 
9543  // -----------------------------------------------------------------
9544  // If there is a connection at one of the ends we need to
9545  // establish that connection
9546  if (is_connected_to_the_left || is_connected_to_the_right)
9547  {
9548  // Now get the new left and right vertices of the shared
9549  // polyline
9550  const unsigned n_vertex = shd_poly_pt->nvertex();
9551 
9552  // Now get the polylines to where the current shared boundary is
9553  // connected and create the connections
9554 
9555  // --------------------------------------------------------------
9556  // Connection to the left
9557  if (is_connected_to_the_left)
9558  {
9559  // Get the unsigned version of the bound id to connect to
9560  // the left
9561  const unsigned uconnection_to_the_left =
9562  shd_poly_pt->initial_vertex_connected_bnd_id();
9563 
9564  // The pointer to the boundary to connect
9565  TriangleMeshPolyLine* poly_to_connect_pt = 0;
9566 
9567  // Flag to indicate we are trying to connect to an split
9568  // boundary
9569  bool connecting_to_an_split_boundary = false;
9570 
9571  // Flag to indicate we are trying to connecto to an internal
9572  // boundary that is overlaped by a shared boundary
9573  bool connecting_to_an_overlaped_boundary = false;
9574 
9575  // Check if the connection is with itself
9576  if (uconnection_to_the_left == bound_id)
9577  {
9578  // Set the pointer to the polyline to connect
9579  poly_to_connect_pt = shd_poly_pt;
9580  }
9581  else
9582  {
9583  // Get the initial shared boundary ids
9584  const unsigned initial_shd_bnd_id = initial_shared_boundary_id();
9585  // Check if the boundary to connect is a shared polyline
9586  if (uconnection_to_the_left >= initial_shd_bnd_id)
9587  {
9588  // Get the polyline pointer representing the destination
9589  // boundary
9590  poly_to_connect_pt =
9591  boundary_polyline_pt(uconnection_to_the_left);
9592  } // if (uconnection_to_the_left >= initial_shd_bnd_id)
9593  else
9594  {
9595  // If we are going to connect to an original boundary
9596  // verify if the boundary was splitted during the
9597  // distribution process to consider all the chunks
9598  // (sub-polylines) of the boundary
9599  if (boundary_was_splitted(uconnection_to_the_left))
9600  {
9601  connecting_to_an_split_boundary = true;
9602  } // if (boundary_was_splitted(uconnection_to_the_left))
9603 
9604  // If we are going to connect to an original boundary
9605  // verify if the boundary, or any of its chunks is
9606  // marked to be overlapped by a shared boundary, if that
9607  // is the case we first check for connections in the
9608  // shared boundary that overlaps the internal boundary,
9609  // or the chunks, and then check for connections in the
9610  // original boundary
9611  if (connecting_to_an_split_boundary)
9612  {
9613  // Get the number of chucks that represent the
9614  // destination boundary
9615  const unsigned n_sub_poly =
9616  nboundary_subpolylines(uconnection_to_the_left);
9617  // Now loop over the chunks of the destination
9618  // boundary and if any of them is marked to be
9619  // overlaped by a shared boundary then set the flag
9620  // and break the loop
9621  for (unsigned ii = 0; ii < n_sub_poly; ii++)
9622  {
9623  if (boundary_marked_as_shared_boundary(
9624  uconnection_to_the_left, ii))
9625  {
9626  // Mark the boundary as being overlaped by a
9627  // shared boundary
9628  connecting_to_an_overlaped_boundary = true;
9629  // Break, no need to look for more overlapings
9630  break;
9631  } // if (boundary_marked_as_shared_boundary(...))
9632  } // for (ii < n_sub_poly)
9633  } // if (connecting_to_an_split_boundary)
9634  else
9635  {
9636  // If not connecting to an split boundary then check
9637  // if the whole destination boundary is overlaped by
9638  // an internal boundary
9639  if (boundary_marked_as_shared_boundary(
9640  uconnection_to_the_left, 0))
9641  {
9642  // Mark the boundary as being overlaped by a shared
9643  // boundary
9644  connecting_to_an_overlaped_boundary = true;
9645  } // if (boundary_marked_as_shared_boundary(...))
9646  } // else if (connecting_to_an_split_boundary)
9647 
9648  // If we are connecting neither to an split boundary nor
9649  // an overlaped boundary then get the pointer to the
9650  // original boundary
9651  if (!(connecting_to_an_split_boundary ||
9652  connecting_to_an_overlaped_boundary))
9653  {
9654  // Get the polyline pointer representing the
9655  // destination boundary
9656  poly_to_connect_pt =
9657  boundary_polyline_pt(uconnection_to_the_left);
9658  } // else if (NOT split, NOT overlaped)
9659  } // else if (uconnection_to_the_left >= initial_shd_bnd_id)
9660 
9661  } // else if (uconnection_to_the_left == bound_id)
9662 
9663 #ifdef PARANOID
9664  // If we are not connecting to an original boundary
9665  // (connecting to the same shared boundary or to another
9666  // shared boundary) then the boundary should not be marked
9667  // as split
9668  if (!connecting_to_an_split_boundary)
9669  {
9670  if (boundary_was_splitted(uconnection_to_the_left))
9671  {
9672  std::stringstream error;
9673  error
9674  << "The current shared boundary (" << bound_id << ") was "
9675  << "marked to have a connection\nto the left with the "
9676  << "boundary (" << uconnection_to_the_left << ").\n"
9677  << "The problem is that the destination boundary (possibly\n"
9678  << "another shared boundary) is marked to be split\n"
9679  << "There should not be split shared boundaries\n\n";
9680  throw OomphLibError(
9681  error.str(),
9682  "TriangleMesh::create_shared_polylines_connections()",
9683  OOMPH_EXCEPTION_LOCATION);
9684  }
9685  } // if (!connecting_to_an_split_boundary)
9686 #endif
9687 
9688  // Now look for the vertex number on the destination
9689  // boundary(ies) -- in case that the boundary was split ---
9690 
9691  // Do not check for same orientation, that was previously
9692  // worked by interchanging the connections boundaries (if
9693  // necessary)
9694 
9695  // Get the left vertex in the shared boundary
9696  Vector<double> shd_bnd_left_vertex =
9697  shd_poly_pt->vertex_coordinate(0);
9698 
9699  // If the boundary was not split then ...
9700  if (!connecting_to_an_split_boundary)
9701  {
9702  // ... check if the boundary is marked to be overlaped by
9703  // a shared boundary
9704  if (!connecting_to_an_overlaped_boundary)
9705  {
9706  // If that is not the case then we can safely look for
9707  // the vertex number on the destination boundar
9708  unsigned vertex_index = 0;
9709 
9710  const bool found_vertex_index =
9711  get_connected_vertex_number_on_destination_polyline(
9712  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9713 
9714  // If we could not find the vertex index to connect then
9715  // we are in trouble
9716  if (!found_vertex_index)
9717  {
9718  std::stringstream error;
9719  error
9720  << "The current shared boundary (" << bound_id << ") was "
9721  << "marked to have a connection\nto the left with the "
9722  << "boundary (" << uconnection_to_the_left << ").\n"
9723  << "The problem is that the left vertex of the current\n"
9724  << "shared boundary is not in the list of vertices of the\n"
9725  << "boundary to connect.\n\n"
9726  << "This is the left vertex of the current shared "
9727  "boundary\n"
9728  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9729  << shd_bnd_left_vertex[1] << ")\n\n"
9730  << "This is the list of vertices on the destination "
9731  << "boundary\n";
9732  const unsigned n_v = poly_to_connect_pt->nvertex();
9733  for (unsigned i = 0; i < n_v; i++)
9734  {
9735  Vector<double> cvertex =
9736  poly_to_connect_pt->vertex_coordinate(i);
9737  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
9738  << cvertex[1] << ")\n";
9739  }
9740  throw OomphLibError(
9741  error.str(),
9742  "TriangleMesh::create_shared_polylines_connections()",
9743  OOMPH_EXCEPTION_LOCATION);
9744  } // if (!found_vertex_index)
9745 
9746  // Create the connection, the left vertex of the current
9747  // shared boundary is connected with the vertex_index-th
9748  // vertex on the destination boundary
9749  shd_poly_pt->connect_initial_vertex_to_polyline(
9750  poly_to_connect_pt, vertex_index);
9751 
9752  } // if (!connecting_to_an_overlaped_boundary)
9753  else
9754  {
9755  // If the boundary is marked to be overlaped by a shared
9756  // boundary then get that shared boundary and look for
9757  // the connection in that boundary
9758 
9759  // The vertex where to store the index to connect
9760  unsigned vertex_index = 0;
9761  // A flag to indicate if the connection was found
9762  bool found_vertex_index = false;
9763 
9764  // Get the shared boundary id that is overlaping the
9765  // internal boundary
9766  Vector<unsigned> dst_shd_bnd_ids;
9767  get_shared_boundaries_overlapping_internal_boundary(
9768  uconnection_to_the_left, dst_shd_bnd_ids);
9769 
9770  // Get the number of shared polylines that were found to
9771  // overlap the internal boundary
9772  const unsigned n_shd_bnd_overlap_int_bnd =
9773  dst_shd_bnd_ids.size();
9774 
9775  // Loop over the shared boundaries that overlap the
9776  // internal boundary and look for the vertex to connect
9777  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
9778  {
9779  // Get the shared polyline
9780  const unsigned new_connection_to_the_left =
9781  dst_shd_bnd_ids[ss];
9782 
9783  // Get the shared polyline that is overlaping the
9784  // internal boundary
9785  poly_to_connect_pt =
9786  boundary_polyline_pt(new_connection_to_the_left);
9787 
9788  if (poly_to_connect_pt != 0)
9789  {
9790  // Look for the vertex number in the destination
9791  // shared polyline
9792  found_vertex_index =
9793  get_connected_vertex_number_on_destination_polyline(
9794  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9795  } // if (poly_to_connect_pt!=0)
9796 
9797  // If we have found the vertex to connect then
9798  // break the loop
9799  if (found_vertex_index)
9800  {
9801  break;
9802  } // if (found_vertex_index)
9803 
9804  } // for (ss < n_shd_bnd_overlaping_int_bnd)
9805 
9806 #ifdef PARANOID
9807  // If we could not find the vertex index to connect then
9808  // we are in trouble
9809  if (!found_vertex_index)
9810  {
9811  std::stringstream error;
9812  error
9813  << "The current shared boundary (" << bound_id << ") was "
9814  << "marked to have a connection\nto the left with the "
9815  << "boundary (" << uconnection_to_the_left << ").\n"
9816  << "This last boundary is marked to be overlaped by "
9817  << "shared boundaries\n"
9818  << "The problem is that the left vertex of the current\n"
9819  << "shared boundary is not in the list of vertices of the\n"
9820  << "boundary to connect.\n\n"
9821  << "This is the left vertex of the current shared "
9822  "boundary\n"
9823  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9824  << shd_bnd_left_vertex[1] << ")\n\n"
9825  << "This is the list of vertices on the destination "
9826  << "boundary\n";
9827  Vector<unsigned> dst_shd_bnd_ids;
9828  get_shared_boundaries_overlapping_internal_boundary(
9829  uconnection_to_the_left, dst_shd_bnd_ids);
9830  const unsigned n_shd_bnd_overlap_int_bnd =
9831  dst_shd_bnd_ids.size();
9832  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
9833  {
9834  const unsigned new_connection_to_the_left =
9835  dst_shd_bnd_ids[ss];
9836  poly_to_connect_pt =
9837  boundary_polyline_pt(new_connection_to_the_left);
9838  if (poly_to_connect_pt != 0)
9839  {
9840  const unsigned shd_bnd_id_overlap =
9841  poly_to_connect_pt->boundary_id();
9842  error << "Shared boundary id(" << shd_bnd_id_overlap
9843  << ")\n";
9844  const unsigned n_v = poly_to_connect_pt->nvertex();
9845  for (unsigned i = 0; i < n_v; i++)
9846  {
9847  Vector<double> cvertex =
9848  poly_to_connect_pt->vertex_coordinate(i);
9849  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
9850  << cvertex[1] << ")\n";
9851  }
9852  } // if (poly_to_connect_pt != 0)
9853  } // for (ss < n_shd_bnd_overlap_int_bnd)
9854 
9855  throw OomphLibError(
9856  error.str(),
9857  "TriangleMesh::create_shared_polylines_connections()",
9858  OOMPH_EXCEPTION_LOCATION);
9859 
9860  } // if (!found_vertex_index)
9861 #endif
9862 
9863  // Create the connection, the left vertex of the current
9864  // shared boundary is connected with the vertex_index-th
9865  // vertex on the destination boundary
9866  shd_poly_pt->connect_initial_vertex_to_polyline(
9867  poly_to_connect_pt, vertex_index);
9868 
9869  } // else if (!connecting_to_an_overlaped_boundary)
9870 
9871  } // if (!connecting_to_an_split_boundary)
9872  else
9873  {
9874  // If the boundary was split then we need to look for the
9875  // vertex in the sub-polylines
9876 
9877  // Get the sub-polylines vector
9878  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
9879  boundary_subpolylines(uconnection_to_the_left);
9880 
9881  // Get the number of sub-polylines
9882  const unsigned nsub_poly = tmp_vector_subpolylines.size();
9883 #ifdef PARANOID
9884  if (nsub_poly <= 1)
9885  {
9886  std::ostringstream error_message;
9887  error_message
9888  << "The boundary (" << uconnection_to_the_left << ") was "
9889  << "marked to be splitted but\n"
9890  << "there are only (" << nsub_poly << ") polylines to "
9891  << "represent it.\n";
9892  throw OomphLibError(
9893  error_message.str(),
9894  "TriangleMesh::create_shared_polylines_connections()",
9895  OOMPH_EXCEPTION_LOCATION);
9896  } // if (nsub_poly <= 1)
9897 #endif
9898  // We need to check if the boundary is marked to be
9899  // overlaped by an internal boundary, if that is the case
9900  // we need to check for each indivual subpolyline, and for
9901  // those overlaped by a shared polyline look for the
9902  // vertex in the shared polyline representation instead of
9903  // the original subpolyline
9904 
9905  // ... check if the boundary is marked to be overlaped by
9906  // a shared boundary
9907  if (!connecting_to_an_overlaped_boundary)
9908  {
9909  // We can work without checking the subpolylines
9910  // individually
9911 
9912  // The vertex where to store the index to connect
9913  unsigned vertex_index = 0;
9914  // The subpoly number to connect
9915  unsigned sub_poly_to_connect = 0;
9916  // A flag to indicate if the connection was found
9917  bool found_vertex_index = false;
9918 
9919  // Look for the vertex number to connect on each of the
9920  // subpolyines
9921  for (unsigned isub = 0; isub < nsub_poly; isub++)
9922  {
9923  // Assign the pointer to the sub-polyline
9924  poly_to_connect_pt = tmp_vector_subpolylines[isub];
9925  // Search for the vertex in the current sub-polyline
9926  found_vertex_index =
9927  get_connected_vertex_number_on_destination_polyline(
9928  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9929  // If we have found the vertex to connect then break the
9930  // loop
9931  if (found_vertex_index)
9932  {
9933  // But first save the subpoly number (chunk), that
9934  // will be used to perform the connection
9935  sub_poly_to_connect = isub;
9936  break;
9937  } // if (found_vertex_index)
9938  } // for (isub < nsub_poly)
9939 
9940 #ifdef PARANOID
9941  // If we could not find the vertex index to connect then
9942  // we are in trouble
9943  if (!found_vertex_index)
9944  {
9945  std::stringstream error;
9946  error
9947  << "The current shared boundary (" << bound_id << ") was "
9948  << "marked to have a connection\nto the left with the "
9949  << "boundary (" << uconnection_to_the_left << ").\n"
9950  << "The problem is that the left vertex of the current\n"
9951  << "shared boundary is not in the list of vertices of any\n"
9952  << "of the sub polylines that represent the boundary to\n"
9953  << "connect.\n\n"
9954  << "This is the left vertex of the current shared "
9955  "boundary\n"
9956  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9957  << shd_bnd_left_vertex[1] << ")\n\n"
9958  << "This is the list of vertices on the destination "
9959  << "boundary\n";
9960  for (unsigned p = 0; p < nsub_poly; p++)
9961  {
9962  error << "Subpolyline #(" << p << ")\n";
9963  poly_to_connect_pt = tmp_vector_subpolylines[p];
9964  const unsigned n_v = poly_to_connect_pt->nvertex();
9965  for (unsigned i = 0; i < n_v; i++)
9966  {
9967  Vector<double> cvertex =
9968  poly_to_connect_pt->vertex_coordinate(i);
9969  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
9970  << cvertex[1] << ")\n";
9971  }
9972  } // for (p < nsub_poly)
9973  throw OomphLibError(
9974  error.str(),
9975  "TriangleMesh::create_shared_polylines_connections()",
9976  OOMPH_EXCEPTION_LOCATION);
9977  } // if (!found_vertex_index)
9978 #endif
9979 
9980  // Create the connection, the left vertex of the current
9981  // shared boundary is connected with the vertex_index-th
9982  // vertex of sub_poly_to_connect-th subpolyline of the
9983  // destination boundary
9984  shd_poly_pt->connect_initial_vertex_to_polyline(
9985  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
9986 
9987  } // if (!connecting_to_an_overlaped_boundary)
9988  else
9989  {
9990  // We first look on the shared boundaries that overlap
9991  // the internal boundaries and the look for the
9992  // sub-polylines that are not marked as being overlaped
9993  // by shared boundaries
9994 
9995  // The vertex where to store the index to connect
9996  unsigned vertex_index = 0;
9997  // The subpoly number to connect
9998  unsigned sub_poly_to_connect = 0;
9999  // A flag to indicate if the connection was found
10000  bool found_vertex_index = false;
10001 
10002  // Get the shared boundaries id that are overlaping the
10003  // internal boundary
10004  Vector<unsigned> dst_shd_bnd_ids;
10005  get_shared_boundaries_overlapping_internal_boundary(
10006  uconnection_to_the_left, dst_shd_bnd_ids);
10007 
10008  // Get the number of shared polylines that were found to
10009  // overlap the internal boundary
10010  const unsigned n_shd_bnd_overlap_int_bnd =
10011  dst_shd_bnd_ids.size();
10012 
10013  // Loop over the shared boundaries that overlap the
10014  // internal boundary and look for the vertex to connect
10015  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10016  {
10017  // Get the shared polyline
10018  const unsigned new_connection_to_the_left =
10019  dst_shd_bnd_ids[ss];
10020 
10021  // Make sure that the destination polyline is not the
10022  // same as the current shared polyline
10023  if (bound_id != new_connection_to_the_left)
10024  {
10025  // Get the shared polyline that is overlaping the
10026  // internal boundary
10027  poly_to_connect_pt =
10028  boundary_polyline_pt(new_connection_to_the_left);
10029 
10030  if (poly_to_connect_pt != 0)
10031  {
10032  // Look for the vertex number in the destination
10033  // shared polyline
10034  found_vertex_index =
10035  get_connected_vertex_number_on_destination_polyline(
10036  poly_to_connect_pt,
10037  shd_bnd_left_vertex,
10038  vertex_index);
10039  } // if (poly_to_connect_pt != 0)
10040 
10041  // If we have found the vertex to connect then
10042  // break the loop
10043  if (found_vertex_index)
10044  {
10045  break;
10046  } // if (found_vertex_index)
10047 
10048  } // if (bound_id != new_connection_to_the_left)
10049 
10050  } // for (ss < n_shd_bnd_overlaping_int_bnd)
10051 
10052  // If we have not yet found the vertex then look for it
10053  // in the sub-polylines that are not overlaped by shared
10054  // boundaries
10055  if (!found_vertex_index)
10056  {
10057  // Look for the vertex number to connect on each of
10058  // the subpolyines
10059  for (unsigned isub = 0; isub < nsub_poly; isub++)
10060  {
10061  // Only work with those sub-polylines that are not
10062  // overlaped by shared boundaries
10063  if (!boundary_marked_as_shared_boundary(
10064  uconnection_to_the_left, isub))
10065  {
10066  // Assign the pointer to the sub-polyline
10067  poly_to_connect_pt = tmp_vector_subpolylines[isub];
10068  // Search for the vertex in the current sub-polyline
10069  found_vertex_index =
10070  get_connected_vertex_number_on_destination_polyline(
10071  poly_to_connect_pt,
10072  shd_bnd_left_vertex,
10073  vertex_index);
10074  // If we have found the vertex to connect then break the
10075  // loop
10076  if (found_vertex_index)
10077  {
10078  // But first save the subpoly number (chunk), that
10079  // will be used to perform the connection
10080  sub_poly_to_connect = isub;
10081  break;
10082  } // if (found_vertex_index)
10083 
10084  } // if (not overlaped by shared boundary)
10085 
10086  } // for (isub < nsub_poly)
10087 
10088  } // if (!found_vertex_index)
10089 
10090 #ifdef PARANOID
10091  // If we could not find the vertex index to connect then
10092  // we are in trouble
10093  if (!found_vertex_index)
10094  {
10095  std::stringstream error;
10096  error
10097  << "The current shared boundary (" << bound_id << ") was "
10098  << "marked to have a connection\nto the left with the "
10099  << "boundary (" << uconnection_to_the_left << ").\n"
10100  << "This last boundary is marked to be overlaped by "
10101  << "shared boundaries\n"
10102  << "The problem is that the left vertex of the current\n"
10103  << "shared boundary is not in the list of vertices of "
10104  << "the\nboundary to connect.\n\n"
10105  << "This is the left vertex of the current shared "
10106  << "boundary\n"
10107  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
10108  << shd_bnd_left_vertex[1] << ")\n\n"
10109  << "This is the list of vertices on the destination "
10110  << "boundary (only those subpolylines not marked as "
10111  << "overlaped by\nshared boundaries)\n";
10112  for (unsigned p = 0; p < nsub_poly; p++)
10113  {
10114  if (!boundary_marked_as_shared_boundary(
10115  uconnection_to_the_left, p))
10116  {
10117  error << "Subpolyline #(" << p << ")\n";
10118  poly_to_connect_pt = tmp_vector_subpolylines[p];
10119  const unsigned n_v = poly_to_connect_pt->nvertex();
10120  for (unsigned i = 0; i < n_v; i++)
10121  {
10122  Vector<double> cvertex =
10123  poly_to_connect_pt->vertex_coordinate(i);
10124  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10125  << cvertex[1] << ")\n";
10126  }
10127  } // Not marked as overlaped
10128  } // for (p < nsub_poly)
10129  error << "\nThis is the list of vertices of the shared "
10130  << "polylines that overlap\nthe internal "
10131  << "boundary\n";
10132  Vector<unsigned> dst_shd_bnd_ids;
10133  get_shared_boundaries_overlapping_internal_boundary(
10134  uconnection_to_the_left, dst_shd_bnd_ids);
10135  const unsigned n_shd_bnd_overlap_int_bnd =
10136  dst_shd_bnd_ids.size();
10137  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10138  {
10139  const unsigned new_connection_to_the_left =
10140  dst_shd_bnd_ids[ss];
10141  poly_to_connect_pt =
10142  boundary_polyline_pt(new_connection_to_the_left);
10143  if (poly_to_connect_pt != 0)
10144  {
10145  const unsigned shd_bnd_id_overlap =
10146  poly_to_connect_pt->boundary_id();
10147  error << "Shared boundary id(" << shd_bnd_id_overlap
10148  << ")\n";
10149  const unsigned n_v = poly_to_connect_pt->nvertex();
10150  for (unsigned i = 0; i < n_v; i++)
10151  {
10152  Vector<double> cvertex =
10153  poly_to_connect_pt->vertex_coordinate(i);
10154  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10155  << cvertex[1] << ")\n";
10156  }
10157  } // if (poly_to_connect_pt != 0)
10158  } // for (ss < n_shd_bnd_overlap_int_bnd)
10159 
10160  throw OomphLibError(
10161  error.str(),
10162  "TriangleMesh::create_shared_polylines_connections()",
10163  OOMPH_EXCEPTION_LOCATION);
10164  } // if (!found_vertex_index)
10165 #endif
10166 
10167  // Create the connection, the left vertex of the current
10168  // shared boundary is connected with the vertex_index-th
10169  // vertex of sub_poly_to_connect-th subpolyline of the
10170  // destination boundary
10171  shd_poly_pt->connect_initial_vertex_to_polyline(
10172  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10173 
10174  } // else if (!connecting_to_an_overlaped_boundary)
10175 
10176  } // else if (!connecting_to_an_split_boundary)
10177 
10178  } // if (connection_to_the_left != -1)
10179 
10180  // --------------------------------------------------------------
10181  // Connection to the right
10182  if (is_connected_to_the_right)
10183  {
10184  // Get the unsigned version of the bound id to connect to
10185  // the right
10186  const unsigned uconnection_to_the_right =
10187  shd_poly_pt->final_vertex_connected_bnd_id();
10188 
10189  // The pointer to the boundary to connect
10190  TriangleMeshPolyLine* poly_to_connect_pt = 0;
10191 
10192  // Flag to indicate we are trying to connect to an split
10193  // boundary
10194  bool connecting_to_an_split_boundary = false;
10195 
10196  // Flag to indicate we are trying to connecto to an internal
10197  // boundary that is overlaped by a shared boundary
10198  bool connecting_to_an_overlaped_boundary = false;
10199 
10200  // Check if the connection is with itself
10201  if (uconnection_to_the_right == bound_id)
10202  {
10203  // Set the pointer to the polyline to connect
10204  poly_to_connect_pt = shd_poly_pt;
10205  }
10206  else
10207  {
10208  // Get the initial shared boundary ids
10209  const unsigned initial_shd_bnd_id = initial_shared_boundary_id();
10210  // Check if the boundary to connect is a shared polyline
10211  if (uconnection_to_the_right >= initial_shd_bnd_id)
10212  {
10213  // Get the polyline pointer representing the destination
10214  // boundary
10215  poly_to_connect_pt =
10216  boundary_polyline_pt(uconnection_to_the_right);
10217  } // if (uconnection_to_the_left >= initial_shd_bnd_id)
10218  else
10219  {
10220  // If we are going to connect to an original boundary
10221  // verify if the boundary was splitted during the
10222  // distribution process to consider all the chunks
10223  // (sub-polylines) of the boundary
10224  if (boundary_was_splitted(uconnection_to_the_right))
10225  {
10226  connecting_to_an_split_boundary = true;
10227  } // if (boundary_was_splitted(uconnection_to_the_right))
10228 
10229  // If we are going to connect to an original boundary
10230  // verify if the boundary, or any of its chunks is
10231  // marked to be overlapped by a shared boundary, if that
10232  // is the case we first check for connections in the
10233  // shared boundary that overlaps the internal boundary,
10234  // or the chunks, and then check for connections in the
10235  // original boundary
10236  if (connecting_to_an_split_boundary)
10237  {
10238  // Get the number of chucks that represent the
10239  // destination boundary
10240  const unsigned n_sub_poly =
10241  nboundary_subpolylines(uconnection_to_the_right);
10242  // Now loop over the chunks of the destination
10243  // boundary and if any of them is marked to be
10244  // overlaped by a shared boundary then set the flag
10245  // and break the loop
10246  for (unsigned ii = 0; ii < n_sub_poly; ii++)
10247  {
10248  if (boundary_marked_as_shared_boundary(
10249  uconnection_to_the_right, ii))
10250  {
10251  // Mark the boundary as being overlaped by a
10252  // shared boundary
10253  connecting_to_an_overlaped_boundary = true;
10254  // Break, no need to look for more overlapings
10255  break;
10256  } // if (boundary_marked_as_shared_boundary(...))
10257  } // for (ii < n_sub_poly)
10258  } // if (connecting_to_an_split_boundary)
10259  else
10260  {
10261  // If not connecting to an split boundary then check
10262  // if the whole destination boundary is overlaped by
10263  // an internal boundary
10264  if (boundary_marked_as_shared_boundary(
10265  uconnection_to_the_right, 0))
10266  {
10267  // Mark the boundary as being overlaped by a shared
10268  // boundary
10269  connecting_to_an_overlaped_boundary = true;
10270  } // if (boundary_marked_as_shared_boundary(...))
10271  } // else if (connecting_to_an_split_boundary)
10272 
10273  // If we are connecting neither to an split boundary nor
10274  // an overlaped boundary then get the pointer to the
10275  // original boundary
10276  if (!(connecting_to_an_split_boundary ||
10277  connecting_to_an_overlaped_boundary))
10278  {
10279  // Get the polyline pointer representing the
10280  // destination boundary
10281  poly_to_connect_pt =
10282  boundary_polyline_pt(uconnection_to_the_right);
10283  } // else if (NOT split, NOT overlaped)
10284  } // else if (uconnection_to_the_right >= initial_shd_bnd_id)
10285 
10286  } // else if (uconnection_to_the_right == bound_id)
10287 
10288 #ifdef PARANOID
10289  // If we are not connecting to an original boundary
10290  // (connecting to the same shared boundary or to another
10291  // shared boundary) then the boundary should not be marked
10292  // as split
10293  if (!connecting_to_an_split_boundary)
10294  {
10295  if (boundary_was_splitted(uconnection_to_the_right))
10296  {
10297  std::stringstream error;
10298  error
10299  << "The current shared boundary (" << bound_id << ") was "
10300  << "marked to have a connection\nto the right with the "
10301  << "boundary (" << uconnection_to_the_right << ").\n"
10302  << "The problem is that the destination boundary (possibly\n"
10303  << "another shared boundary) is marked to be split\n"
10304  << "There should not be split shared boundaries\n\n";
10305  throw OomphLibError(
10306  error.str(),
10307  "TriangleMesh::create_shared_polylines_connections()",
10308  OOMPH_EXCEPTION_LOCATION);
10309  }
10310  } // if (!connecting_to_an_split_boundary)
10311 #endif
10312 
10313  // Now look for the vertex number on the destination
10314  // boundary(ies) -- in case that the boundary was split ---
10315 
10316  // Do not check for same orientation, that was previously
10317  // worked by interchanging the connections boundaries (if
10318  // necessary)
10319 
10320  // Get the right vertex in the shared boundary
10321  Vector<double> shd_bnd_right_vertex =
10322  shd_poly_pt->vertex_coordinate(n_vertex - 1);
10323 
10324  // If the boundary was not split then inmediately look for
10325  // the vertex index in the destination boundary
10326  if (!connecting_to_an_split_boundary)
10327  {
10328  // ... check if the boundary is marked to be overlaped by
10329  // a shared boundary
10330  if (!connecting_to_an_overlaped_boundary)
10331  {
10332  // If that is not the case then we can safely look for
10333  // the vertex number on the destination boundar
10334 
10335  unsigned vertex_index = 0;
10336  const bool found_vertex_index =
10337  get_connected_vertex_number_on_destination_polyline(
10338  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10339 
10340  // If we could not find the vertex index to connect then
10341  // we are in trouble
10342  if (!found_vertex_index)
10343  {
10344  std::stringstream error;
10345  error
10346  << "The current shared boundary (" << bound_id << ") was "
10347  << "marked to have a connection\nto the right with the "
10348  << "boundary (" << uconnection_to_the_right << ").\n"
10349  << "The problem is that the right vertex of the current\n"
10350  << "shared boundary is not in the list of vertices of the\n"
10351  << "boundary to connect.\n\n"
10352  << "This is the right vertex of the current shared "
10353  "boundary\n"
10354  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10355  << shd_bnd_right_vertex[1] << ")\n\n"
10356  << "This is the list of vertices on the destination "
10357  "boundary\n";
10358  const unsigned n_v = poly_to_connect_pt->nvertex();
10359  for (unsigned i = 0; i < n_v; i++)
10360  {
10361  Vector<double> cvertex =
10362  poly_to_connect_pt->vertex_coordinate(i);
10363  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10364  << cvertex[1] << ")\n";
10365  }
10366  throw OomphLibError(
10367  error.str(),
10368  "TriangleMesh::create_shared_polylines_connections()",
10369  OOMPH_EXCEPTION_LOCATION);
10370  } // if (!found_vertex_index)
10371 
10372  // Create the connection, the right vertex of the current
10373  // shared boundary is connected with the vertex_index-th
10374  // vertex on the destination boundary
10375  shd_poly_pt->connect_final_vertex_to_polyline(
10376  poly_to_connect_pt, vertex_index);
10377 
10378  } // if (!connecting_to_an_overlaped_boundary)
10379  else
10380  {
10381  // If the boundary is marked to be overlaped by a shared
10382  // boundary then get that shared boundary and look for
10383  // the connection in that boundary
10384 
10385  // The vertex where to store the index to connect
10386  unsigned vertex_index = 0;
10387  // A flag to indicate if the connection was found
10388  bool found_vertex_index = false;
10389 
10390  // Get the shared boundary id that is overlaping the
10391  // internal boundary
10392  Vector<unsigned> dst_shd_bnd_ids;
10393  get_shared_boundaries_overlapping_internal_boundary(
10394  uconnection_to_the_right, dst_shd_bnd_ids);
10395 
10396  // Get the number of shared polylines that were found to
10397  // overlap the internal boundary
10398  const unsigned n_shd_bnd_overlap_int_bnd =
10399  dst_shd_bnd_ids.size();
10400 
10401  // Loop over the shared boundaries that overlap the
10402  // internal boundary and look for the vertex to connect
10403  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10404  {
10405  // Get the shared polyline
10406  const unsigned new_connection_to_the_right =
10407  dst_shd_bnd_ids[ss];
10408 
10409  // Get the shared polyline that is overlaping the
10410  // internal boundary
10411  poly_to_connect_pt =
10412  boundary_polyline_pt(new_connection_to_the_right);
10413 
10414  if (poly_to_connect_pt != 0)
10415  {
10416  // Look for the vertex number in the destination
10417  // shared polyline
10418  found_vertex_index =
10419  get_connected_vertex_number_on_destination_polyline(
10420  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10421  } // if (poly_to_connect_pt!=0)
10422 
10423  // If we have found the vertex to connect then
10424  // break the loop
10425  if (found_vertex_index)
10426  {
10427  break;
10428  } // if (found_vertex_index)
10429 
10430  } // for (ss < n_shd_bnd_overlaping_int_bnd)
10431 
10432 #ifdef PARANOID
10433  // If we could not find the vertex index to connect then
10434  // we are in trouble
10435  if (!found_vertex_index)
10436  {
10437  std::stringstream error;
10438  error
10439  << "The current shared boundary (" << bound_id << ") was "
10440  << "marked to have a connection\nto the right with the "
10441  << "boundary (" << uconnection_to_the_right << ").\n"
10442  << "This last boundary is marked to be overlaped by "
10443  << "shared boundaries\n"
10444  << "The problem is that the right vertex of the current\n"
10445  << "shared boundary is not in the list of vertices of the\n"
10446  << "boundary to connect.\n\n"
10447  << "This is the right vertex of the current shared "
10448  "boundary\n"
10449  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10450  << shd_bnd_right_vertex[1] << ")\n\n"
10451  << "This is the list of vertices on the destination "
10452  << "boundary\n";
10453  Vector<unsigned> dst_shd_bnd_ids;
10454  get_shared_boundaries_overlapping_internal_boundary(
10455  uconnection_to_the_right, dst_shd_bnd_ids);
10456  const unsigned n_shd_bnd_overlap_int_bnd =
10457  dst_shd_bnd_ids.size();
10458  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10459  {
10460  const unsigned new_connection_to_the_right =
10461  dst_shd_bnd_ids[ss];
10462  poly_to_connect_pt =
10463  boundary_polyline_pt(new_connection_to_the_right);
10464  if (poly_to_connect_pt != 0)
10465  {
10466  const unsigned shd_bnd_id_overlap =
10467  poly_to_connect_pt->boundary_id();
10468  error << "Shared boundary id(" << shd_bnd_id_overlap
10469  << ")\n";
10470  const unsigned n_v = poly_to_connect_pt->nvertex();
10471  for (unsigned i = 0; i < n_v; i++)
10472  {
10473  Vector<double> cvertex =
10474  poly_to_connect_pt->vertex_coordinate(i);
10475  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10476  << cvertex[1] << ")\n";
10477  }
10478  } // if (poly_to_connect_pt != 0)
10479  } // for (ss < n_shd_bnd_overlap_int_bnd)
10480 
10481  throw OomphLibError(
10482  error.str(),
10483  "TriangleMesh::create_shared_polylines_connections()",
10484  OOMPH_EXCEPTION_LOCATION);
10485 
10486  } // if (!found_vertex_index)
10487 #endif
10488 
10489  // Create the connection, the right vertex of the
10490  // current shared boundary is connected with the
10491  // vertex_index-th vertex on the destination boundary
10492  shd_poly_pt->connect_final_vertex_to_polyline(
10493  poly_to_connect_pt, vertex_index);
10494 
10495  } // else if (!connecting_to_an_overlaped_boundary)
10496 
10497  } // if (!connecting_to_an_split_boundary)
10498  else
10499  {
10500  // If the boundary was split then we need to look for the
10501  // vertex in the sub-polylines
10502 
10503  // Get the sub-polylines vector
10504  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
10505  boundary_subpolylines(uconnection_to_the_right);
10506 
10507  // Get the number of sub-polylines
10508  const unsigned nsub_poly = tmp_vector_subpolylines.size();
10509 #ifdef PARANOID
10510  if (nsub_poly <= 1)
10511  {
10512  std::ostringstream error_message;
10513  error_message
10514  << "The boundary (" << uconnection_to_the_right << ") was "
10515  << "marked to be splitted but\n"
10516  << "there are only (" << nsub_poly << ") polylines to "
10517  << "represent it.\n";
10518  throw OomphLibError(
10519  error_message.str(),
10520  "TriangleMesh::create_shared_polylines_connections()",
10521  OOMPH_EXCEPTION_LOCATION);
10522  } // if (nsub_poly <= 1)
10523 #endif
10524 
10525  // We need to check if the boundary is marked to be
10526  // overlaped by an internal boundary, if that is the case
10527  // we need to check for each indivual subpolyline, and for
10528  // those overlaped by a shared polyline look for the
10529  // vertex in the shared polyline representation instead of
10530  // the original subpolyline
10531 
10532  // ... check if the boundary is marked to be overlaped by
10533  // a shared boundary
10534  if (!connecting_to_an_overlaped_boundary)
10535  {
10536  // We can work without checking the subpolylines
10537  // individually
10538 
10539  // The vertex where to store the index to connect
10540  unsigned vertex_index = 0;
10541  // The subpoly number to connect
10542  unsigned sub_poly_to_connect = 0;
10543  // A flag to indicate if the connection was found
10544  bool found_vertex_index = false;
10545 
10546  // Look for the vertex number to connect on each of the
10547  // subpolyines
10548  for (unsigned isub = 0; isub < nsub_poly; isub++)
10549  {
10550  // Assign the pointer to the sub-polyline
10551  poly_to_connect_pt = tmp_vector_subpolylines[isub];
10552  // Search for the vertex in the current sub-polyline
10553  found_vertex_index =
10554  get_connected_vertex_number_on_destination_polyline(
10555  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10556  // If we have found the vertex to connect then break the
10557  // loop
10558  if (found_vertex_index)
10559  {
10560  // But first save the subpoly number (chunk), that
10561  // will be used to perform the connection
10562  sub_poly_to_connect = isub;
10563  break;
10564  } // if (found_vertex_index)
10565  } // for (isub < nsub_poly)
10566 
10567 #ifdef PARANOID
10568  // If we could not find the vertex index to connect then
10569  // we are in trouble
10570  if (!found_vertex_index)
10571  {
10572  std::stringstream error;
10573  error
10574  << "The current shared boundary (" << bound_id << ") was "
10575  << "marked to have a connection\nto the right with the "
10576  << "boundary (" << uconnection_to_the_right << ").\n"
10577  << "The problem is that the right vertex of the current\n"
10578  << "shared boundary is not in the list of vertices of any\n"
10579  << "of the sub polylines that represent the boundary to\n"
10580  << "connect.\n\n"
10581  << "This is the right vertex of the current shared "
10582  "boundary\n"
10583  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10584  << shd_bnd_right_vertex[1] << ")\n\n"
10585  << "This is the list of vertices on the destination "
10586  << "boundary\n";
10587  for (unsigned p = 0; p < nsub_poly; p++)
10588  {
10589  error << "Subpolyline #(" << p << ")\n";
10590  poly_to_connect_pt = tmp_vector_subpolylines[p];
10591  const unsigned n_v = poly_to_connect_pt->nvertex();
10592  for (unsigned i = 0; i < n_v; i++)
10593  {
10594  Vector<double> cvertex =
10595  poly_to_connect_pt->vertex_coordinate(i);
10596  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10597  << cvertex[1] << ")\n";
10598  }
10599  } // for (p < nsub_poly)
10600  throw OomphLibError(
10601  error.str(),
10602  "TriangleMesh::create_shared_polylines_connections()",
10603  OOMPH_EXCEPTION_LOCATION);
10604  } // if (!found_vertex_index)
10605 #endif
10606 
10607  // Create the connection, the right vertex of the current
10608  // shared boundary is connected with the vertex_index-th
10609  // vertex of sub_poly_to_connect-th subpolyline of the
10610  // destination boundary
10611  shd_poly_pt->connect_final_vertex_to_polyline(
10612  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10613 
10614  } // if (!connecting_to_an_overlaped_boundary)
10615  else
10616  {
10617  // We first look on the shared boundaries that overlap
10618  // the internal boundaries and the look for the
10619  // sub-polylines that are not marked as being overlaped
10620  // by shared boundaries
10621 
10622  // The vertex where to store the index to connect
10623  unsigned vertex_index = 0;
10624  // The subpoly number to connect
10625  unsigned sub_poly_to_connect = 0;
10626  // A flag to indicate if the connection was found
10627  bool found_vertex_index = false;
10628 
10629  // Get the shared boundaries id that are overlaping the
10630  // internal boundary
10631  Vector<unsigned> dst_shd_bnd_ids;
10632  get_shared_boundaries_overlapping_internal_boundary(
10633  uconnection_to_the_right, dst_shd_bnd_ids);
10634 
10635  // Get the number of shared polylines that were found to
10636  // overlap the internal boundary
10637  const unsigned n_shd_bnd_overlap_int_bnd =
10638  dst_shd_bnd_ids.size();
10639 
10640  // Loop over the shared boundaries that overlap the
10641  // internal boundary and look for the vertex to connect
10642  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10643  {
10644  // Get the shared polyline
10645  const unsigned new_connection_to_the_right =
10646  dst_shd_bnd_ids[ss];
10647 
10648  // Make sure that the destination polyline is not the
10649  // same as the current shared polyline
10650  if (bound_id != new_connection_to_the_right)
10651  {
10652  // Get the shared polyline that is overlaping the
10653  // internal boundary
10654  poly_to_connect_pt =
10655  boundary_polyline_pt(new_connection_to_the_right);
10656 
10657  if (poly_to_connect_pt != 0)
10658  {
10659  // Look for the vertex number in the destination
10660  // shared polyline
10661  found_vertex_index =
10662  get_connected_vertex_number_on_destination_polyline(
10663  poly_to_connect_pt,
10664  shd_bnd_right_vertex,
10665  vertex_index);
10666  } // if (poly_to_connect_pt != 0)
10667 
10668  // If we have found the vertex to connect then
10669  // break the loop
10670  if (found_vertex_index)
10671  {
10672  break;
10673  } // if (found_vertex_index)
10674 
10675  } // if (bound_id != new_connection_to_the_right)
10676 
10677  } // for (ss < n_shd_bnd_overlaping_int_bnd)
10678 
10679  // If we have not yet found the vertex then look for it
10680  // in the sub-polylines that are not overlaped by shared
10681  // boundaries
10682  if (!found_vertex_index)
10683  {
10684  // Look for the vertex number to connect on each of
10685  // the subpolyines
10686  for (unsigned isub = 0; isub < nsub_poly; isub++)
10687  {
10688  // Only work with those sub-polylines that are not
10689  // overlaped by shared boundaries
10690  if (!boundary_marked_as_shared_boundary(
10691  uconnection_to_the_right, isub))
10692  {
10693  // Assign the pointer to the sub-polyline
10694  poly_to_connect_pt = tmp_vector_subpolylines[isub];
10695  // Search for the vertex in the current sub-polyline
10696  found_vertex_index =
10697  get_connected_vertex_number_on_destination_polyline(
10698  poly_to_connect_pt,
10699  shd_bnd_right_vertex,
10700  vertex_index);
10701  // If we have found the vertex to connect then break the
10702  // loop
10703  if (found_vertex_index)
10704  {
10705  // But first save the subpoly number (chunk), that
10706  // will be used to perform the connection
10707  sub_poly_to_connect = isub;
10708  break;
10709  } // if (found_vertex_index)
10710 
10711  } // if (not overlaped by shared boundary)
10712 
10713  } // for (isub < nsub_poly)
10714 
10715  } // if (!found_vertex_index)
10716 
10717 #ifdef PARANOID
10718  // If we could not find the vertex index to connect then
10719  // we are in trouble
10720  if (!found_vertex_index)
10721  {
10722  std::stringstream error;
10723  error
10724  << "The current shared boundary (" << bound_id << ") was "
10725  << "marked to have a connection\nto the right with the "
10726  << "boundary (" << uconnection_to_the_right << ").\n"
10727  << "This last boundary is marked to be overlaped by "
10728  << "shared boundaries\n"
10729  << "The problem is that the right vertex of the current\n"
10730  << "shared boundary is not in the list of vertices of "
10731  << "the\nboundary to connect.\n\n"
10732  << "This is the right vertex of the current shared "
10733  << "boundary\n"
10734  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10735  << shd_bnd_right_vertex[1] << ")\n\n"
10736  << "This is the list of vertices on the destination "
10737  << "boundary (only those subpolylines not marked as "
10738  << "overlaped by\nshared boundaries)\n";
10739  for (unsigned p = 0; p < nsub_poly; p++)
10740  {
10741  if (!boundary_marked_as_shared_boundary(
10742  uconnection_to_the_right, p))
10743  {
10744  error << "Subpolyline #(" << p << ")\n";
10745  poly_to_connect_pt = tmp_vector_subpolylines[p];
10746  const unsigned n_v = poly_to_connect_pt->nvertex();
10747  for (unsigned i = 0; i < n_v; i++)
10748  {
10749  Vector<double> cvertex =
10750  poly_to_connect_pt->vertex_coordinate(i);
10751  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10752  << cvertex[1] << ")\n";
10753  }
10754  } // Not marked as overlaped
10755  } // for (p < nsub_poly)
10756  error << "\nThis is the list of vertices of the shared "
10757  << "polylines that overlap\nthe internal "
10758  << "boundary\n";
10759  Vector<unsigned> dst_shd_bnd_ids;
10760  get_shared_boundaries_overlapping_internal_boundary(
10761  uconnection_to_the_right, dst_shd_bnd_ids);
10762  const unsigned n_shd_bnd_overlap_int_bnd =
10763  dst_shd_bnd_ids.size();
10764  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10765  {
10766  const unsigned new_connection_to_the_right =
10767  dst_shd_bnd_ids[ss];
10768  poly_to_connect_pt =
10769  boundary_polyline_pt(new_connection_to_the_right);
10770  if (poly_to_connect_pt != 0)
10771  {
10772  const unsigned shd_bnd_id_overlap =
10773  poly_to_connect_pt->boundary_id();
10774  error << "Shared boundary id(" << shd_bnd_id_overlap
10775  << ")\n";
10776  const unsigned n_v = poly_to_connect_pt->nvertex();
10777  for (unsigned i = 0; i < n_v; i++)
10778  {
10779  Vector<double> cvertex =
10780  poly_to_connect_pt->vertex_coordinate(i);
10781  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10782  << cvertex[1] << ")\n";
10783  }
10784  } // if (poly_to_connect_pt != 0)
10785  } // for (ss < n_shd_bnd_overlap_int_bnd)
10786 
10787  throw OomphLibError(
10788  error.str(),
10789  "TriangleMesh::create_shared_polylines_connections()",
10790  OOMPH_EXCEPTION_LOCATION);
10791  } // if (!found_vertex_index)
10792 #endif
10793 
10794  // Create the connection, the left vertex of the current
10795  // shared boundary is connected with the vertex_index-th
10796  // vertex of sub_poly_to_connect-th subpolyline of the
10797  // destination boundary
10798  shd_poly_pt->connect_final_vertex_to_polyline(
10799  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10800 
10801  } // else if (!connecting_to_an_overlaped_boundary)
10802 
10803  } // else if (!connecting_to_an_split_boundary)
10804 
10805  } // if (connection_to_the_right != -1)
10806 
10807  } // if (connection_to_the_left != -1 || connection_to_the_right != -1)
10808 
10809  } // for (ipoly < npoly)
10810 
10811  } // for (icurve < ncurves)
10812  }
10813 
10814  //=======================================================================
10815  // Compute the holes left by the halo elements, those adjacent
10816  // to the shared boundaries
10817  //=======================================================================
10818  template<class ELEMENT>
10820  Vector<Vector<double>>& output_holes_coordinates)
10821  {
10822  // Storage for number of processors and current processor
10823  const unsigned n_proc = this->communicator_pt()->nproc();
10824  const unsigned my_rank = this->communicator_pt()->my_rank();
10825 
10826  // Mark those done elements, so we do not repeat any coordinate left
10827  // by repeated halo elements
10828  std::map<FiniteElement*, bool> done_ele;
10829 
10830  // Loop over the processors and get the shared boundaries ids that
10831  // the current processor has with the other processors
10832  for (unsigned iproc = 0; iproc < n_proc; iproc++)
10833  {
10834  // There are shared boundaries only with the other processors
10835  if (iproc != my_rank)
10836  {
10837  // Get the number of shared boundaries with the iproc
10838  const unsigned n_shd_bnd_iproc = nshared_boundaries(my_rank, iproc);
10839 
10840 #ifdef PARANOID
10841  // Get the number of shared boundaries with the iproc, but
10842  // reversing the indexes
10843  const unsigned n_shd_bnd_iproc_rev = nshared_boundaries(iproc, my_rank);
10844  if (n_shd_bnd_iproc != n_shd_bnd_iproc_rev)
10845  {
10846  std::ostringstream error_stream;
10847  error_stream
10848  << "The number of shared boundaries of processor (" << my_rank
10849  << ") with processor(" << iproc << "): (" << n_shd_bnd_iproc
10850  << ")\n"
10851  << "is different from the number of shared boundaries of "
10852  << "processor (" << iproc << ")\nwith processor (" << my_rank
10853  << "): (" << n_shd_bnd_iproc << ")\n\n";
10854  throw OomphLibError(error_stream.str(),
10855  OOMPH_CURRENT_FUNCTION,
10856  OOMPH_EXCEPTION_LOCATION);
10857 
10858  } // if (n_shd_bnd_iproc != n_shd_bnd_iproc_rev)
10859 #endif
10860 
10861  // Loop over the shared boundaries ids
10862  for (unsigned i = 0; i < n_shd_bnd_iproc; i++)
10863  {
10864  // Get the shared boundary id
10865  const unsigned shd_bnd_id = shared_boundaries_ids(my_rank, iproc, i);
10866 
10867  // Get the number of shared boundary elements
10868  const unsigned n_shd_bnd_ele = nshared_boundary_element(shd_bnd_id);
10869 
10870  // Loop over the shared boundary elements
10871  for (unsigned e = 0; e < n_shd_bnd_ele; e++)
10872  {
10873  // Get the shared boundary element
10874  FiniteElement* ele_pt = shared_boundary_element_pt(shd_bnd_id, e);
10875 
10876  // Only work with halo elements
10877  if (ele_pt->is_halo())
10878  {
10879  // If the element has not been visited
10880  if (!done_ele[ele_pt])
10881  {
10882  // Get the number of nodes
10883  const unsigned n_nodes = ele_pt->nnode();
10884 
10885  // Compute the centroid of the element
10886  Vector<double> element_centroid(2, 0.0);
10887  // Loop over the nodes
10888  for (unsigned k = 0; k < n_nodes; k++)
10889  {
10890  Node* tmp_node_pt = ele_pt->node_pt(k);
10891  // Loop over the dimension
10892  for (unsigned d = 0; d < 2; d++)
10893  {
10894  element_centroid[d] += tmp_node_pt->x(d);
10895  } // for (d < 2)
10896  } // for (k < n_nodes)
10897 
10898  // Average the data
10899  for (unsigned d = 0; d < 2; d++)
10900  {
10901  element_centroid[d] = element_centroid[d] / (double)n_nodes;
10902  } // for (d < 2)
10903 
10904  // Add the centroid to the output holes
10905  output_holes_coordinates.push_back(element_centroid);
10906 
10907  } // if (!done_ele[ele_pt])
10908 
10909  } // if (ele_pt->is_halo())
10910 
10911  } // for1 (e < n_shd_bnd_ele)
10912 
10913  } // for (i < n_shd_bnd_iproc)
10914 
10915  } // if (iproc != my_rank)
10916 
10917  } // for (iproc < n_proc)
10918  }
10919 
10920  //======================================================================
10921  // Keeps those vertices that define a hole, those that are
10922  // inside closed internal boundaries in the new polygons that define
10923  // the domain. Delete those outside/inside the outer polygons (this
10924  // is required since Triangle can not deal with vertices that define
10925  // holes outside the new outer polygons of the domain)
10926  //======================================================================
10927  template<class ELEMENT>
10929  Vector<TriangleMeshPolygon*>& polygons_pt,
10930  Vector<Vector<double>>& output_holes_coordinates)
10931  {
10932  // General strategy
10933 
10934  // 1) Identify the inner closed boundaries
10935 
10936  // 2) Separate the vertices in three groups
10937 
10938  // --- 2.1) The vertices inside the inner closed boundaries, these
10939  // are not deleted because they define holes
10940 
10941  // --- 2.2) The vertices outside the outer boundaries, these are
10942  // deleted only if they are outside the convex hull defined
10943  // by all the polygons
10944 
10945  // --- 2.3) Any other vertex is deleted
10946 
10947  // Get the number of input holes
10948  const unsigned n_input_holes = output_holes_coordinates.size();
10949 
10950  // Only do something if there are holes
10951  if (n_input_holes == 0)
10952  {
10953  return;
10954  }
10955 
10956  // Get the number of input polygons
10957  const unsigned n_polygons = polygons_pt.size();
10958 
10959  // Store the vertices of all the input polygons
10960  // vertices_polygons[x][ ][ ]: Polygon number
10961  // vertices_polygons[ ][x][ ]: Vertex number
10962  // vertices_polygons[ ][ ][x]: Vertex coordinate
10963  Vector<Vector<Vector<double>>> vertices_polygons(n_polygons);
10964 
10965  // Loop over all the polygons and get the vertices
10966  for (unsigned p = 0; p < n_polygons; p++)
10967  {
10968  // Get the number of polylines associated to the polygon
10969  const unsigned n_polylines = polygons_pt[p]->npolyline();
10970  // Loop over the polylines and get the vertices
10971  for (unsigned pp = 0; pp < n_polylines; pp++)
10972  {
10973  // Get the polyline
10974  const TriangleMeshPolyLine* tmp_poly_pt =
10975  polygons_pt[p]->polyline_pt(pp);
10976  // Get the number of vertices in the polyline
10977  const unsigned n_vertices = tmp_poly_pt->nvertex();
10978  // Loop over the vertices but only add (n_vertices-1) vertices,
10979  // the last vertex of polyline (pp) is the first vertex of
10980  // polyline (pp+1)
10981  for (unsigned v = 0; v < n_vertices - 1; v++)
10982  {
10983  // Get the current vertex
10984  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
10985  vertices_polygons[p].push_back(current_vertex);
10986  } // for (v < nvertex)
10987  } // for (p < nouter_polylines)
10988  } // for (p < n_polygons)
10989 
10990  // -------------------------------------------------------------------
10991  // 1) Identify the inner closed boundaries
10992  // -------------------------------------------------------------------
10993 
10994  // A container that indicates if a given polygon should be
10995  // considered as an outer or as an inner polygon. By default all the
10996  // polygons are considered as outer polygons
10997  std::vector<bool> is_outer_polygon(n_polygons, true);
10998 
10999  // We only check for innner polygons if there are more than one
11000  // polygon
11001  if (n_polygons > 1)
11002  {
11003  // Propose an inner polygon, if one of the middle points of its
11004  // edges lies inside any other polygon then the proposed inner
11005  // polygon is marked as an internal polygon
11006 
11007  // Pre-compute the middle points of the edges in the polygons
11008  Vector<Vector<Vector<double>>> polygon_edge_middle_vertex(n_polygons);
11009 
11010  for (unsigned p = 0; p < n_polygons; p++)
11011  {
11012  // Temporary store the vertices of the proposed inner polygon
11013  Vector<Vector<double>> tmp_inner_polygon = vertices_polygons[p];
11014 
11015  // Get the number of vertices in the current proposed inner polygon
11016  const unsigned n_vertices = tmp_inner_polygon.size();
11017 
11018  // Resize with the number of edges in the polygon
11019  polygon_edge_middle_vertex[p].resize(n_vertices - 1);
11020 
11021  // Loop over the vertices and compute the middle point in the edge
11022  // that joins each pair of contiguous vertices
11023  for (unsigned e = 0; e < n_vertices - 1; e++)
11024  {
11025  // The dimension
11026  const unsigned dim = 2;
11027  polygon_edge_middle_vertex[p][e].resize(dim);
11028  for (unsigned d = 0; d < dim; d++)
11029  {
11030  polygon_edge_middle_vertex[p][e][d] =
11031  (tmp_inner_polygon[e][d] + tmp_inner_polygon[e + 1][d]) / 2.0;
11032  } // for (d < 2)
11033 
11034  } // for (e < n_vertices - 1)
11035 
11036  } // for (p < n_polygons)
11037 
11038  // Loop over the polygons and for every loop propose a different
11039  // inner polygon
11040  for (unsigned idx_inner = 0; idx_inner < n_polygons; idx_inner++)
11041  {
11042  // Flag to indicate that ONE of the middle edge vertices of the
11043  // proposed inner polygon is inside another polygon, this will
11044  // set the proposed inner polygon as an actual inner polygon
11045  bool is_inner_polygon = false;
11046 
11047  // Loop over all the polygons, except the proposed one and check
11048  // if all the middle edges of its edges are inside any other
11049  // polygon
11050  for (unsigned i = 0; i < n_polygons; i++)
11051  {
11052  // Do not check with the polygon itself
11053  if (i != idx_inner)
11054  {
11055  // Get the number of edges of the proposed inner polygon
11056  const unsigned n_edges =
11057  polygon_edge_middle_vertex[idx_inner].size();
11058  // Loop over the middle points in the edges of the current
11059  // proposed inner polygon
11060  for (unsigned e = 0; e < n_edges; e++)
11061  {
11062  // Get the vertex in the current proposed inner polygon
11063  Vector<double> current_vertex =
11064  polygon_edge_middle_vertex[idx_inner][e];
11065  // Check if the current vertex is inside the current i-th
11066  // polygon
11067  const bool is_point_inside = is_point_inside_polygon_helper(
11068  vertices_polygons[i], current_vertex);
11069 
11070  // If one point is inside then the polygon is inside the
11071  // i-th polygon
11072  if (is_point_inside)
11073  {
11074  // The polygon is an inner polygon
11075  is_inner_polygon = true;
11076  // Break the loop
11077  break;
11078  } // if (is_point_inside)
11079 
11080  } // for (e < n_edges)
11081 
11082  } // if (i != idx_inner)
11083 
11084  // Are all the vertices of the current proposed inner polygon
11085  // inside the i-th polygon
11086  if (is_inner_polygon)
11087  {
11088  // The current proposed inner polygon is an actual inner
11089  // polygon, and is inside the i-th polygon
11090  break;
11091  }
11092 
11093  } // for (i < n_polygons)
11094 
11095  // Is the current proposed inner polygon an actual inner polygon
11096  if (is_inner_polygon)
11097  {
11098  // The current proposed inner polygon is a real inner polygon
11099  is_outer_polygon[idx_inner] = false;
11100  }
11101  else
11102  {
11103  // The current proposed inner polygon IS NOT a real inner
11104  // polygon
11105  is_outer_polygon[idx_inner] = true;
11106  }
11107 
11108  } // for (idx_outer < npolygons)
11109 
11110  } // if (n_polygons > 1)
11111 
11112  // Count the number of outer closed boundaries and inner closed
11113  // boundaries
11114  unsigned n_outer_polygons = 0;
11115  unsigned n_inner_polygons = 0;
11116  // Also get the indexes of the inner polygons
11117  Vector<unsigned> index_inner_polygon;
11118  // Loop over the polygons
11119  for (unsigned i = 0; i < n_polygons; i++)
11120  {
11121  if (is_outer_polygon[i])
11122  {
11123  // Increase the counter for outer polygons
11124  n_outer_polygons++;
11125  }
11126  else
11127  {
11128  // Increase the counter for inner polygons
11129  n_inner_polygons++;
11130  // Store the index of the inner polygon
11131  index_inner_polygon.push_back(i);
11132  }
11133  } // for (i < n_polygons)
11134 
11135  // -------------------------------------------------------------------
11136  // 2) Separate the vertices in three groups
11137 
11138  // --- 2.1) The vertices inside the inner closed boundaries, these are
11139  // not deleted because they define holes
11140 
11141  // --- 2.2) The vertices outside the outer boundaries, these are
11142  // deleted only if they are outside the convex hull defined
11143  // by all the polygons
11144 
11145  // --- 2.3) Any other vertex is deleted
11146  // -------------------------------------------------------------------
11147 
11148  // Keep track of the vertices inside the inner closed boundaries (by
11149  // default all vertices not inside the inner polygons)
11150  std::vector<bool> is_inside_an_inner_polygon(n_input_holes, false);
11151 
11152  // Keep track of the vertices outside the outer closed boundaries
11153  // (by default all the vertices are outside the outer polygons)
11154  std::vector<bool> is_outside_the_outer_polygons(n_input_holes, true);
11155 
11156  // Keep track of the vertices inside the convex hull (by default
11157  // all the vertices are not inside the convex hull)
11158  std::vector<bool> is_inside_the_convex_hull(n_input_holes, false);
11159 
11160  // Mark the vertices inside the inner closed boundaries
11161  Vector<Vector<Vector<double>>> vertex_inside_inner_polygon(
11162  n_inner_polygons);
11163 
11164  // -------------------------------------------------------------------
11165  // Loop over the inner polygons and find all the vertices inside
11166  // each one
11167  for (unsigned i = 0; i < n_inner_polygons; i++)
11168  {
11169  // Get the vertex of the inner polygon
11170  const unsigned ii = index_inner_polygon[i];
11171  // Loop over the vertices defining holes, mark and store those
11172  // inside the inner polygon
11173  for (unsigned h = 0; h < n_input_holes; h++)
11174  {
11175  // Check if the vertex has not been already marked as inside
11176  // another polygon
11177  if (!is_inside_an_inner_polygon[h])
11178  {
11179  // Check if the hole is inside the current inner polygon
11180  const bool is_inside_polygon = is_point_inside_polygon_helper(
11181  vertices_polygons[ii], output_holes_coordinates[h]);
11182 
11183  // If the vertex is inside the current inner polygon then mark
11184  // it and associate the vertices to the current inner polygon
11185  if (is_inside_polygon)
11186  {
11187  // Set as inside an inner polygon
11188  is_inside_an_inner_polygon[h] = true;
11189  // Associate the vertex to the current inner polygon
11190  vertex_inside_inner_polygon[i].push_back(
11191  output_holes_coordinates[h]);
11192  } // if (is_inside_polygon)
11193 
11194  } // if (!is_inside_an_inner_polygon[h])
11195 
11196  } // for (h < n_input_holes)
11197 
11198  } // for (i < n_polygons)
11199 
11200  // -------------------------------------------------------------------
11201  // Loop over the vertices defining holes and mark those as outside the
11202  // outer polygons
11203  for (unsigned h = 0; h < n_input_holes; h++)
11204  {
11205  // Check if the vertex has not been already marked as inside
11206  // another polygon
11207  if (!is_inside_an_inner_polygon[h])
11208  {
11209  // Loop over the polygons and check if the vertex is outside ALL
11210  // the outer polygons
11211  for (unsigned i = 0; i < n_polygons; i++)
11212  {
11213  // Only work with outer polygons
11214  if (is_outer_polygon[i])
11215  {
11216  // Check if the hole is inside the current outer polygon
11217  const bool is_inside_polygon = is_point_inside_polygon_helper(
11218  vertices_polygons[i], output_holes_coordinates[h]);
11219 
11220  // If the vertex is inside the current outer polygon then
11221  // mark it and break the loop (it is not outside ALL the
11222  // polygons)
11223  if (is_inside_polygon)
11224  {
11225  // Set as inside an outer polygon
11226  is_outside_the_outer_polygons[h] = false;
11227  // Break the loop
11228  break;
11229  } // if (is_inside_polygon)
11230 
11231  } // if (is_outer_polygon[i])
11232 
11233  } // for (i < n_polygons)
11234 
11235  } // if (!is_inside_an_inner_polygon[h])
11236  else
11237  {
11238  // If the vertex is inside an inner polygon then it is inside an
11239  // outer polygon
11240  is_outside_the_outer_polygons[h] = false;
11241  } // else if (!is_inside_an_inner_polygon[h])
11242 
11243  } // for (h < n_input_holes)
11244 
11245  // -------------------------------------------------------------------
11246  // Compute the convex hull Create the data structure
11247  std::vector<Point> input_vertices_convex_hull;
11248  // Copy ALL the vertices of the polygons
11249  // Loop over the polygons
11250  for (unsigned p = 0; p < n_polygons; p++)
11251  {
11252  // Get the number of vertices
11253  const unsigned n_vertices = vertices_polygons[p].size();
11254  // Loop over the vertices in the polygon
11255  for (unsigned v = 0; v < n_vertices; v++)
11256  {
11257  // Create a new "Point" to store in the input vertices
11258  Point point;
11259  // Assign the values to the "Point"
11260  point.x = vertices_polygons[p][v][0];
11261  point.y = vertices_polygons[p][v][1];
11262  // Add the "Point" to the input vertices
11263  input_vertices_convex_hull.push_back(point);
11264  } // for (v < n_vertices)
11265  } // for (p < n_polygons)
11266 
11267  // Compute the convex hull
11268  std::vector<Point> output_vertices_convex_hull =
11269  convex_hull(input_vertices_convex_hull);
11270 
11271  // Get the number of vertices in the convex hull
11272  const unsigned n_vertices_convex_hull = output_vertices_convex_hull.size();
11273 
11274  // Copy the output to the used data structures
11275  Vector<Vector<double>> vertices_convex_hull(n_vertices_convex_hull);
11276  for (unsigned i = 0; i < n_vertices_convex_hull; i++)
11277  {
11278  // Resize the data structure
11279  vertices_convex_hull[i].resize(2);
11280  // Copy the data
11281  vertices_convex_hull[i][0] = output_vertices_convex_hull[i].x;
11282  vertices_convex_hull[i][1] = output_vertices_convex_hull[i].y;
11283  } // for (i < n_vertices_convex_hull)
11284 
11285  // Loop over the vertices defining holes, work only with those
11286  // outside ALL the outer boundaries and mark those inside the convex
11287  // hull
11288  for (unsigned h = 0; h < n_input_holes; h++)
11289  {
11290  // Only work with those outside ALL the outer polygons
11291  if (is_outside_the_outer_polygons[h])
11292  {
11293  // Check if the hole is inside the convex hull
11294  const bool is_inside_convex_hull = is_point_inside_polygon_helper(
11295  vertices_convex_hull, output_holes_coordinates[h]);
11296 
11297  // If the vertex is inside the convex hull then mark it
11298  if (is_inside_convex_hull)
11299  {
11300  // Set as inside the convex hull
11301  is_inside_the_convex_hull[h] = true;
11302  } // if (is_inside_convex_hull)
11303 
11304  } // if (is_outside_the_outer_polygons[h])
11305  else
11306  {
11307  // Any vertex inside any outer polygon is inside the convex hull
11308  is_inside_the_convex_hull[h] = true;
11309  } // else if (is_outside_the_outer_polygons[h])
11310 
11311  } // for (h < n_input_holes)
11312 
11313  // Store the output holes, only (those inside an inner polygon) OR
11314  // (those outside ALL the polygons AND inside the convex hull)
11315  Vector<Vector<double>> hole_kept;
11316  for (unsigned h = 0; h < n_input_holes; h++)
11317  {
11318  // Check if the hole should be kept
11319  if ((is_inside_an_inner_polygon[h]) ||
11320  (is_outside_the_outer_polygons[h] && is_inside_the_convex_hull[h]))
11321  {
11322  // Copy the hole information
11323  hole_kept.push_back(output_holes_coordinates[h]);
11324  } // if (keep_hole[h])
11325  } // for (h < n_input_holes)
11326 
11327  // Clear the previous storage
11328  output_holes_coordinates.clear();
11329  // Set the output holes
11330  output_holes_coordinates = hole_kept;
11331  }
11332 
11333  //======================================================================
11334  // Sorts the polylines so they be contiguous and then we can
11335  // create a closed or open curve from them
11336  //======================================================================
11337  template<class ELEMENT>
11339  Vector<TriangleMeshPolyLine*>& unsorted_polylines_pt,
11340  Vector<Vector<TriangleMeshPolyLine*>>& sorted_polylines_pt)
11341  {
11342  unsigned n_unsorted_polylines = unsorted_polylines_pt.size();
11343  unsigned n_sorted_polylines = 0;
11344  unsigned curves_index = 0;
11345 
11346  // Map to know which polyline has been already sorted
11347  std::map<TriangleMeshPolyLine*, bool> done_polyline;
11348 
11349  do
11350  {
11351  // Create the list that stores the polylines and allows to introduce
11352  // polylines to the left and to the right
11353  std::list<TriangleMeshPolyLine*> sorted_polyline_list_pt;
11354  bool changes = false;
11355 
11356  // Create pointers to the left and right "side" of the sorted list of
11357  // new created TriangleMeshPolyLines
11358  TriangleMeshPolyLine* left_pt = 0;
11359  TriangleMeshPolyLine* right_pt = 0;
11360 
11361  // 1) Take the first non done polyline on the unsorted list of polylines
11362  unsigned pp = 0;
11363  bool found_root_polyline = false;
11364  while (pp < n_unsorted_polylines && !found_root_polyline)
11365  {
11366  if (!done_polyline[unsorted_polylines_pt[pp]])
11367  {
11368  found_root_polyline = true;
11369  }
11370  else
11371  {
11372  pp++;
11373  }
11374  }
11375 
11376  // Check if there are polylines to be sorted
11377  if (pp < n_unsorted_polylines)
11378  {
11379  // 2) Mark the polyline as done
11380  left_pt = right_pt = unsorted_polylines_pt[pp];
11381  done_polyline[left_pt] = true;
11382  // Increment the number of sorted polylines
11383  n_sorted_polylines++;
11384 
11385  // 3) Add this polyline to the sorted list and use it as root
11386  // to sort the other polylines
11387  sorted_polyline_list_pt.push_back(left_pt);
11388 
11389  do
11390  {
11391  changes = false;
11392 
11393  Vector<double> left_vertex(2);
11394  Vector<double> right_vertex(2);
11395 
11396  left_pt->initial_vertex_coordinate(left_vertex);
11397  right_pt->final_vertex_coordinate(right_vertex);
11398 
11399  for (unsigned i = pp + 1; i < n_unsorted_polylines; i++)
11400  {
11401  TriangleMeshPolyLine* current_polyline_pt =
11402  unsorted_polylines_pt[i];
11403  if (!done_polyline[current_polyline_pt])
11404  {
11405  Vector<double> initial_vertex(2);
11406  Vector<double> final_vertex(2);
11407  current_polyline_pt->initial_vertex_coordinate(initial_vertex);
11408  current_polyline_pt->final_vertex_coordinate(final_vertex);
11409 
11410  // Compare if the current polyline should go to the left or
11411  // to the right on the sorted polyline list
11412 
11413  // Go to the left
11414  if (left_vertex == final_vertex)
11415  {
11416  left_pt = current_polyline_pt;
11417  sorted_polyline_list_pt.push_front(left_pt);
11418  done_polyline[left_pt] = true;
11419  n_sorted_polylines++;
11420 
11421  // We have added one more polyline, go for another round
11422  changes = true;
11423  }
11424  // Go to the right
11425  else if (right_vertex == initial_vertex)
11426  {
11427  right_pt = current_polyline_pt;
11428  sorted_polyline_list_pt.push_back(right_pt);
11429  done_polyline[right_pt] = true;
11430  n_sorted_polylines++;
11431 
11432  // We have added one more polyline, go for another round
11433  changes = true;
11434  }
11435  // Go to the left but it is reversed
11436  else if (left_vertex == initial_vertex)
11437  {
11438  current_polyline_pt->reverse();
11439  left_pt = current_polyline_pt;
11440  sorted_polyline_list_pt.push_front(left_pt);
11441  done_polyline[left_pt] = true;
11442  n_sorted_polylines++;
11443 
11444  // We have added one more polyline, go for another round
11445  changes = true;
11446  }
11447  // Go to the right but it is reversed
11448  else if (right_vertex == final_vertex)
11449  {
11450  current_polyline_pt->reverse();
11451  right_pt = current_polyline_pt;
11452  sorted_polyline_list_pt.push_back(right_pt);
11453  done_polyline[right_pt] = true;
11454  n_sorted_polylines++;
11455 
11456  // We have added one more polyline, go for another round
11457  changes = true;
11458  }
11459  } // if (!done_polyline[current_polyline_pt])
11460  if (changes)
11461  {
11462  break;
11463  }
11464  } // for (i < n_unsorted_polylines)
11465  } while (changes);
11466 
11467  } // if (pp < n_unsorted_polylines)
11468  else
11469  {
11470  // All the polylines are now on the sorted list of polylines
11471 #ifdef PARANOID
11472  // This case comes when it was not possible to find a root polyline
11473  // since all of them are marked as done but the number of sorted and
11474  // unsorted polylines is not the same
11475  if (!found_root_polyline)
11476  {
11477  std::stringstream err;
11478  err << "It was not possible to find a root polyline to sort the "
11479  << "others around it.\nThe number of unsorted and sorted "
11480  << "polylines is different, it means that\nnot all the "
11481  << "polylines have been sorted.\n"
11482  << "Found root polyline: (" << found_root_polyline << ")\n"
11483  << "Sorted polylines: (" << n_sorted_polylines << ")\n"
11484  << "Unsorted polylines: (" << n_unsorted_polylines << ")\n";
11485  throw OomphLibError(err.str(),
11486  "TriangleMesh::sort_polylines_helper()",
11487  OOMPH_EXCEPTION_LOCATION);
11488  }
11489 #endif
11490  }
11491 
11492  // Create the storage for the new sorted polylines and copy them on the
11493  // vector structure for sorted polylines
11494  unsigned n_sorted_polyline_on_list = sorted_polyline_list_pt.size();
11495 
11496  // Create the temporal vector that stores the sorted polylines
11497  Vector<TriangleMeshPolyLine*> tmp_sorted_polylines(
11498  n_sorted_polyline_on_list);
11499  unsigned counter = 0;
11500 
11501  std::list<TriangleMeshPolyLine*>::iterator it_polyline;
11502  for (it_polyline = sorted_polyline_list_pt.begin();
11503  it_polyline != sorted_polyline_list_pt.end();
11504  it_polyline++)
11505  {
11506  tmp_sorted_polylines[counter] = *it_polyline;
11507  counter++;
11508  }
11509 
11510  sorted_polylines_pt.push_back(tmp_sorted_polylines);
11511 
11512  ++curves_index;
11513 
11514  } while (n_sorted_polylines < n_unsorted_polylines);
11515 
11516 #ifdef PARANOID
11517  // Verify that the number of polylines on the sorted list is the same
11518  // as the number of polylines on the unsorted list
11519  if (n_sorted_polylines != n_unsorted_polylines)
11520  {
11521  std::stringstream err;
11522  err << "The number of polylines on the unsorted and sorted vectors"
11523  << " is different,\n"
11524  << "it means that not all the polylines have been sorted.\n"
11525  << "Sorted polylines: " << n_sorted_polylines
11526  << "\nUnsorted polylines: " << n_unsorted_polylines;
11527  throw OomphLibError(err.str(),
11528  "TriangleMesh::sort_polylines_helper()",
11529  OOMPH_EXCEPTION_LOCATION);
11530  }
11531 #endif
11532  }
11533 
11534  //======================================================================
11535  // Creates the shared boundaries
11536  //======================================================================
11537  template<class ELEMENT>
11539  OomphCommunicator* comm_pt,
11540  const Vector<unsigned>& element_domain,
11541  const Vector<GeneralisedElement*>& backed_up_el_pt,
11542  const Vector<FiniteElement*>& backed_up_f_el_pt,
11543  std::map<Data*, std::set<unsigned>>& processors_associated_with_data,
11544  const bool& overrule_keep_as_halo_element_status)
11545  {
11546  // Storage for number of processors and current processor
11547  const unsigned nproc = comm_pt->nproc();
11548  const unsigned my_rank = comm_pt->my_rank();
11549 
11550  // Storage for all the halo elements on all processors
11551  // halo_element[iproc][jproc][ele_number]
11552  // Stores the "ele_number"-th halo element of processor "iproc" with
11553  // processor "jproc"
11554  Vector<Vector<Vector<GeneralisedElement*>>> halo_element_pt(nproc);
11555  // Create complete storage for the halo_element_pt container
11556  for (unsigned iproc = 0; iproc < nproc; iproc++)
11557  {
11558  halo_element_pt[iproc].resize(nproc);
11559  }
11560 
11561  // Store the global index of the element, used to check for possible
11562  // misclassification of halo elements in the above container
11563  // (halo_element_pt)
11564  std::map<GeneralisedElement*, unsigned> element_to_global_index;
11565 
11566  // Get the halo elements on all processors
11567  this->get_halo_elements_on_all_procs(nproc,
11568  element_domain,
11569  backed_up_el_pt,
11570  processors_associated_with_data,
11571  overrule_keep_as_halo_element_status,
11572  element_to_global_index,
11573  halo_element_pt);
11574 
11575  // Resize the shared polylines container
11576  flush_shared_boundary_polyline_pt();
11577  Shared_boundary_polyline_pt.resize(nproc);
11578 
11579  // Create a set that store only the elements that will be kept in
11580  // the processor as nonhalo element, those whose element_domains is
11581  // equal to my_rank. This set is used when creating the shared
11582  // polylines and identify the connections to the original boundaries
11583  std::set<FiniteElement*> element_in_processor_pt;
11584  const unsigned n_ele = backed_up_f_el_pt.size();
11585  for (unsigned e = 0; e < n_ele; e++)
11586  {
11587  if (element_domain[e] == my_rank)
11588  {
11589  element_in_processor_pt.insert(backed_up_f_el_pt[e]);
11590  } // if (element_domain[e] == my_rank)
11591  } // for (e < n_elex)
11592 
11593  // Look for elements edges that may lie on internal boundaries
11594  // If that is the case then relate the face with the boundary on
11595  // which it lies
11596  std::map<std::pair<Node*, Node*>, unsigned> elements_edges_on_boundary;
11597  this->get_element_edges_on_boundary(elements_edges_on_boundary);
11598 
11599  // Now we have all the halo elements on all processors. Use the
11600  // edges shared by the halo elements to create the shared boundaries.
11601  this->create_polylines_from_halo_elements_helper(
11602  element_domain,
11603  element_to_global_index,
11604  element_in_processor_pt,
11605  halo_element_pt,
11606  elements_edges_on_boundary,
11607  Shared_boundary_polyline_pt);
11608  }
11609 
11610  //======================================================================
11611  /// Creates the halo elements on all processors
11612  /// Gets the halo elements on all processors, these elements are then used
11613  /// on the function that computes the shared boundaries among the processors
11614  //======================================================================
11615  template<class ELEMENT>
11617  const unsigned& nproc,
11618  const Vector<unsigned>& element_domain,
11619  const Vector<GeneralisedElement*>& backed_up_el_pt,
11620  std::map<Data*, std::set<unsigned>>& processors_associated_with_data,
11621  const bool& overrule_keep_as_halo_element_status,
11622  std::map<GeneralisedElement*, unsigned>& element_to_global_index,
11623  Vector<Vector<Vector<GeneralisedElement*>>>& output_halo_elements_pt)
11624  {
11625  const unsigned n_ele = backed_up_el_pt.size();
11626 
11627  // Loop over all the processors
11628  for (unsigned iproc = 0; iproc < nproc; iproc++)
11629  {
11630  // Boolean to know which elements has been already added to the
11631  // halo scheme on "iproc" processor
11632  Vector<std::map<GeneralisedElement*, bool>> already_added(nproc);
11633 
11634  // Loop over all backed up elements
11635  for (unsigned e = 0; e < n_ele; e++)
11636  {
11637  // Get element and its domain
11638  GeneralisedElement* el_pt = backed_up_el_pt[e];
11639  unsigned el_domain = element_domain[e];
11640 
11641  // If element is NOT located on "iproc" processor then check if it is
11642  // halo with "el_domain" processor
11643  if (el_domain != iproc)
11644  {
11645  // If this current mesh has been told to keep all elements as halos,
11646  // OR the element itself knows that it must be kept then
11647  // keep it
11648  if ((this->Keep_all_elements_as_halos) ||
11649  (el_pt->must_be_kept_as_halo()))
11650  {
11651  if (!overrule_keep_as_halo_element_status)
11652  {
11653  // Add as halo element whose non-halo counterpart is
11654  // located on processor "el_domain"
11655  if (!already_added[el_domain][el_pt])
11656  {
11657  output_halo_elements_pt[iproc][el_domain].push_back(el_pt);
11658  already_added[el_domain][el_pt] = true;
11659  element_to_global_index[el_pt] = e;
11660  }
11661  }
11662  }
11663  // Otherwise: Is one of the nodes associated with other processor?
11664  else
11665  {
11666  // Can only have nodes if this is a finite element
11667  FiniteElement* finite_el_pt = dynamic_cast<FiniteElement*>(el_pt);
11668  if (finite_el_pt != 0)
11669  {
11670  unsigned n_node = finite_el_pt->nnode();
11671  for (unsigned n = 0; n < n_node; n++)
11672  {
11673  Node* nod_pt = finite_el_pt->node_pt(n);
11674 
11675  // Keep element?
11676  std::set<unsigned>::iterator it =
11677  processors_associated_with_data[nod_pt].find(iproc);
11678  if (it != processors_associated_with_data[nod_pt].end())
11679  {
11680  // Add as root halo element whose non-halo counterpart is
11681  // located on processor "el_domain"
11682  if (!already_added[el_domain][el_pt])
11683  {
11684  output_halo_elements_pt[iproc][el_domain].push_back(el_pt);
11685  already_added[el_domain][el_pt] = true;
11686  element_to_global_index[el_pt] = e;
11687  }
11688  // Now break out of loop over nodes
11689  break;
11690  } // if (it!=processors_associated_with_data[nod_pt].end())
11691  } // for (n < n_node)
11692  } // if (finite_el_pt!=0)
11693  } // else (this->Keep_all_elements_as_halos)
11694  } // if (el_domain!=iproc)
11695  } // for (e < nele)
11696  } // for (iproc < nproc)
11697  }
11698 
11699  //====================================================================
11700  // Get the element edges (pair of nodes, edges) that lie
11701  // on a boundary (used to mark shared boundaries that lie on
11702  // internal boundaries)
11703  //====================================================================
11704  template<class ELEMENT>
11706  std::map<std::pair<Node*, Node*>, unsigned>& element_edges_on_boundary)
11707  {
11708  // The number of original boundaries
11709  const unsigned nbound = this->nboundary();
11710  // Loop over the boundaries
11711  for (unsigned b = 0; b < nbound; b++)
11712  {
11713  // Keep track of the pair of nodes done
11714  std::map<std::pair<Node*, Node*>, bool> edge_done;
11715  // Get the number of elements on the boundary
11716  const unsigned nbound_ele = this->nboundary_element(b);
11717  for (unsigned e = 0; e < nbound_ele; e++)
11718  {
11719  // Get the boundary bulk element
11720  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
11721  // Get the face index
11722  int face_index = this->face_index_at_boundary(b, e);
11723  // Create the face element
11724  FiniteElement* face_ele_pt =
11725  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
11726  // Get the number of nodes on the face element
11727  const unsigned nnodes = face_ele_pt->nnode();
11728  // Get the first and last node
11729  Node* first_node_pt = face_ele_pt->node_pt(0);
11730  Node* last_node_pt = face_ele_pt->node_pt(nnodes - 1);
11731 
11732  // Create the pair to store the nodes
11733  std::pair<Node*, Node*> edge =
11734  std::make_pair(first_node_pt, last_node_pt);
11735 
11736  // Has the edge been included
11737  if (!edge_done[edge])
11738  {
11739  // Mark the edge as done
11740  edge_done[edge] = true;
11741 
11742  // Create the reversed version and mark it as done too
11743  std::pair<Node*, Node*> inv_edge =
11744  std::make_pair(last_node_pt, first_node_pt);
11745 
11746  // Mark the reversed edge as done
11747  edge_done[inv_edge] = true;
11748 
11749  // Mark the edge to belong to boundary b
11750  element_edges_on_boundary[edge] = b;
11751  } // if (!edge_done[edge])
11752 
11753  // Free the memory allocated for the face element
11754  delete face_ele_pt;
11755  face_ele_pt = 0;
11756 
11757  } // for (e < nbound_ele)
11758 
11759  } // for (b < nbound)
11760  }
11761 
11762  // ======================================================================
11763  // Creates polylines from the intersection of halo elements on
11764  // all processors. The new polylines define the shared boundaries in
11765  // the domain This method computes the polylines on ALL processors,
11766  // that is why the three dimensions in the structure
11767  // output_polylines_pt[iproc][ncurve][npolyline]
11768  // ======================================================================
11769  template<class ELEMENT>
11771  const Vector<unsigned>& element_domain,
11772  std::map<GeneralisedElement*, unsigned>& element_to_global_index,
11773  std::set<FiniteElement*>& element_in_processor_pt,
11774  Vector<Vector<Vector<GeneralisedElement*>>>& input_halo_elements,
11775  std::map<std::pair<Node*, Node*>, unsigned>& elements_edges_on_boundary,
11776  Vector<Vector<Vector<TriangleMeshPolyLine*>>>& output_polylines_pt)
11777  {
11778  const unsigned nproc = this->communicator_pt()->nproc();
11779  const unsigned my_rank = this->communicator_pt()->my_rank();
11780 
11781  // ---------------------------------------------------------------
11782  // Get the edges shared between each pair of processors
11783  // ---------------------------------------------------------------
11784 
11785  // Storage for the edges (pair of nodes) shared between a pair of
11786  // processors
11787  Vector<Vector<Vector<std::pair<Node*, Node*>>>> edges(nproc);
11788 
11789  // Each edge is associated to two elements, a haloi (halo element
11790  // in processors i) and a haloj (halo element in processors j)
11791  Vector<Vector<Vector<Vector<FiniteElement*>>>> edge_element_pt(nproc);
11792 
11793  // Each edge is associated to two elements, a haloi and a haloj,
11794  // the edge was created from a given face from each element, the
11795  // haloi face is stored at [0], the haloj face is stored at [1]
11796  Vector<Vector<Vector<Vector<int>>>> edge_element_face(nproc);
11797 
11798  // Store the possible internal boundary id associated to each edge
11799  // (-1 if there is no association). Some edges may overlap an
11800  // internal boundary (and only internal boundaries)
11801  Vector<Vector<Vector<int>>> edge_boundary(nproc);
11802 
11803  // Mark those edges (pair of nodes overlapped by a shared boundary)
11804  std::map<std::pair<Node*, Node*>, bool> overlapped_edge;
11805 
11806  // Resize the containers, they store info. for each pair of
11807  // processors
11808 
11809  // First resize the global container
11810  Shared_boundaries_ids.resize(nproc);
11811  for (unsigned j = 0; j < nproc; j++)
11812  {
11813  edges[j].resize(nproc);
11814  edge_element_pt[j].resize(nproc);
11815  edge_element_face[j].resize(nproc);
11816  edge_boundary[j].resize(nproc);
11817 
11818  // Resize the global container for shared boundaries ids
11819  Shared_boundaries_ids[j].resize(nproc);
11820 
11821  } // for (j < nproc)
11822 
11823  // Take the halo elements of processor "iproc" and compare their
11824  // edges with halo elements of other processors (except itself)
11825  for (unsigned iproc = 0; iproc < nproc; iproc++)
11826  {
11827  // Take the halo elements of processor iproc and compare with
11828  // other processors
11829  // Start from the iproc + 1,
11830  // 1) To avoid comparing with itself,
11831  // 2) To avoid generation of repeated boundaries
11832  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
11833  {
11834  // **************************************************************
11835  // FIRST PART
11836  // 1) Get the halo elements of processor "iproc" with processor
11837  // "jproc"
11838  // 2) Get the halo elements of processor "jproc" with processor
11839  // "iproc"
11840  // 3) Compare their edges and those that match are the ones that
11841  // define the shared boundaries
11842  // **************************************************************
11843 
11844  // Storage for halo elements
11845  Vector<GeneralisedElement*> halo_elements_iproc_with_jproc;
11846  Vector<GeneralisedElement*> halo_elements_jproc_with_iproc;
11847 
11848  // Get the halo elements of "iproc" with "jproc"
11849  halo_elements_iproc_with_jproc = input_halo_elements[iproc][jproc];
11850 
11851  // If there are halo elements then there are shared boundaries
11852  const unsigned nhalo_elements_iproc_with_jproc =
11853  halo_elements_iproc_with_jproc.size();
11854  // DEBP(nhalo_elements_iproc_with_jproc);
11855  if (nhalo_elements_iproc_with_jproc > 0)
11856  {
11857  // Get the halo elements of "jproc" with "iproc"
11858  halo_elements_jproc_with_iproc = input_halo_elements[jproc][iproc];
11859 
11860  // If there are halo elements then there are shared
11861  // boundaries
11862  const unsigned nhalo_elements_jproc_with_iproc =
11863  halo_elements_jproc_with_iproc.size();
11864 // DEBP(nhalo_elements_jproc_with_iproc);
11865 #ifdef PARANOID
11866  if (nhalo_elements_jproc_with_iproc == 0)
11867  {
11868  // If there are halo elements of iproc with jproc there
11869  // MUST be halo elements on the other way round, not
11870  // necessary the same but at least one
11871  std::stringstream err;
11872  err << "There are no halo elements from processor (" << jproc
11873  << ") "
11874  << "with processor (" << iproc << ").\n"
11875  << "This is strange since there are halo elements from "
11876  << "processor (" << iproc << ") with processor (" << jproc
11877  << ").\n"
11878  << "Number of halo elements from (" << iproc << ") to ("
11879  << jproc << ") : (" << nhalo_elements_iproc_with_jproc << ")\n"
11880  << "Number of halo elements from (" << jproc << ") to ("
11881  << iproc << ") : (" << nhalo_elements_jproc_with_iproc << ")\n";
11882  throw OomphLibError(
11883  err.str(),
11884  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11885  OOMPH_EXCEPTION_LOCATION);
11886  }
11887 #endif
11888  // The edges are defined as pair of nodes
11889  Vector<Node*> halo_edges_iproc;
11890  unsigned halo_edges_counter_iproc = 0;
11891  Vector<Node*> halo_edges_jproc;
11892  unsigned halo_edges_counter_jproc = 0;
11893 
11894  // Map to associate the edge with the element used to create it
11895  std::map<std::pair<Node*, Node*>, FiniteElement*>
11896  edgesi_to_element_pt;
11897 
11898  // Map to associated the edge with the face number of the
11899  // element that created it
11900  std::map<std::pair<std::pair<Node*, Node*>, FiniteElement*>, int>
11901  edgesi_element_pt_to_face_index;
11902 
11903  // Map to associate the edge with the element used to create it
11904  std::map<std::pair<Node*, Node*>, FiniteElement*>
11905  edgesj_to_element_pt;
11906 
11907  // Map to associated the edge with the face number of the
11908  // element that created it
11909  std::map<std::pair<std::pair<Node*, Node*>, FiniteElement*>, int>
11910  edgesj_element_pt_to_face_index;
11911 
11912  // **************************************************************
11913  // 1.1) Store the edges of the "iproc" halo elements
11914  // **************************************************************
11915  // Go throught halo elements on "iproc" processor
11916  for (unsigned ih = 0; ih < nhalo_elements_iproc_with_jproc; ih++)
11917  {
11918 #ifdef PARANOID
11919  unsigned e =
11920  element_to_global_index[halo_elements_iproc_with_jproc[ih]];
11921  // Only work with halo elements inside the "jproc" processor
11922  if (element_domain[e] != jproc)
11923  {
11924  // There was a problem on the ihalo-jhalo classification
11925  std::stringstream err;
11926  err << "There was a problem on the ihalo-jhalo classification.\n"
11927  << "One of the elements, (the one with the (" << e << ")-th "
11928  << "index ) is not on the (" << jproc << ")-th processor\n"
11929  << "but it was stored as a halo element of processor ("
11930  << iproc << ") with processor (" << jproc << ").\n";
11931  throw OomphLibError(
11932  err.str(),
11933  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11934  OOMPH_EXCEPTION_LOCATION);
11935  }
11936 #endif
11937 
11938  FiniteElement* el_pt =
11939  dynamic_cast<FiniteElement*>(halo_elements_iproc_with_jproc[ih]);
11940 
11941  if (el_pt == 0)
11942  {
11943  std::stringstream err;
11944  err << "The halo element (" << ih
11945  << ") could not be casted to the "
11946  << "FiniteElement type.\n";
11947  throw OomphLibError(
11948  err.str(),
11949  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11950  OOMPH_EXCEPTION_LOCATION);
11951  }
11952 
11953 #ifdef PARANOID
11954  // Number of nodes on this element
11955  const unsigned n_nodes = el_pt->nnode();
11956 
11957  // The number of nodes on every element should be at least
11958  // three since we are going to work with the cornes nodes,
11959  // the ones with index 0, 1 and 2
11960  if (n_nodes < 3)
11961  {
11962  std::stringstream err;
11963  err << "The number of nodes of the " << ih
11964  << "-th halo element is"
11965  << " (" << n_nodes << ").\nWe can not work with triangle "
11966  << "elements with less than three nodes\n";
11967  throw OomphLibError(
11968  err.str(),
11969  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11970  OOMPH_EXCEPTION_LOCATION);
11971  }
11972 #endif
11973 
11974  // Get the corner nodes, the first three nodes
11975  Node* first_node_pt = el_pt->node_pt(0);
11976  Node* second_node_pt = el_pt->node_pt(1);
11977  Node* third_node_pt = el_pt->node_pt(2);
11978 
11979  // Store the edges
11980  halo_edges_iproc.push_back(first_node_pt);
11981  halo_edges_iproc.push_back(second_node_pt);
11982  halo_edges_counter_jproc++;
11983 
11984  halo_edges_iproc.push_back(second_node_pt);
11985  halo_edges_iproc.push_back(third_node_pt);
11986  halo_edges_counter_jproc++;
11987 
11988  halo_edges_iproc.push_back(third_node_pt);
11989  halo_edges_iproc.push_back(first_node_pt);
11990  halo_edges_counter_jproc++;
11991 
11992  // Store the info. of the element used to create these edges
11993  std::pair<Node*, Node*> edge1 =
11994  std::make_pair(first_node_pt, second_node_pt);
11995  edgesi_to_element_pt[edge1] = el_pt;
11996 
11997  std::pair<Node*, Node*> edge2 =
11998  std::make_pair(second_node_pt, third_node_pt);
11999  edgesi_to_element_pt[edge2] = el_pt;
12000 
12001  std::pair<Node*, Node*> edge3 =
12002  std::make_pair(third_node_pt, first_node_pt);
12003  edgesi_to_element_pt[edge3] = el_pt;
12004 
12005  // Store the face index of the edge in the element
12006  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele1 =
12007  std::make_pair(edge1, el_pt);
12008  edgesi_element_pt_to_face_index[edge_ele1] = 2;
12009 
12010  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele2 =
12011  std::make_pair(edge2, el_pt);
12012  edgesi_element_pt_to_face_index[edge_ele2] = 0;
12013 
12014  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele3 =
12015  std::make_pair(edge3, el_pt);
12016  edgesi_element_pt_to_face_index[edge_ele3] = 1;
12017 
12018  } // for (ih < nhalo_elements_iproc_with_jproc)
12019 
12020  // **************************************************************
12021  // 1.2) Store the edges of the "jproc" halo elements
12022  // **************************************************************
12023  // Go throught halo elements on "jproc" processor
12024  for (unsigned jh = 0; jh < nhalo_elements_jproc_with_iproc; jh++)
12025  {
12026 #ifdef PARANOID
12027  unsigned e =
12028  element_to_global_index[halo_elements_jproc_with_iproc[jh]];
12029  // Only work with halo elements inside the "jproc" processor
12030  if (element_domain[e] != iproc)
12031  {
12032  // There was a problem on the jhalo-ihalo classification
12033  std::stringstream err;
12034  err << "There was a problem on the jhalo-ihalo classification.\n"
12035  << "One of the elements, (the one with the (" << e << ")-th "
12036  << "index ) is not on the (" << iproc << ")-th processor\n"
12037  << "but it was stored as a halo element of processor ("
12038  << jproc << ") with processor (" << iproc << ").\n";
12039  throw OomphLibError(
12040  err.str(),
12041  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12042  OOMPH_EXCEPTION_LOCATION);
12043  }
12044 #endif
12045 
12046  FiniteElement* el_pt =
12047  dynamic_cast<FiniteElement*>(halo_elements_jproc_with_iproc[jh]);
12048  if (el_pt == 0)
12049  {
12050  std::stringstream err;
12051  err << "The halo element (" << jh
12052  << ") could not be casted to the "
12053  << "FiniteElement type.\n";
12054  throw OomphLibError(
12055  err.str(),
12056  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12057  OOMPH_EXCEPTION_LOCATION);
12058  }
12059 
12060 #ifdef PARANOID
12061  // Number of nodes on this element
12062  const unsigned n_nodes = el_pt->nnode();
12063 
12064  // The number of nodes on every element should be at least
12065  // three since we are going to work with the cornes nodes,
12066  // the ones with index 0, 1 and 2
12067  if (n_nodes < 3)
12068  {
12069  std::stringstream err;
12070  err << "The number of nodes of the " << jh
12071  << "-th halo element is"
12072  << " (" << n_nodes << ").\nWe can not work with triangle "
12073  << "elements with less than three nodes\n";
12074  throw OomphLibError(
12075  err.str(),
12076  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12077  OOMPH_EXCEPTION_LOCATION);
12078  }
12079 #endif
12080 
12081  // Get the nodes pointers
12082  Node* first_node_pt = el_pt->node_pt(0);
12083  Node* second_node_pt = el_pt->node_pt(1);
12084  Node* third_node_pt = el_pt->node_pt(2);
12085 
12086  // Store the edges
12087  halo_edges_jproc.push_back(first_node_pt);
12088  halo_edges_jproc.push_back(second_node_pt);
12089  halo_edges_counter_iproc++;
12090 
12091  halo_edges_jproc.push_back(second_node_pt);
12092  halo_edges_jproc.push_back(third_node_pt);
12093  halo_edges_counter_iproc++;
12094 
12095  halo_edges_jproc.push_back(third_node_pt);
12096  halo_edges_jproc.push_back(first_node_pt);
12097  halo_edges_counter_iproc++;
12098 
12099  // Store the info. of the element used to create these edges
12100  std::pair<Node*, Node*> edge1 =
12101  std::make_pair(first_node_pt, second_node_pt);
12102  edgesj_to_element_pt[edge1] = el_pt;
12103 
12104  std::pair<Node*, Node*> edge2 =
12105  std::make_pair(second_node_pt, third_node_pt);
12106  edgesj_to_element_pt[edge2] = el_pt;
12107 
12108  std::pair<Node*, Node*> edge3 =
12109  std::make_pair(third_node_pt, first_node_pt);
12110  edgesj_to_element_pt[edge3] = el_pt;
12111 
12112  // Store the face index of the edge in the element
12113  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele1 =
12114  std::make_pair(edge1, el_pt);
12115  edgesj_element_pt_to_face_index[edge_ele1] = 2;
12116 
12117  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele2 =
12118  std::make_pair(edge2, el_pt);
12119  edgesj_element_pt_to_face_index[edge_ele2] = 0;
12120 
12121  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele3 =
12122  std::make_pair(edge3, el_pt);
12123  edgesj_element_pt_to_face_index[edge_ele3] = 1;
12124 
12125  } // for (jh < nhalo_elements_jproc_with_iproc)
12126 
12127  // ***************************************************************
12128  // SECOND PART
12129  // 1) We already have the information of the edges on the iproc
12130  // halo and jproc halo elements
12131  // 2) Identify the shared edges to create the shared boundaries
12132  // (Only store the information but do not create the polyline)
12133  // ***************************************************************
12134 
12135  // Get the number of edges from each processor
12136  unsigned nhalo_iedges = halo_edges_iproc.size();
12137  unsigned nhalo_jedges = halo_edges_jproc.size();
12138 
12139  // Start comparing the edges to check which of those are
12140  // shared between the "ihalo_edge" and the "jhalo_edge"
12141  for (unsigned ihe = 0; ihe < nhalo_iedges; ihe += 2)
12142  {
12143  // Get the ihe-th edge (pair of nodes)
12144  Vector<Node*> ihalo_edge(2);
12145  ihalo_edge[0] = halo_edges_iproc[ihe];
12146  ihalo_edge[1] = halo_edges_iproc[ihe + 1];
12147 
12148  // Create the pair that defines the edge
12149  std::pair<Node*, Node*> tmp_edge =
12150  std::make_pair(ihalo_edge[0], ihalo_edge[1]);
12151 
12152  // Check if the edge lies on a boundary (default values is
12153  // -1 for no association with an internal boundary)
12154  int edge_boundary_id = -1;
12155  {
12156  std::map<std::pair<Node*, Node*>, unsigned>::iterator it;
12157  it = elements_edges_on_boundary.find(tmp_edge);
12158  // If the edges lie on a boundary then get the boundary id
12159  // on which the edges lie
12160  if (it != elements_edges_on_boundary.end())
12161  {
12162  // Assign the internal boundary id associated with the
12163  // edge
12164  edge_boundary_id = (*it).second;
12165  }
12166  else
12167  {
12168  // Look for the reversed version of the edge (the nodes
12169  // inverted)
12170  std::pair<Node*, Node*> rtmp_edge =
12171  std::make_pair(ihalo_edge[1], ihalo_edge[0]);
12172  it = elements_edges_on_boundary.find(rtmp_edge);
12173  if (it != elements_edges_on_boundary.end())
12174  {
12175  // Assign the internal boundary id associated with the
12176  // edge
12177  edge_boundary_id = (*it).second;
12178  }
12179  }
12180  }
12181 
12182  // Go through the jhalo_edge and compare with the
12183  // ihalo_edge
12184  for (unsigned jhe = 0; jhe < nhalo_jedges; jhe += 2)
12185  {
12186  // Get the jhe-th edge (pair of nodes)
12187  Vector<Node*> jhalo_edge(2);
12188  jhalo_edge[0] = halo_edges_jproc[jhe];
12189  jhalo_edge[1] = halo_edges_jproc[jhe + 1];
12190 
12191  // Comparing pointer of nodes
12192  if (ihalo_edge[0] == jhalo_edge[0] &&
12193  ihalo_edge[1] == jhalo_edge[1])
12194  {
12195  // Create the edge (both nodes that make the edge)
12196  std::pair<Node*, Node*> new_edge =
12197  std::make_pair(ihalo_edge[0], ihalo_edge[1]);
12198 
12199  // Get the elements involved in the creation of the
12200  // edge to check that there are elements associated to
12201  // the edge
12202  FiniteElement* haloi_ele_pt = 0;
12203  haloi_ele_pt = edgesi_to_element_pt[new_edge];
12204  FiniteElement* haloj_ele_pt = 0;
12205  haloj_ele_pt = edgesj_to_element_pt[new_edge];
12206 
12207  // Verify that there is an element associated with it
12208  if (haloi_ele_pt == 0 || haloj_ele_pt == 0)
12209  {
12210  std::stringstream err;
12211  err << "There is no associated elements with the new "
12212  << "shared boundary. This is an storing problem,\n"
12213  << "possibly related with a memory leak problem!!!\n"
12214  << "The nodes that compound the edge are these:\n"
12215  << "On processor (" << iproc << "):\n"
12216  << "(" << ihalo_edge[0]->x(0) << ", "
12217  << ihalo_edge[0]->x(1) << ") and (" << ihalo_edge[1]->x(0)
12218  << ", " << ihalo_edge[1]->x(1) << ")\n\n"
12219  << "On processor (" << jproc << "):\n"
12220  << "(" << jhalo_edge[0]->x(0) << ", "
12221  << jhalo_edge[0]->x(1) << ") and (" << jhalo_edge[1]->x(0)
12222  << ", " << jhalo_edge[1]->x(1) << ")\n\n"
12223  << "The nodes coordinates should be the same!!!\n";
12224  throw OomphLibError(err.str(),
12225  "TriangleMesh::create_polylines_from_"
12226  "halo_elements_helper()",
12227  OOMPH_EXCEPTION_LOCATION);
12228  }
12229 
12230  // Store the edge
12231  edges[iproc][jproc].push_back(new_edge);
12232 
12233  // Is the edge overlapped by a shared boundary
12234  if (edge_boundary_id >= 0)
12235  {
12236  // Mark the edge as overlapped
12237  overlapped_edge[new_edge] = true;
12238 
12239  // Also mark the reversed edge
12240  std::pair<Node*, Node*> rev_new_edge =
12241  std::make_pair(ihalo_edge[1], ihalo_edge[0]);
12242 
12243  // Mark the edge as overlapped
12244  overlapped_edge[rev_new_edge] = true;
12245 
12246  } // if (edge_boundary_id >= 0)
12247 
12248  // Store the internal boundary id (default -1)
12249  // associated to the edge
12250  edge_boundary[iproc][jproc].push_back(edge_boundary_id);
12251 
12252  // Store the two elements associated with the edge
12253  Vector<FiniteElement*> tmp_elements_pt;
12254  tmp_elements_pt.push_back(haloi_ele_pt);
12255  tmp_elements_pt.push_back(haloj_ele_pt);
12256 
12257  // Associate the edge with the elements that gave rise to it
12258  edge_element_pt[iproc][jproc].push_back(tmp_elements_pt);
12259 
12260  // Get the face index on each element that gave rise to
12261  // the edge
12262 
12263  // .. first create the pair (edge, finite_element)
12264  std::pair<std::pair<Node*, Node*>, FiniteElement*>
12265  edge_elementi_pair = make_pair(new_edge, haloi_ele_pt);
12266 
12267  std::pair<std::pair<Node*, Node*>, FiniteElement*>
12268  edge_elementj_pair = make_pair(new_edge, haloj_ele_pt);
12269 
12270  // Set default values to later check if values were
12271  // read from the map structure
12272  int face_index_haloi_ele = -1;
12273  face_index_haloi_ele =
12274  edgesi_element_pt_to_face_index[edge_elementi_pair];
12275  int face_index_haloj_ele = -1;
12276  face_index_haloj_ele =
12277  edgesj_element_pt_to_face_index[edge_elementj_pair];
12278  // Verify that there is an element associated with it
12279  if (face_index_haloi_ele == -1 || face_index_haloj_ele == -1)
12280  {
12281  std::stringstream err;
12282  err << "There is no associated face indexes to the"
12283  << "elements that gave\nrise to the shared edge\n"
12284  << "The nodes that compound the edge are these:\n"
12285  << "On processor (" << iproc << "):\n"
12286  << "(" << ihalo_edge[0]->x(0) << ", "
12287  << ihalo_edge[0]->x(1) << ") and (" << ihalo_edge[1]->x(0)
12288  << ", " << ihalo_edge[1]->x(1) << ")\n\n"
12289  << "On processor (" << jproc << "):\n"
12290  << "(" << jhalo_edge[0]->x(0) << ", "
12291  << jhalo_edge[0]->x(1) << ") and (" << jhalo_edge[1]->x(0)
12292  << ", " << jhalo_edge[1]->x(1) << ")\n\n"
12293  << "The nodes coordinates should be the same!!!\n";
12294  throw OomphLibError(err.str(),
12295  "TriangleMesh::create_polylines_from_"
12296  "halo_elements_helper()",
12297  OOMPH_EXCEPTION_LOCATION);
12298  } // if (face_index_haloi_ele == -1 ||
12299  // face_index_haloj_ele == -1)
12300 
12301  // Get the face indexes from the map structure
12302  Vector<int> tmp_edge_element_face_index;
12303  tmp_edge_element_face_index.push_back(face_index_haloi_ele);
12304  tmp_edge_element_face_index.push_back(face_index_haloj_ele);
12305  // Store the face indexes
12306  edge_element_face[iproc][jproc].push_back(
12307  tmp_edge_element_face_index);
12308 
12309  break; // break for (jhe < nhalo_jedges) since edge
12310  // found
12311 
12312  } // if (ihalo_edge[0] == jhalo_edge[0] &&
12313  // ihalo_edge[1] == jhalo_edge[1])
12314  // Comparing nodes pointers
12315  else if (ihalo_edge[0] == jhalo_edge[1] &&
12316  ihalo_edge[1] == jhalo_edge[0])
12317  {
12318  // Create the edge (both nodes that make the edge)
12319  std::pair<Node*, Node*> new_edge =
12320  std::make_pair(ihalo_edge[0], ihalo_edge[1]);
12321 
12322  // Get the elements involved in the creation of the
12323  // edge
12324  FiniteElement* haloi_ele_pt = 0;
12325  haloi_ele_pt = edgesi_to_element_pt[new_edge];
12326 
12327  FiniteElement* haloj_ele_pt = 0;
12328  // Create the edge (reversed, that is how it was
12329  // originally stored)
12330  std::pair<Node*, Node*> new_edge_reversed =
12331  std::make_pair(jhalo_edge[0], jhalo_edge[1]);
12332  haloj_ele_pt = edgesj_to_element_pt[new_edge_reversed];
12333 
12334  // Verify that there is an element associated with it
12335  if (haloi_ele_pt == 0 || haloj_ele_pt == 0)
12336  {
12337  std::stringstream err;
12338  err << "There is no associated elements with the new "
12339  << "shared boundary (reversed version). This is an "
12340  << "storing problem, possibly related with a memory "
12341  << "leak problem!!!\n"
12342  << "The nodes that compound the edge are these:\n"
12343  << "On processor (" << iproc << "):\n"
12344  << "(" << ihalo_edge[0]->x(0) << ", "
12345  << ihalo_edge[0]->x(1) << ") and (" << ihalo_edge[1]->x(0)
12346  << ", " << ihalo_edge[1]->x(1) << ")\n\n"
12347  << "On processor (" << jproc << "):\n"
12348  << "(" << jhalo_edge[0]->x(0) << ", "
12349  << jhalo_edge[0]->x(1) << ") and (" << jhalo_edge[1]->x(0)
12350  << ", " << jhalo_edge[1]->x(1) << ")\n\n"
12351  << "The nodes coordinates should be the same!!!\n";
12352  throw OomphLibError(err.str(),
12353  "TriangleMesh::create_polylines_from_"
12354  "halo_elements_helper()",
12355  OOMPH_EXCEPTION_LOCATION);
12356  }
12357 
12358  // Store the edge
12359  edges[iproc][jproc].push_back(new_edge);
12360 
12361  // Is the edge overlapped by a shared boundary
12362  if (edge_boundary_id >= 0)
12363  {
12364  // Mark the edge as overlapped
12365  overlapped_edge[new_edge] = true;
12366 
12367  // Also mark the reversed edge
12368  std::pair<Node*, Node*> rev_new_edge =
12369  std::make_pair(ihalo_edge[1], ihalo_edge[0]);
12370 
12371  // Mark the edge as overlapped
12372  overlapped_edge[rev_new_edge] = true;
12373  } // if (edge_boundary_id >= 0)
12374 
12375  // Store the internal boundary id (default -1)
12376  // associated to the edge
12377  edge_boundary[iproc][jproc].push_back(edge_boundary_id);
12378 
12379  // Store the two elements associated with the edge
12380  Vector<FiniteElement*> tmp_elements_pt;
12381  tmp_elements_pt.push_back(haloi_ele_pt);
12382  tmp_elements_pt.push_back(haloj_ele_pt);
12383 
12384  // Associate the edge with the elements that gave rise to it
12385  edge_element_pt[iproc][jproc].push_back(tmp_elements_pt);
12386 
12387  // Get the face index on each element that gave rise to
12388  // the edge
12389 
12390  // .. first create the pair (edge, finite_element)
12391  std::pair<std::pair<Node*, Node*>, FiniteElement*>
12392  edge_elementi_pair = make_pair(new_edge, haloi_ele_pt);
12393 
12394  std::pair<std::pair<Node*, Node*>, FiniteElement*>
12395  edge_elementj_pair =
12396  make_pair(new_edge_reversed, haloj_ele_pt);
12397 
12398  // Set default values to later check if values were
12399  // read from the map structure
12400  int face_index_haloi_ele = -1;
12401  face_index_haloi_ele =
12402  edgesi_element_pt_to_face_index[edge_elementi_pair];
12403  int face_index_haloj_ele = -1;
12404  face_index_haloj_ele =
12405  edgesj_element_pt_to_face_index[edge_elementj_pair];
12406  // Verify that there is an element associated with it
12407  if (face_index_haloi_ele == -1 || face_index_haloj_ele == -1)
12408  {
12409  std::stringstream err;
12410  err << "There is no associated face indexes to the"
12411  << "elements that gave\nrise to the shared edge\n"
12412  << "The nodes that compound the edge are these:\n"
12413  << "On processor (" << iproc << "):\n"
12414  << "(" << ihalo_edge[0]->x(0) << ", "
12415  << ihalo_edge[0]->x(1) << ") and (" << ihalo_edge[1]->x(0)
12416  << ", " << ihalo_edge[1]->x(1) << ")\n\n"
12417  << "On processor (" << jproc << "):\n"
12418  << "(" << jhalo_edge[0]->x(0) << ", "
12419  << jhalo_edge[0]->x(1) << ") and (" << jhalo_edge[1]->x(0)
12420  << ", " << jhalo_edge[1]->x(1) << ")\n\n"
12421  << "The nodes coordinates should be the same!!!\n";
12422  throw OomphLibError(err.str(),
12423  "TriangleMesh::create_polylines_from_"
12424  "halo_elements_helper()",
12425  OOMPH_EXCEPTION_LOCATION);
12426  } // if (face_index_haloi_ele == -1 ||
12427  // face_index_haloj_ele == -1)
12428 
12429  // Get the face indexes from the map structure
12430  Vector<int> tmp_edge_element_face_index;
12431  tmp_edge_element_face_index.push_back(face_index_haloi_ele);
12432  tmp_edge_element_face_index.push_back(face_index_haloj_ele);
12433  // Store the face indexes
12434  edge_element_face[iproc][jproc].push_back(
12435  tmp_edge_element_face_index);
12436 
12437  break; // break for (jhe < nhalo_jedges) since edge found
12438 
12439  } // else if (ihalo_edge[0] == jhalo_edge[1] &&
12440  // ihalo_edge[1] == jhalo_edge[0])
12441 
12442  } // for (jhe < nhaloj_edges)
12443 
12444  } // for (ihe < nhaloi_edges)
12445 
12446  } // if (nhalo_elements_iproc_with_jproc > 0)
12447 
12448  } // for (jproc < nproc)
12449 
12450  } // for (iproc < nproc)
12451 
12452  // ------------------------------------------------------------------
12453  // Compute the degree of each node in the shared edges
12454  // ------------------------------------------------------------------
12455 
12456  // Visit all the shared edges between each pair of processors,
12457  // visit the nodes of each edge and compute the degree of each node
12458 
12459  // Store the degree (valency) of each node
12460  std::map<Node*, unsigned> global_shared_node_degree;
12461 
12462 #ifdef PARANOID
12463  // Map to check if an edge has been already visited
12464  std::map<std::pair<Node*, Node*>, bool> edge_done;
12465 #endif // #ifdef PARANOID
12466  // Map to check if a node has been already visited
12467  std::map<Node*, bool> node_done;
12468 
12469  // Loop over the processors and get the shared edged between each
12470  // pair of processors
12471  for (unsigned iproc = 0; iproc < nproc; iproc++)
12472  {
12473  // Start from iproc + 1 to avoid checking with itself (there is
12474  // no shared edges between the same processor), and to avoid
12475  // double counting the edges and nodes (the shared edges between
12476  // processor (iproc, jproc) are the same as those between
12477  // processor jproc, iproc)
12478  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
12479  {
12480  // Get the number of edges shared between the pair of processors
12481  const unsigned nshd_edges = edges[iproc][jproc].size();
12482 #ifdef PARANOID
12483  // There must be the same number of information on each of the
12484  // containers
12485 
12486  // Get the number of edge elements
12487  const unsigned nedge_element = edge_element_pt[iproc][jproc].size();
12488  if (nshd_edges != nedge_element)
12489  {
12490  std::stringstream error_message;
12491  error_message
12492  << "The number of shared edges between processor iproc and jproc\n"
12493  << "is different form the number of edge elements between the\n"
12494  << "pair of processors\n"
12495  << "iproc: (" << iproc << ")\n"
12496  << "jproc: (" << jproc << ")\n"
12497  << "# of shared edges: (" << nshd_edges << ")\n"
12498  << "# of edge elements: (" << nedge_element << ")\n\n";
12499  throw OomphLibError(
12500  error_message.str(),
12501  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12502  OOMPH_EXCEPTION_LOCATION);
12503  }
12504 
12505  // Get the number of edge element faces
12506  const unsigned nedge_element_face =
12507  edge_element_face[iproc][jproc].size();
12508  if (nshd_edges != nedge_element_face)
12509  {
12510  std::stringstream error_message;
12511  error_message
12512  << "The number of shared edges between processor iproc and jproc\n"
12513  << "is different form the number of edge element faces between "
12514  "the\n"
12515  << "pair of processors\n"
12516  << "iproc: (" << iproc << ")\n"
12517  << "jproc: (" << jproc << ")\n"
12518  << "# of shared edges: (" << nshd_edges << ")\n"
12519  << "# of edge element faces: (" << nedge_element_face << ")\n\n";
12520  throw OomphLibError(
12521  error_message.str(),
12522  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12523  OOMPH_EXCEPTION_LOCATION);
12524  }
12525 
12526  // Get the number of edge boundaries
12527  const unsigned nedge_boundary = edge_boundary[iproc][jproc].size();
12528  if (nshd_edges != nedge_boundary)
12529  {
12530  std::stringstream error_message;
12531  error_message
12532  << "The number of shared edges between processor iproc and jproc\n"
12533  << "is different form the number of edge boundaries ids between "
12534  "the\n"
12535  << "pair of processors\n"
12536  << "iproc: (" << iproc << ")\n"
12537  << "jproc: (" << jproc << ")\n"
12538  << "# of shared edges: (" << nshd_edges << ")\n"
12539  << "# of edge boundaries ids: (" << nedge_boundary << ")\n\n";
12540  throw OomphLibError(
12541  error_message.str(),
12542  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12543  OOMPH_EXCEPTION_LOCATION);
12544  }
12545 
12546 #endif // #ifdef PARANOID
12547 
12548  // Loop over the shared edges between (iproc, jproc) processors
12549  for (unsigned se = 0; se < nshd_edges; se++)
12550  {
12551  // Get the edge
12552  std::pair<Node*, Node*> edge = edges[iproc][jproc][se];
12553 #ifdef PARANOID
12554  // Check that the edge has not been previously visited
12555  if (edge_done[edge])
12556  {
12557  std::stringstream error_message;
12558  error_message
12559  << "The shared edge between processor iproc and processor\n"
12560  << "jproc has been already visited, this is weird since the\n"
12561  << "edge should not be shared by other pair of processors\n"
12562  << "iproc: (" << iproc << ")\n"
12563  << "jproc: (" << jproc << ")\n"
12564  << "First node of edge: (" << edge.first->x(0) << ", "
12565  << edge.first->x(1) << ")\n"
12566  << "Second node of edge: (" << edge.second->x(0) << ", "
12567  << edge.second->x(1) << ")\n"
12568  << "Associated edge boundary id: ("
12569  << edge_boundary[iproc][jproc][se] << ")\n\n";
12570  throw OomphLibError(
12571  error_message.str(),
12572  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12573  OOMPH_EXCEPTION_LOCATION);
12574  }
12575 
12576  // Mark the edge as done
12577  edge_done[edge] = true;
12578  // Create the reversed version and include it too
12579  std::pair<Node*, Node*> rev_edge =
12580  std::make_pair(edge.second, edge.first);
12581  // Mark reversed edge as done
12582  edge_done[rev_edge] = true;
12583 #endif // #ifdef PARANOID
12584 
12585  // Get each of the nodes that conform the edge
12586  Node* left_node_pt = edge.first;
12587  Node* right_node_pt = edge.second;
12588 
12589  // Check if the left node has been already done
12590  if (!node_done[left_node_pt])
12591  {
12592  // Set the degree of the node to once since this is the
12593  // first time it has been found
12594  global_shared_node_degree[left_node_pt] = 1;
12595 
12596  } // if (!done_node[left_node_pt])
12597  else
12598  {
12599  // Increase the degree of the node
12600  global_shared_node_degree[left_node_pt]++;
12601  }
12602 
12603  // Check if the right node has been already done
12604  if (!node_done[right_node_pt])
12605  {
12606  // Set the degree of the node to once since this is the
12607  // first time it has been found
12608  global_shared_node_degree[right_node_pt] = 1;
12609  } // if (!done_node[right_node_pt])
12610  else
12611  {
12612  // Increase the degree of the node
12613  global_shared_node_degree[right_node_pt]++;
12614  }
12615 
12616  } // for (se < nshd_edges)
12617 
12618  } // for (jproc < nproc)
12619 
12620  } // for (iproc < nproc)
12621 
12622  // -----------------------------------------------------------------
12623  // Identify those nodes living on edges of original boundaries not
12624  // overlapped by a shared boundary
12625 
12626  // Mark the nodes on original boundaries not overlapped by shared
12627  // boundaries
12628  std::map<unsigned, std::map<Node*, bool>>
12629  node_on_bnd_not_overlapped_by_shd_bnd;
12630 
12631  // Loop over the edges of the original boundaries
12632  for (std::map<std::pair<Node*, Node*>, unsigned>::iterator it_map =
12633  elements_edges_on_boundary.begin();
12634  it_map != elements_edges_on_boundary.end();
12635  it_map++)
12636  {
12637  // Get the edge
12638  std::pair<Node*, Node*> edge_pair = (*it_map).first;
12639 
12640  // Is the edge overlaped by a shared boundary
12641  if (!overlapped_edge[edge_pair])
12642  {
12643  // Mark the nodes of the edge as being on an edge not overlaped
12644  // by a shared boundary on the boundary the edge is
12645  unsigned b = (*it_map).second;
12646 
12647  // Get the left node
12648  Node* left_node_pt = edge_pair.first;
12649  node_on_bnd_not_overlapped_by_shd_bnd[b][left_node_pt] = true;
12650 
12651  // Get the right node
12652  Node* right_node_pt = edge_pair.second;
12653  node_on_bnd_not_overlapped_by_shd_bnd[b][right_node_pt] = true;
12654 
12655  } // if (!overlapped_edge[edge_pair])
12656 
12657  } // Loop over edges to mark those nodes on overlaped edge by
12658  // shared boundaries
12659 
12660  // ------------------------------------------------------------------
12661  // Now create the shared polylines but including the degree of the
12662  // nodes as a nw stop condition for adding more edges to the side
12663  // or a root edge
12664  // ------------------------------------------------------------------
12665 
12666  // Storage for new created polylines with "each processor", non
12667  // sorted (shared polylines of the current processor only)
12668  Vector<Vector<TriangleMeshPolyLine*>> unsorted_polylines_pt(nproc);
12669 
12670  // Map that associates the shared boundary id with the list of
12671  // nodes that create it (shared boundary of the current processor
12672  // only)
12673  std::map<unsigned, std::list<Node*>> shared_bnd_id_to_sorted_list_node_pt;
12674 
12675  // Get maximum user boundary id and set the initial shared boundary
12676  // id
12677  unsigned shared_boundary_id_start = this->nboundary();
12678  Initial_shared_boundary_id = shared_boundary_id_start;
12679 
12680  // Aqui
12681 
12682  // Loop over the processors and get the shared edged between each
12683  // pair of processors
12684  for (unsigned iproc = 0; iproc < nproc; iproc++)
12685  {
12686  // Start from iproc + 1 to avoid checking with itself (there is
12687  // no shared edges between the same processor), and to avoid
12688  // double counting the edges and nodes (the shared edges between
12689  // processor (iproc, jproc) are the same as those between
12690  // processor jproc, iproc)
12691  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
12692  {
12693  // *************************************************************
12694  // THIRD PART
12695  // 1) Sort the edges (make them contiguous) so that they can
12696  // be used as the vertex coordinates that define a shared
12697  // boundary (polyline)
12698  // *************************************************************
12699  unsigned npolylines_counter = 0;
12700  const unsigned nedges = edges[iproc][jproc].size();
12701 
12702  // -----------------------------------------------------------
12703  // Compute all the SHARED POLYLINES
12704  // -----------------------------------------------------------
12705  // The number of sorted edges
12706  unsigned nsorted_edges = 0;
12707 
12708  // Keep track of the already done edges
12709  std::map<std::pair<Node*, Node*>, bool> edge_done;
12710 
12711  // Loop over all the edges to create all the polylines with
12712  // the current processors involved
12713  while (nsorted_edges < nedges)
12714  {
12715  // Temporaly storage for the elements associated to the
12716  // sorted edges
12717  std::list<FiniteElement*> tmp_boundary_element_pt;
12718  // Temporly storage for the face indexes on the element
12719  // that created the given edge
12720  std::list<int> tmp_face_index_element;
12721  // Get an initial pair of nodes to create an edge
12722  std::pair<Node*, Node*> edge;
12723 #ifdef PARANOID
12724  bool found_initial_edge = false;
12725 #endif
12726  int root_edge_bound_id = -1;
12727  unsigned iedge = 0;
12728  for (iedge = 0; iedge < nedges; iedge++)
12729  {
12730  edge = edges[iproc][jproc][iedge];
12731  // If not done then take it as initial edge
12732  if (!edge_done[edge])
12733  {
12734  // Get the boundary id that the edge may be overlapping
12735  root_edge_bound_id = edge_boundary[iproc][jproc][iedge];
12736 #ifdef PARANOID
12737  found_initial_edge = true;
12738 #endif
12739  nsorted_edges++;
12740  iedge++;
12741  break;
12742  } // if (!edge_done[edge])
12743  } // for (iedge < nedges)
12744 
12745 #ifdef PARANOID
12746  if (!found_initial_edge)
12747  {
12748  std::ostringstream error_message;
12749  error_message
12750  << "All the edge are already done, but the number of done\n"
12751  << "edges (" << nsorted_edges
12752  << ") is still less than the total\n"
12753  << "number of edges (" << nedges << ").\n";
12754  // << "----- Possible memory leak -----\n";
12755  throw OomphLibError(
12756  error_message.str(),
12757  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12758  OOMPH_EXCEPTION_LOCATION);
12759  }
12760 #endif
12761 
12762  // Storing for the sorting nodes extracted from the
12763  // edges. The sorted nodes are used to create a polyline
12764  std::list<Node*> sorted_nodes;
12765  sorted_nodes.clear();
12766 
12767  // The initial and final nodes of the list
12768  Node* first_node_pt = edge.first;
12769  Node* last_node_pt = edge.second;
12770 
12771  // Push back on the list the new edge (nodes)
12772  sorted_nodes.push_back(first_node_pt);
12773  sorted_nodes.push_back(last_node_pt);
12774 
12775  // Get the elements associated to the edge and store them
12776  // in the temporaly boundary elements storage
12777  tmp_boundary_element_pt.push_back(
12778  edge_element_pt[iproc][jproc][iedge - 1][0]);
12779  tmp_boundary_element_pt.push_back(
12780  edge_element_pt[iproc][jproc][iedge - 1][1]);
12781 
12782  // ... then get the face index of the element from where
12783  // the edge came from
12784  tmp_face_index_element.push_back(
12785  edge_element_face[iproc][jproc][iedge - 1][0]);
12786  tmp_face_index_element.push_back(
12787  edge_element_face[iproc][jproc][iedge - 1][1]);
12788 
12789  // Mark edge as done
12790  edge_done[edge] = true;
12791 
12792  // Continue iterating if a new node (that creates a new
12793  // edge) is added to the list, we have just added two nodes
12794  // (the first and last of the root edge)
12795  bool node_added = true;
12796 
12797  // Flags to indicate at which end the node was added (left
12798  // or right)
12799  bool node_added_to_the_left = true;
12800  bool node_added_to_the_right = true;
12801 
12802  // The nodes that create a shared boundary are obtained by
12803  // connecting the edges shared by the halo and haloed
12804  // elements. These edges are connected to left or right of
12805  // the shared boundary. Every time a new edge is added to
12806  // the left (or right), the most left (or right) node is
12807  // searched in the list of nodes of previous shared
12808  // boundaries, if the node is found then it is said to be
12809  // shared with another boundary and a connection to that
12810  // boundary needs to be specified. We stop adding edges
12811  // (and nodes) to the side where that nodes was found to be
12812  // shared. Note that the intersection (shared node) may be
12813  // with the same shared boundary
12814 
12815  // Flag to indicate a node was found to be shared with
12816  // another boundary at the left end (most left node) of the
12817  // shared boundary
12818  bool connection_to_the_left = false;
12819 
12820  // Flag to indicate a node was found to be shared with
12821  // another boundary at the right end (most right node) of
12822  // the shared boundary
12823  bool connection_to_the_right = false;
12824 
12825  // Flag to stop the adding of edges (and nodes) to the
12826  // current shared boundary
12827  bool current_polyline_has_connections_at_both_ends = false;
12828 
12829  // Store the boundary ids of the polylines to connect (only
12830  // used when the polyline was found to have a connection)
12831  // -1: Indicates no connection
12832  // -2: Indicates connection with itself
12833  // Any other value: Boundary id to connect
12834  int bound_id_connection_to_the_left = -1;
12835  int bound_id_connection_to_the_right = -1;
12836 
12837  // Get the degree of the first node
12838  const unsigned first_node_degree =
12839  global_shared_node_degree[first_node_pt];
12840 
12841  // Check if the nodes of the root edge have connections
12842  // ... to the left
12843  bound_id_connection_to_the_left = check_connections_of_polyline_nodes(
12844  element_in_processor_pt,
12845  root_edge_bound_id,
12846  overlapped_edge,
12847  node_on_bnd_not_overlapped_by_shd_bnd,
12848  sorted_nodes,
12849  shared_bnd_id_to_sorted_list_node_pt,
12850  first_node_degree,
12851  first_node_pt);
12852 
12853  // If there is a connection then set the
12854  // corresponding flag
12855  // (-1): No connection
12856  // (-2): Connection with itself
12857  // (-3): No connection, stop adding nodes
12858  // (other value): Boundary id
12859  if (bound_id_connection_to_the_left != -1)
12860  {
12861  connection_to_the_left = true;
12862  } // if (bound_id_connection_to_the_left != -1)
12863 
12864  // Get the degree of the last node
12865  const unsigned last_node_degree =
12866  global_shared_node_degree[last_node_pt];
12867 
12868  // Check if the nodes of the root edge have connections
12869  // ... to the right
12870  bound_id_connection_to_the_right =
12871  check_connections_of_polyline_nodes(
12872  element_in_processor_pt,
12873  root_edge_bound_id,
12874  overlapped_edge,
12875  node_on_bnd_not_overlapped_by_shd_bnd,
12876  sorted_nodes,
12877  shared_bnd_id_to_sorted_list_node_pt,
12878  last_node_degree,
12879  last_node_pt);
12880 
12881  // If there is a connection then set the
12882  // corresponding flag
12883  // (-1): No connection
12884  // (-2): Connection with itself
12885  // (other value): Boundary id
12886  if (bound_id_connection_to_the_right != -1)
12887  {
12888  connection_to_the_right = true;
12889  } // if (bound_id_connection_to_the_right != -1)
12890 
12891  // If the current shared boundary has connections at both
12892  // ends then stop the adding of nodes
12893  if (connection_to_the_left && connection_to_the_right)
12894  {
12895  current_polyline_has_connections_at_both_ends = true;
12896  }
12897 
12898  // Continue searching for more edges if
12899  // 1) A new node was added at the left or right of the list
12900  // 2) There are more edges to possible add
12901  // 3) The added node is not part of any other previous
12902  // shared polyline
12903  while (node_added && (nsorted_edges < nedges) &&
12904  !current_polyline_has_connections_at_both_ends)
12905  {
12906  // Start from the next edge since we have already added
12907  // the previous one as the initial edge (any previous
12908  // edge had to be added to previous polylines)
12909  for (unsigned iiedge = iedge; iiedge < nedges; iiedge++)
12910  {
12911  // Reset the flags for added nodes, to the left and right
12912  node_added = false;
12913  node_added_to_the_left = false;
12914  node_added_to_the_right = false;
12915  // Get the current edge
12916  edge = edges[iproc][jproc][iiedge];
12917  const int edge_bound_id = edge_boundary[iproc][jproc][iiedge];
12918 
12919  // We need to ensure to connect with edges that share
12920  // the same bound id or with those that has no boundary
12921  // id associated (the default -1 value), may apply
12922  // exclusively to internal boundaries
12923  if (!edge_done[edge] && (edge_bound_id == root_edge_bound_id))
12924  {
12925  // Get each individual node
12926  Node* left_node_pt = edge.first;
12927  Node* right_node_pt = edge.second;
12928 
12929  // Pointer to the new added node
12930  Node* new_added_node_pt = 0;
12931 
12932  // Is the node to be added to the left?
12933  if (left_node_pt == first_node_pt && !connection_to_the_left)
12934  {
12935  // Push front the new node
12936  sorted_nodes.push_front(right_node_pt);
12937  // Update the new added node and the first node
12938  new_added_node_pt = first_node_pt = right_node_pt;
12939  // Set the node added flag to true
12940  node_added = true;
12941  // Indicate the node was added to the left
12942  node_added_to_the_left = true;
12943  }
12944  // Is the node to be added to the right?
12945  else if (left_node_pt == last_node_pt &&
12946  !connection_to_the_right)
12947  {
12948  // Push back the new node
12949  sorted_nodes.push_back(right_node_pt);
12950  // Update the new added node and the last node
12951  new_added_node_pt = last_node_pt = right_node_pt;
12952  // Set the node added flag to true
12953  node_added = true;
12954  // Indicate the node was added to the right
12955  node_added_to_the_right = true;
12956  }
12957  // Is the node to be added to the left?
12958  else if (right_node_pt == first_node_pt &&
12959  !connection_to_the_left)
12960  {
12961  // Push front the new node
12962  sorted_nodes.push_front(left_node_pt);
12963  // Update the new added node and the first node
12964  new_added_node_pt = first_node_pt = left_node_pt;
12965  // Set the node added flag to true
12966  node_added = true;
12967  // Indicate the node was added to the left
12968  node_added_to_the_left = true;
12969  }
12970  // Is the node to be added to the right?
12971  else if (right_node_pt == last_node_pt &&
12972  !connection_to_the_right)
12973  {
12974  // Push back the new node
12975  sorted_nodes.push_back(left_node_pt);
12976  // Update the new added node and the last node
12977  new_added_node_pt = last_node_pt = left_node_pt;
12978  // Set the node added flag to true
12979  node_added = true;
12980  // Indicate the node was added to the right
12981  node_added_to_the_right = true;
12982  }
12983 
12984  // If we added a new node then we need to check if
12985  // that node has been already added in other shared
12986  // boundaries (which may define a connection)
12987  if (node_added)
12988  {
12989  // Mark as done only if one of its nodes has been
12990  // added to the list
12991  edge_done[edge] = true;
12992  nsorted_edges++;
12993 
12994  // Get the degree of the added node
12995  const unsigned added_node_degree =
12996  global_shared_node_degree[new_added_node_pt];
12997 
12998  if (node_added_to_the_left)
12999  {
13000  // Add the bulk elements
13001  tmp_boundary_element_pt.push_front(
13002  edge_element_pt[iproc][jproc][iiedge][1]);
13003  tmp_boundary_element_pt.push_front(
13004  edge_element_pt[iproc][jproc][iiedge][0]);
13005  // Add the face elements
13006  tmp_face_index_element.push_front(
13007  edge_element_face[iproc][jproc][iiedge][1]);
13008  tmp_face_index_element.push_front(
13009  edge_element_face[iproc][jproc][iiedge][0]);
13010  }
13011 
13012  if (node_added_to_the_right)
13013  {
13014  // Add the bulk elements
13015  tmp_boundary_element_pt.push_back(
13016  edge_element_pt[iproc][jproc][iiedge][0]);
13017  tmp_boundary_element_pt.push_back(
13018  edge_element_pt[iproc][jproc][iiedge][1]);
13019  // Add the face elements
13020  tmp_face_index_element.push_back(
13021  edge_element_face[iproc][jproc][iiedge][0]);
13022  tmp_face_index_element.push_back(
13023  edge_element_face[iproc][jproc][iiedge][1]);
13024  }
13025 
13026  // Based on which side the node was added, look for
13027  // connections on that side
13028 
13029  // Verify for connections to the left (we need to
13030  // check for the connection variable too, since
13031  // after a connection has been done we no longer
13032  // need to verify for this condition)
13033  if (node_added_to_the_left && !connection_to_the_left)
13034  {
13035  // Check for connection
13036  bound_id_connection_to_the_left =
13037  check_connections_of_polyline_nodes(
13038  element_in_processor_pt,
13039  root_edge_bound_id,
13040  overlapped_edge,
13041  node_on_bnd_not_overlapped_by_shd_bnd,
13042  sorted_nodes,
13043  shared_bnd_id_to_sorted_list_node_pt,
13044  added_node_degree,
13045  new_added_node_pt);
13046 
13047  // If there is a connection then set the
13048  // corresponding flag
13049  // (-1): No connection
13050  // (-2): Connection with itself
13051  // (other value): Boundary id
13052  if (bound_id_connection_to_the_left != -1)
13053  {
13054  connection_to_the_left = true;
13055  } // if (bound_id_connection_to_the_left != -1)
13056 
13057  } // if (node_added_to_the_left &&
13058  // !connection_to_the_left)
13059 
13060  // Verify for connections to the right (we need to
13061  // check for the connection variable too, since
13062  // after a connection has been done we no longer
13063  // need to verify for this condition)
13064  if (node_added_to_the_right && !connection_to_the_right)
13065  {
13066  // Check for connection
13067  bound_id_connection_to_the_right =
13068  check_connections_of_polyline_nodes(
13069  element_in_processor_pt,
13070  root_edge_bound_id,
13071  overlapped_edge,
13072  node_on_bnd_not_overlapped_by_shd_bnd,
13073  sorted_nodes,
13074  shared_bnd_id_to_sorted_list_node_pt,
13075  added_node_degree,
13076  new_added_node_pt);
13077 
13078  // If there is a connection then set the
13079  // corresponding flag
13080  // (-1): No connection
13081  // (-2): Connection with itself
13082  // (other value): Boundary id
13083  if (bound_id_connection_to_the_right != -1)
13084  {
13085  connection_to_the_right = true;
13086  } // if (bound_id_connection_to_the_right != -1)
13087 
13088  } // if (node_added_to_the_right &&
13089  // !connection_to_the_right)
13090 
13091  // If the current shared boundary has connections
13092  // at both ends then stop the adding of nodes
13093  if (connection_to_the_left && connection_to_the_right)
13094  {
13095  current_polyline_has_connections_at_both_ends = true;
13096  }
13097 
13098  // Break the for and re-start to look more edges to
13099  // the left or right
13100  break;
13101 
13102  } // if (node_added)
13103 
13104  } // if (!edge_done[edge])
13105  } // for (iiedge < nedges)
13106 
13107  } // while(node_added && (nsorted_edges < nedges)
13108  // && !current_polyline_has_connections_at_both_ends)
13109 
13110  // ------------------------------------------------------------
13111  // If the sorted nodes of the shared polyline create a loop
13112  // it is necessary to break it by creating as many
13113  // polylines as required
13114 
13115  // Change the list to a vector representation of the
13116  // boundary elements and the face indexes
13117 
13118  // Get the number of boundary elements
13119  const unsigned n_bnd_ele = tmp_boundary_element_pt.size();
13120 
13121  // Storage for the boundary elements and face indexes
13122  Vector<FiniteElement*> tmp_bnd_ele_pt(n_bnd_ele);
13123  Vector<int> tmp_face_idx_ele(n_bnd_ele);
13124  // Helper counter
13125  unsigned help_counter = 0;
13126  // Fill the data structures
13127  for (std::list<FiniteElement*>::iterator it_bnd_ele =
13128  tmp_boundary_element_pt.begin();
13129  it_bnd_ele != tmp_boundary_element_pt.end();
13130  it_bnd_ele++)
13131  {
13132  tmp_bnd_ele_pt[help_counter++] = (*it_bnd_ele);
13133  }
13134 
13135  // Restart counter
13136  help_counter = 0;
13137  for (std::list<int>::iterator it_face_idx =
13138  tmp_face_index_element.begin();
13139  it_face_idx != tmp_face_index_element.end();
13140  it_face_idx++)
13141  {
13142  tmp_face_idx_ele[help_counter++] = (*it_face_idx);
13143  }
13144 
13145  // Store the nodes for the new shared polylines without
13146  // loops
13147  Vector<std::list<Node*>> final_sorted_nodes_pt;
13148  // Store the boundary elements of the shared polyline
13149  // without loops
13150  Vector<Vector<FiniteElement*>> final_boundary_element_pt;
13151  // Face indexes of the boundary elements without loops
13152  Vector<Vector<int>> final_face_index_element;
13153  // Connection flags (to the left) of the shared boundaries
13154  // without loops
13155  Vector<int> final_bound_id_connection_to_the_left;
13156  // Connection flags (to the right) of the shared boundaries
13157  // without loops
13158  Vector<int> final_bound_id_connection_to_the_right;
13159 
13160  // Break any possible loop created by the shared polyline
13161  break_loops_on_shared_polyline_helper(
13162  shared_boundary_id_start,
13163  sorted_nodes,
13164  tmp_bnd_ele_pt,
13165  tmp_face_idx_ele,
13166  bound_id_connection_to_the_left,
13167  bound_id_connection_to_the_right,
13168  final_sorted_nodes_pt,
13169  final_boundary_element_pt,
13170  final_face_index_element,
13171  final_bound_id_connection_to_the_left,
13172  final_bound_id_connection_to_the_right);
13173 
13174  // Get the number of final sorted nodes
13175  const unsigned n_final_sorted_nodes = final_sorted_nodes_pt.size();
13176 
13177  // Loop over the list of final sorted nodes
13178  for (unsigned i = 0; i < n_final_sorted_nodes; i++)
13179  {
13180  // --------------------------------------------------------
13181  // Associate the list of sorted nodes with the boundary id
13182  // of the shared boundary that is going to be crated
13183  shared_bnd_id_to_sorted_list_node_pt[shared_boundary_id_start] =
13184  final_sorted_nodes_pt[i];
13185 
13186  // Create the shared polyline and fill the data
13187  // structured associated to it
13188  create_shared_polyline(my_rank,
13189  shared_boundary_id_start,
13190  iproc,
13191  jproc,
13192  final_sorted_nodes_pt[i],
13193  root_edge_bound_id,
13194  final_boundary_element_pt[i],
13195  final_face_index_element[i],
13196  unsorted_polylines_pt,
13197  final_bound_id_connection_to_the_left[i],
13198  final_bound_id_connection_to_the_right[i]);
13199 
13200  // Increase the register for the number of created shared
13201  // polylines
13202  npolylines_counter++;
13203 
13204  // Increase the boundary id (the one that will be used by
13205  // the next shared boundary)
13206  shared_boundary_id_start++;
13207 
13208  } // for (i < n_final_sorted_nodes)
13209 
13210  } // while(nsorted_edges < nedges);
13211 
13212  } // for (jproc < nproc)
13213 
13214  // We already have all the shared polylines (shared boundaries)
13215  // of processor iproc with processor jproc. Now we sort them so
13216  // that they be contiguous and can create polygons.
13217 
13218  // If there are polylines to be sorted then sort them
13219  if (unsorted_polylines_pt[iproc].size() > 0)
13220  {
13221  // Now that we have all the new unsorted polylines on "iproc"
13222  // processor it is time to sort them so they be all contiguous
13223  sort_polylines_helper(unsorted_polylines_pt[iproc],
13224  output_polylines_pt[iproc]);
13225  }
13226 
13227 #ifdef PARANOID
13228  const unsigned nunsorted_polylines_iproc =
13229  unsorted_polylines_pt[iproc].size();
13230 
13231  // Verify that all the polylines have been sorted
13232  unsigned tmp_ntotal_polylines = 0;
13233  // Count the total number of sorted polylines
13234  for (unsigned ii = 0; ii < output_polylines_pt[iproc].size(); ii++)
13235  {
13236  tmp_ntotal_polylines += output_polylines_pt[iproc][ii].size();
13237  }
13238  if (tmp_ntotal_polylines != nunsorted_polylines_iproc)
13239  {
13240  std::ostringstream error_message;
13241  error_message << " The total number of unsorted polylines ("
13242  << nunsorted_polylines_iproc
13243  << ") in common with\nprocessor (" << iproc
13244  << ") is different from the total number of sorted "
13245  << "polylines (" << tmp_ntotal_polylines
13246  << ") with\nthe same "
13247  << "proessor\n";
13248  throw OomphLibError(error_message.str(),
13249  OOMPH_CURRENT_FUNCTION,
13250  OOMPH_EXCEPTION_LOCATION);
13251  } // if (tmp_ntotal_polylines != nunsorted_polylines_iproc)
13252 #endif
13253 
13254  } // for (iproc < nproc)
13255 
13256  // Establish the last used boundary id
13257  this->Final_shared_boundary_id = shared_boundary_id_start;
13258  }
13259 
13260  // ======================================================================
13261  // Break any possible loop created by the sorted list of nodes
13262  // that is used to create a new shared polyline
13263  // ======================================================================
13264  template<class ELEMENT>
13266  const unsigned& initial_shd_bnd_id,
13267  std::list<Node*>& input_nodes,
13268  Vector<FiniteElement*>& input_boundary_element_pt,
13269  Vector<int>& input_face_index_element,
13270  const int& input_connect_to_the_left,
13271  const int& input_connect_to_the_right,
13272  Vector<std::list<Node*>>& output_sorted_nodes_pt,
13273  Vector<Vector<FiniteElement*>>& output_boundary_element_pt,
13274  Vector<Vector<int>>& output_face_index_element,
13275  Vector<int>& output_connect_to_the_left,
13276  Vector<int>& output_connect_to_the_right)
13277  {
13278  // Get the left and right node of the current list of sorted nodes
13279  Node* left_node_pt = input_nodes.front();
13280  Node* right_node_pt = input_nodes.back();
13281 
13282  // Temporary storage for list of nodes, boundary elements and face
13283  // element's indexes
13284  Vector<std::list<Node*>> tmp_sub_nodes;
13285  Vector<Vector<FiniteElement*>> tmp_sub_bnd_ele_pt;
13286  Vector<Vector<int>> tmp_sub_face_idx_ele;
13287 
13288  // Iterator for the list of input nodes
13289  std::list<Node*>::iterator it = input_nodes.begin();
13290 
13291  // Counter
13292  unsigned counter = 0;
13293 
13294  // Loop while not all nodes have been done
13295  while (it != input_nodes.end())
13296  {
13297  // Check if the current node is the final one
13298  it++;
13299  // Is the current node the final node?
13300  if (it == input_nodes.end())
13301  {
13302  // Break, add no more nodes
13303  break;
13304  }
13305  else
13306  {
13307  // Restore the iterator
13308  it--;
13309  }
13310 
13311  // Get a list of nonrepeated nodes
13312  std::list<Node*> sub_nodes;
13313  // The temporary vector of boundary elements associated with the
13314  // nodes
13315  Vector<FiniteElement*> sub_bnd_ele_pt;
13316  // The temporary vector of face indexes associated with the
13317  // boundary elements
13318  Vector<int> sub_face_idx_ele;
13319 
13320  // Add the current node to the list
13321  sub_nodes.push_back(*it);
13322 
13323  // Add nodes until found a repeated node (the left or right
13324  // node) or until reaching the end of the list of nodes
13325  do
13326  {
13327  // Go to the next node
13328  ++it;
13329 
13330  // Add the new node
13331  sub_nodes.push_back((*it));
13332 
13333  // Add the boundary elements
13334  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter]);
13335  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter + 1]);
13336 
13337  // Add the face indexes
13338  sub_face_idx_ele.push_back(input_face_index_element[counter]);
13339  sub_face_idx_ele.push_back(input_face_index_element[counter + 1]);
13340 
13341  // Increase the counter
13342  counter += 2;
13343 
13344  // Continue adding until reaching a repeated node or the end
13345  // of the list of nodes
13346  } while ((*it) != left_node_pt && (*it) != right_node_pt &&
13347  it != input_nodes.end());
13348 
13349  // Add the sub-set of nodes to the temporary storage
13350  tmp_sub_nodes.push_back(sub_nodes);
13351  // Add the face elements to the temporary storage
13352  tmp_sub_bnd_ele_pt.push_back(sub_bnd_ele_pt);
13353  // Add the face indexes to the temporary storage
13354  tmp_sub_face_idx_ele.push_back(sub_face_idx_ele);
13355 
13356  } // while((*it) != input_nodes.end())
13357 
13358  // --------------------------------------------------
13359  // Now create as many shared boundaries as required
13360 
13361  // Get the number of sub-list of nodes created
13362  const unsigned n_sub_list = tmp_sub_nodes.size();
13363 
13364 #ifdef PARANOID
13365  if (n_sub_list > 3)
13366  {
13367  std::stringstream error_message;
13368  error_message
13369  << "The number of sub-list of nodes created from the shared\n"
13370  << "polyline with loops was (" << n_sub_list << ").\n"
13371  << "We can only handle up to three sub-list of nodes\n";
13372  throw OomphLibError(
13373  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
13374  }
13375 #endif
13376 
13377  // If there is only one list it may be because there are no loops or
13378  // there is only one loop (a circle)
13379  if (n_sub_list == 1 && (left_node_pt != right_node_pt))
13380  {
13381  // There are no loops, return just after filling the data
13382  // structures
13383 
13384  // This is the base case used most of the times
13385 
13386  // Set the vector of lists of nodes
13387  output_sorted_nodes_pt = tmp_sub_nodes;
13388  // Set the vector of boundary elements
13389  output_boundary_element_pt = tmp_sub_bnd_ele_pt;
13390  // Set the vector of face indexes
13391  output_face_index_element = tmp_sub_face_idx_ele;
13392 
13393  // Set the connection flags, change them by the proper connection
13394  // flag
13395 
13396 #ifdef PARANOID
13397  if (input_connect_to_the_left == -2)
13398  {
13399  std::stringstream error_message;
13400  error_message
13401  << "The connection flag to the left (" << input_connect_to_the_left
13402  << ") indicates a connection\n"
13403  << "with the same polyline.\n However, only one sub-polyline was "
13404  << "found and no loop\nwas identified\n\n";
13405  throw OomphLibError(error_message.str(),
13406  OOMPH_CURRENT_FUNCTION,
13407  OOMPH_EXCEPTION_LOCATION);
13408  }
13409 #endif
13410 
13411  // The left connection flag
13412  if (input_connect_to_the_left == -3)
13413  {
13414  output_connect_to_the_left.push_back(-1);
13415  }
13416  else
13417  {
13418  output_connect_to_the_left.push_back(input_connect_to_the_left);
13419  }
13420 
13421 #ifdef PARANOID
13422  if (input_connect_to_the_right == -2)
13423  {
13424  std::stringstream error_message;
13425  error_message
13426  << "The connection flag to the right (" << input_connect_to_the_right
13427  << ") indicates a connection\n"
13428  << "with the same polyline.\n However, only one sub-polyline was "
13429  << "found and no loop\nwas identified\n\n";
13430  throw OomphLibError(
13431  error_message.str(),
13432  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13433  OOMPH_EXCEPTION_LOCATION);
13434  }
13435 #endif
13436 
13437  // The right connection flag
13438  if (input_connect_to_the_right == -3)
13439  {
13440  output_connect_to_the_right.push_back(-1);
13441  }
13442  else
13443  {
13444  output_connect_to_the_right.push_back(input_connect_to_the_right);
13445  }
13446 
13447  // Return inmediately
13448  return;
13449  }
13450 
13451  // The temporary storage for the shared boundary id
13452  unsigned tmp_shd_bnd_id = initial_shd_bnd_id;
13453 
13454  // -----------------------------------------------------------------
13455  // Check all the sub-list of nodes and create two shared boundaries
13456  // from those that make a loop (circle)
13457 
13458  // -----------------------------------------------------------
13459  // Get the left and right node of the first sub-list of nodes
13460  Node* left_sub_node_pt = tmp_sub_nodes[0].front();
13461  Node* right_sub_node_pt = tmp_sub_nodes[0].back();
13462 
13463  // Check if the sub-list of nodes creates a loop (circle)
13464  if (left_sub_node_pt == right_sub_node_pt)
13465  {
13466  // We need to create two shared polylines and therefore increase
13467  // the shared boundary id by two
13468 
13469  // The first and second half of nodes
13470  std::list<Node*> first_half_node_pt;
13471  std::list<Node*> second_half_node_pt;
13472  // The first and second half of boundary elements
13473  Vector<FiniteElement*> first_half_ele_pt;
13474  Vector<FiniteElement*> second_half_ele_pt;
13475  // The first and second half of face indexes
13476  Vector<int> first_half_face_idx;
13477  Vector<int> second_half_face_idx;
13478 
13479  // Get the number of sub-nodes in the sub-list of nodes
13480  const unsigned n_sub_nodes = tmp_sub_nodes[0].size();
13481 
13482  // The number of sub-nodes for the first half of the shared
13483  // boundary
13484  const unsigned n_sub_nodes_half =
13485  static_cast<unsigned>(n_sub_nodes / 2.0);
13486 
13487  // Copy as many sub-nodes for the first half of the sub-polyline
13488 
13489  // Iterator to loop over the nodes
13490  std::list<Node*>::iterator it_sub = tmp_sub_nodes[0].begin();
13491 
13492  // Add the first node
13493  first_half_node_pt.push_back(*it_sub);
13494 
13495  // Skip the first node
13496  it_sub++;
13497 
13498  // Counter
13499  unsigned counter_nodes = 0;
13500  unsigned counter2 = 0;
13501 
13502  // Loop to copy the nodes
13503  for (; it_sub != tmp_sub_nodes[0].end(); it_sub++)
13504  {
13505  // Add the sub-node to the first half
13506  first_half_node_pt.push_back(*it_sub);
13507 
13508  // Add the boundary elements of the first half
13509  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
13510  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2 + 1]);
13511  // Add the face indexes of the first half
13512  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
13513  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2 + 1]);
13514 
13515  // Increase the counter of added nodes
13516  counter_nodes++;
13517 
13518  // Increase the other counter
13519  counter2 += 2;
13520 
13521  if (counter_nodes == n_sub_nodes_half)
13522  {
13523  // Stop adding to the first half of nodes
13524  break;
13525  }
13526 
13527  } // Copy the first half of nodes
13528 
13529  // The second half
13530 
13531  // Add the first node of the second half
13532  second_half_node_pt.push_back(*it_sub);
13533 
13534  // Skip the first node of the second half
13535  it_sub++;
13536 
13537  // Loop to copy the nodes
13538  for (; it_sub != tmp_sub_nodes[0].end(); it_sub++)
13539  {
13540  // Add the sub-node to the first half
13541  second_half_node_pt.push_back(*it_sub);
13542 
13543  // Add the boundary elements of the first half
13544  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
13545  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2 + 1]);
13546  // Add the face indexes of the first half
13547  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
13548  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2 + 1]);
13549 
13550  // Increase the other counter
13551  counter2 += 2;
13552 
13553  } // Copy the second half of nodes
13554 
13555  // Add the sub-list of nodes to the vector of lists of nodes
13556  output_sorted_nodes_pt.push_back(first_half_node_pt);
13557  output_sorted_nodes_pt.push_back(second_half_node_pt);
13558  // Add the sub-vector of elements to the vector of boundary
13559  // elements
13560  output_boundary_element_pt.push_back(first_half_ele_pt);
13561  output_boundary_element_pt.push_back(second_half_ele_pt);
13562  // Add the sub-vector of face indexes to the vector of face
13563  // indexes
13564  output_face_index_element.push_back(first_half_face_idx);
13565  output_face_index_element.push_back(second_half_face_idx);
13566 
13567  // Set the connection flags, change them by the proper connection
13568  // flag
13569 
13570  // ----------------------------------------------------------------
13571  // Connections flags for the first half
13572 
13573  // The left connection flag
13574 
13575  // Connected with nothing but required to stop adding nodes
13576  if (input_connect_to_the_left == -3)
13577  {
13578  // Set connected to nothing
13579  output_connect_to_the_left.push_back(-1);
13580  }
13581  // Connected with itself
13582  else if (input_connect_to_the_left == -2)
13583  {
13584  // Set connected to nothing, this is the base node
13585  output_connect_to_the_left.push_back(-1);
13586  }
13587  else
13588  {
13589  // Any other value keep it
13590  output_connect_to_the_left.push_back(input_connect_to_the_left);
13591  }
13592 
13593  // The right connection flag
13594 
13595  // Set connected to nothing, this is the base node
13596  output_connect_to_the_right.push_back(-1);
13597 
13598  // Increase the shared boundary id
13599  tmp_shd_bnd_id++;
13600 
13601  // ----------------------------------------------------------------
13602  // Connections flags for the second half
13603 
13604  // The left connection flag
13605 
13606  // Set connected to the previous boundary
13607  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
13608 
13609  // The right connection flag
13610 
13611  // Are we in the last sub-list of nodes, if that is the case we
13612  // need to respect the flag assigned to the right
13613  if (n_sub_list == 1)
13614  {
13615  if (input_connect_to_the_right == -3)
13616  {
13617  // Set connected to the previous shared boundary id
13618  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13619  }
13620  else if (input_connect_to_the_right == -2)
13621  {
13622  // Set connected to the previous shared boundary id
13623  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13624  }
13625  else if (input_connect_to_the_right == -1)
13626  {
13627  // Set connected to the previous shared boundary id
13628  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13629  }
13630  else
13631  {
13632  // Any other value keep it
13633  output_connect_to_the_right.push_back(input_connect_to_the_right);
13634  }
13635  } // if (n_sub_list == 1)
13636  else
13637  {
13638  // Set connected to the previous shared boundary id
13639  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13640  }
13641 
13642  // Increase the shared boundary id
13643  tmp_shd_bnd_id++;
13644 
13645  } // if (left_sub_node_pt == right_sub_node_pt)
13646  else
13647  {
13648  // No need to create two boundaries, create only one with the
13649  // sub-list of nodes
13650 
13651  // Add the sub-list of nodes to the vector of lists of nodes
13652  output_sorted_nodes_pt.push_back(tmp_sub_nodes[0]);
13653  // Add the sub-vector of elements to the vector of boundary
13654  // elements
13655  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[0]);
13656  // Add the sub-vector of face indexes to the vector of face
13657  // indexes
13658  output_face_index_element.push_back(tmp_sub_face_idx_ele[0]);
13659 
13660  // Set the connection flags, change them by the proper connection
13661  // flag
13662 
13663  // The left connection flag
13664 
13665  // Connected with nothing but required to stop adding nodes
13666  if (input_connect_to_the_left == -3)
13667  {
13668  // Set to connected to nothing
13669  output_connect_to_the_left.push_back(-1);
13670  }
13671  // Connected with itself
13672  else if (input_connect_to_the_left == -2)
13673  {
13674  // Set connected to the next shared polyline id
13675  output_connect_to_the_left.push_back(tmp_shd_bnd_id + 1);
13676  }
13677  else
13678  {
13679  // Any other value keep it
13680  output_connect_to_the_left.push_back(input_connect_to_the_left);
13681  }
13682 
13683  // The right connection flag
13684 
13685  // Set connected to the next shared polyline id
13686  output_connect_to_the_right.push_back(tmp_shd_bnd_id + 1);
13687 
13688  // Increase the shared boundary id by one
13689  tmp_shd_bnd_id++;
13690 
13691  } // else if (left_sub_node_pt == right_sub_node_pt)
13692 
13693  // At least two sub-list of nodes were created
13694  if (n_sub_list > 1)
13695  {
13696  // ------------------------------------------------------------
13697  // Get the left and right node of the second sub-list of nodes
13698  left_sub_node_pt = tmp_sub_nodes[1].front();
13699  right_sub_node_pt = tmp_sub_nodes[1].back();
13700 
13701  // Check if the sub-list of nodes creates a loop (circle)
13702  if (left_sub_node_pt == right_sub_node_pt)
13703  {
13704  // We need to create two shared polylines and therefore increase
13705  // the shared boundary id by two
13706 
13707  // The first and second half of nodes
13708  std::list<Node*> first_half_node_pt;
13709  std::list<Node*> second_half_node_pt;
13710  // The first and second half of boundary elements
13711  Vector<FiniteElement*> first_half_ele_pt;
13712  Vector<FiniteElement*> second_half_ele_pt;
13713  // The first and second half of face indexes
13714  Vector<int> first_half_face_idx;
13715  Vector<int> second_half_face_idx;
13716 
13717  // Get the number of sub-nodes in the sub-list of nodes
13718  const unsigned n_sub_nodes = tmp_sub_nodes[1].size();
13719 
13720  // The number of sub-nodes for the first half of the shared
13721  // boundary
13722  const unsigned n_sub_nodes_half =
13723  static_cast<unsigned>(n_sub_nodes / 2.0);
13724 
13725  // Copy as many sub-nodes for the first half of the sub-polyline
13726 
13727  // Iterator to loop over the nodes
13728  std::list<Node*>::iterator it_sub = tmp_sub_nodes[1].begin();
13729 
13730  // Add the first node
13731  first_half_node_pt.push_back(*it_sub);
13732 
13733  // Skip the first node
13734  it_sub++;
13735 
13736  // Counter
13737  unsigned counter_nodes = 0;
13738  unsigned counter2 = 0;
13739 
13740  // Loop to copy the nodes
13741  for (; it_sub != tmp_sub_nodes[1].end(); it_sub++)
13742  {
13743  // Add the sub-node to the first half
13744  first_half_node_pt.push_back(*it_sub);
13745  // Add the boundary elements of the first half
13746  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2]);
13747  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2 + 1]);
13748  // Add the face indexes of the first half
13749  first_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2]);
13750  first_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2 + 1]);
13751 
13752  // Increase the counter of added nodes
13753  counter_nodes++;
13754 
13755  // Increase the other counter
13756  counter2 += 2;
13757 
13758  if (counter_nodes == n_sub_nodes_half)
13759  {
13760  // Stop adding to the first half of nodes
13761  break;
13762  }
13763 
13764  } // Copy the first half of nodes
13765 
13766  // The second half
13767 
13768  // Add the first node of the second half
13769  second_half_node_pt.push_back(*it_sub);
13770 
13771  // Skip the first node of the second half
13772  it_sub++;
13773 
13774  // Loop to copy the nodes
13775  for (; it_sub != tmp_sub_nodes[1].end(); it_sub++)
13776  {
13777  // Add the sub-node to the first half
13778  second_half_node_pt.push_back(*it_sub);
13779  // Add the boundary elements of the first half
13780  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2]);
13781  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2 + 1]);
13782  // Add the face indexes of the first half
13783  second_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2]);
13784  second_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2 + 1]);
13785 
13786  // Increase the other counter
13787  counter2 += 2;
13788 
13789  } // Copy the second half of nodes
13790 
13791  // Add the sub-list of nodes to the vector of lists of nodes
13792  output_sorted_nodes_pt.push_back(first_half_node_pt);
13793  output_sorted_nodes_pt.push_back(second_half_node_pt);
13794  // Add the sub-vector of elements to the vector of boundary
13795  // elements
13796  output_boundary_element_pt.push_back(first_half_ele_pt);
13797  output_boundary_element_pt.push_back(second_half_ele_pt);
13798  // Add the sub-vector of face indexes to the vector of face
13799  // indexes
13800  output_face_index_element.push_back(first_half_face_idx);
13801  output_face_index_element.push_back(second_half_face_idx);
13802 
13803  // Set the connection flags, change them by the proper
13804  // connection flag
13805 
13806  // --------------------------------------
13807  // Connections flags for the first half
13808 
13809  // The left connection flag
13810 
13811  // Connected to the previous boundary
13812  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
13813 
13814  // The right connection flag
13815 
13816  // Set connected to nothing, this is the base node
13817  output_connect_to_the_right.push_back(-1);
13818 
13819  // Increase the shared boundary id
13820  tmp_shd_bnd_id++;
13821 
13822  // --------------------------------------
13823  // Connections flags for the second half
13824 
13825  // The left connection flag
13826 
13827  // Set connected to the previous boundary
13828  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
13829 
13830  // The right connection flag
13831 
13832  // Are we in the last sub-list of nodes, if that is the case we
13833  // need to respect the flag assigned to the right
13834  if (n_sub_list == 2)
13835  {
13836  // Connected with nothing
13837  if (input_connect_to_the_right == -1)
13838  {
13839  // Set connected to the previous shared boundary
13840  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13841  }
13842  // Connected with the same boundary
13843  else if (input_connect_to_the_right == -2)
13844  {
13845  // Set connected to the previous shared boundary
13846  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13847  }
13848  // Connetted with nothing but stop adding nodes
13849  else if (input_connect_to_the_right == -3)
13850  {
13851  // Set connected to the previous shared boundary
13852  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13853  }
13854  else
13855  {
13856  // Any other value keep it
13857  output_connect_to_the_right.push_back(input_connect_to_the_right);
13858  }
13859 
13860  // Increase the shared boundary id
13861  tmp_shd_bnd_id++;
13862 
13863  } // if (n_sub_list == 2)
13864 #ifdef PARANOID
13865  else
13866  {
13867  std::stringstream error_message;
13868  error_message
13869  << "The second sub-list of nodes creates a loop but this is not\n"
13870  << "the last list of sub-nodes.\n"
13871  << "This configuration is not supported\n";
13872  throw OomphLibError(
13873  error_message.str(),
13874  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13875  OOMPH_EXCEPTION_LOCATION);
13876  }
13877 #endif
13878 
13879  } // if (left_sub_node_pt == right_sub_node_pt)
13880  else
13881  {
13882  // No need to create two boundaries, create only one with the
13883  // sub-list of nodes
13884 
13885  // Add the sub-list of nodes to the vector of lists of nodes
13886  output_sorted_nodes_pt.push_back(tmp_sub_nodes[1]);
13887  // Add the sub-vector of elements to the vector of boundary
13888  // elements
13889  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[1]);
13890  // Add the sub-vector of face indexes to the vector of face
13891  // indexes
13892  output_face_index_element.push_back(tmp_sub_face_idx_ele[1]);
13893 
13894  // Set the connection flags, change them by the proper connection
13895  // flag
13896 
13897  // The left connection flag
13898 
13899  // Set connected to the previous shared boundary id
13900  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
13901 
13902  // The right connection flag
13903 
13904  // Are we in the last sub-list of nodes, if that is the case we
13905  // need to respect the flag assigned to the right
13906  if (n_sub_list == 2)
13907  {
13908  // Connected with nothing but required to stop adding nodes
13909  if (input_connect_to_the_right == -3)
13910  {
13911  // Set to connected to nothing
13912  output_connect_to_the_right.push_back(-1);
13913  }
13914 #ifdef PARANOID
13915  // Connected with itself
13916  else if (input_connect_to_the_right == -2)
13917  {
13918  std::stringstream error_message;
13919  error_message
13920  << "The connection flag to the right ("
13921  << input_connect_to_the_right << ") indicates a connection\n"
13922  << "with the same polyline.\n However, the second sub-list of\n"
13923  << "nodes was found not making a loop so no connection with\n"
13924  << "itself should be marked\n\n";
13925  throw OomphLibError(
13926  error_message.str(),
13927  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13928  OOMPH_EXCEPTION_LOCATION);
13929  }
13930 #endif
13931  else
13932  {
13933  // Any other value keep it
13934  output_connect_to_the_right.push_back(input_connect_to_the_right);
13935  }
13936  } // if (n_sub_list == 2)
13937  else
13938  {
13939  // Set connected to the next shared boundary id
13940  output_connect_to_the_right.push_back(tmp_shd_bnd_id + 1);
13941  } // else if (n_sub_list == 2)
13942 
13943  // Increase the shared boundary id by one
13944  tmp_shd_bnd_id++;
13945 
13946  } // if (left_sub_node_pt == right_sub_node_pt)
13947 
13948  } // if (n_sub_list > 1)
13949 
13950  // Three sub-list of nodes were created
13951  if (n_sub_list > 2)
13952  {
13953  // ------------------------------------------------------------
13954  // Get the left and right node of the third sub-list of nodes
13955  left_sub_node_pt = tmp_sub_nodes[2].front();
13956  right_sub_node_pt = tmp_sub_nodes[2].back();
13957 
13958  // Check if the sub-list of nodes creates a loop (circle)
13959  if (left_sub_node_pt == right_sub_node_pt)
13960  {
13961  // We need to create two shared polylines and therefore increase
13962  // the shared boundary id by two
13963 
13964  // The first and second half of nodes
13965  std::list<Node*> first_half_node_pt;
13966  std::list<Node*> second_half_node_pt;
13967  // The first and second half of boundary elements
13968  Vector<FiniteElement*> first_half_ele_pt;
13969  Vector<FiniteElement*> second_half_ele_pt;
13970  // The first and second half of face indexes
13971  Vector<int> first_half_face_idx;
13972  Vector<int> second_half_face_idx;
13973 
13974  // Get the number of sub-nodes in the sub-list of nodes
13975  const unsigned n_sub_nodes = tmp_sub_nodes[2].size();
13976 
13977  // The number of sub-nodes for the first half of the shared
13978  // boundary
13979  const unsigned n_sub_nodes_half =
13980  static_cast<unsigned>(n_sub_nodes / 2.0);
13981 
13982  // Copy as many sub-nodes for the first half of the sub-polyline
13983 
13984  // Iterator to loop over the nodes
13985  std::list<Node*>::iterator it_sub = tmp_sub_nodes[2].begin();
13986 
13987  // Add the first node
13988  first_half_node_pt.push_back(*it_sub);
13989 
13990  // Skip the first node
13991  it_sub++;
13992 
13993  // Counter
13994  unsigned counter_nodes = 0;
13995  unsigned counter2 = 0;
13996 
13997  // Loop to copy the nodes
13998  for (; it_sub != tmp_sub_nodes[2].end(); it_sub++)
13999  {
14000  // Add the sub-node to the first half
14001  first_half_node_pt.push_back(*it_sub);
14002  // Add the boundary elements of the first half
14003  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2]);
14004  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2 + 1]);
14005  // Add the face indexes of the first half
14006  first_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2]);
14007  first_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2 + 1]);
14008 
14009  // Increase the counter of added nodes
14010  counter_nodes++;
14011 
14012  // Increase the other counter
14013  counter2 += 2;
14014 
14015  if (counter_nodes == n_sub_nodes_half)
14016  {
14017  // Stop adding to the first half of nodes
14018  break;
14019  }
14020 
14021  } // Copy the first half of nodes
14022 
14023  // The second half
14024 
14025  // Add the first node of the second half
14026  second_half_node_pt.push_back(*it_sub);
14027 
14028  // Skip the first node of the second half
14029  it_sub++;
14030 
14031  // Loop to copy the nodes
14032  for (; it_sub != tmp_sub_nodes[2].end(); it_sub++)
14033  {
14034  // Add the sub-node to the first half
14035  second_half_node_pt.push_back(*it_sub);
14036  // Add the boundary elements of the first half
14037  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2]);
14038  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2 + 1]);
14039  // Add the face indexes of the first half
14040  second_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2]);
14041  second_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2 + 1]);
14042 
14043  // Increase the other counter
14044  counter2 += 2;
14045 
14046  } // Copy the second half of nodes
14047 
14048  // Add the sub-list of nodes to the vector of lists of nodes
14049  output_sorted_nodes_pt.push_back(first_half_node_pt);
14050  output_sorted_nodes_pt.push_back(second_half_node_pt);
14051  // Add the sub-vector of elements to the vector of boundary
14052  // elements
14053  output_boundary_element_pt.push_back(first_half_ele_pt);
14054  output_boundary_element_pt.push_back(second_half_ele_pt);
14055  // Add the sub-vector of face indexes to the vector of face
14056  // indexes
14057  output_face_index_element.push_back(first_half_face_idx);
14058  output_face_index_element.push_back(second_half_face_idx);
14059 
14060  // --------------------------------------
14061  // Connections flags for the first half
14062 
14063  // The left connection flag
14064 
14065  // Connected to the previous shared boundary
14066  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
14067 
14068  // The right connection flag
14069 
14070  // Set connected to nothing, this is the base node
14071  output_connect_to_the_right.push_back(-1);
14072 
14073  // Increase the shared boundary id
14074  tmp_shd_bnd_id++;
14075 
14076  // --------------------------------------
14077  // Connections flags for the second half
14078 
14079  // The left connection flag
14080 
14081  // Set connected to the previous boundary
14082  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
14083 
14084  // The right connection flag
14085 
14086  if (input_connect_to_the_right == -3)
14087  {
14088  // Set connected to the previous shared boundary id
14089  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14090  }
14091  else if (input_connect_to_the_right == -2)
14092  {
14093  // Set connected to the previous shared boundary id
14094  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14095  }
14096  else if (input_connect_to_the_right == -1)
14097  {
14098  // Set connected to the previous shared boundary id
14099  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14100  }
14101  else
14102  {
14103  // Any other value keep it
14104  output_connect_to_the_right.push_back(input_connect_to_the_right);
14105  }
14106 
14107  // Increase the shared boundary id
14108  tmp_shd_bnd_id++;
14109 
14110  } // if (left_sub_node_pt == right_sub_node_pt)
14111  else
14112  {
14113  // No need to create two boundaries, create only one with the
14114  // sub-list of nodes
14115 
14116  // Add the sub-list of nodes to the vector of lists of nodes
14117  output_sorted_nodes_pt.push_back(tmp_sub_nodes[2]);
14118  // Add the sub-vector of elements to the vector of boundary
14119  // elements
14120  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[2]);
14121  // Add the sub-vector of face indexes to the vector of face
14122  // indexes
14123  output_face_index_element.push_back(tmp_sub_face_idx_ele[2]);
14124 
14125  // Set the connection flags, change them by the proper
14126  // connection flag
14127 
14128  // The left connection flag
14129 
14130  // Set connected to the previous shared boundary id
14131  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
14132 
14133  // The right connection flag
14134 
14135  // Connected with nothing but required to stop adding nodes
14136  if (input_connect_to_the_right == -3)
14137  {
14138  std::stringstream error_message;
14139  error_message
14140  << "The connection flag to the right ("
14141  << input_connect_to_the_right << ") indicates 'no connection and\n"
14142  << "stop adding nodes'.\n However, the thrid sub-list of\n"
14143  << "nodes must have a connection to the right with the same\n"
14144  << "shared polyline or with any other polyline\n\n";
14145  throw OomphLibError(
14146  error_message.str(),
14147  "TriangleMesh::break_loops_on_shared_polyline_helper()",
14148  OOMPH_EXCEPTION_LOCATION);
14149  }
14150  else if (input_connect_to_the_right == -1)
14151  {
14152  std::stringstream error_message;
14153  error_message
14154  << "The connection flag to the right ("
14155  << input_connect_to_the_right << ") indicates 'no connection.\n"
14156  << "However, the thrid sub-list of nodes must have a connection\n"
14157  << "to the right with the same shared polyline or with any other\n"
14158  << "polyline\n\n";
14159  throw OomphLibError(
14160  error_message.str(),
14161  "TriangleMesh::break_loops_on_shared_polyline_helper()",
14162  OOMPH_EXCEPTION_LOCATION);
14163  }
14164  // Connected with itself
14165  else if (input_connect_to_the_right == -2)
14166  {
14167  // Set connected to the previous shared boundary id
14168  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14169  }
14170  else
14171  {
14172  // Any other value keep it
14173  output_connect_to_the_right.push_back(input_connect_to_the_right);
14174  }
14175 
14176  // Increase the shared boundary id by one
14177  tmp_shd_bnd_id++;
14178 
14179  } // if (left_sub_node_pt == right_sub_node_pt)
14180 
14181  } // if (n_sub_list > 2)
14182  }
14183 
14184  // ======================================================================
14185  // Break any possible loop created by the sorted list of nodes
14186  // that is used to create a new shared polyline
14187  // ======================================================================
14188  template<class ELEMENT>
14191  const unsigned& initial_shd_bnd_id,
14192  std::list<Node*>& input_nodes,
14193  Vector<FiniteElement*>& input_boundary_element_pt,
14194  Vector<FiniteElement*>& input_boundary_face_element_pt,
14195  Vector<int>& input_face_index_element,
14196  const int& input_connect_to_the_left,
14197  const int& input_connect_to_the_right,
14198  Vector<std::list<Node*>>& output_sorted_nodes_pt,
14199  Vector<Vector<FiniteElement*>>& output_boundary_element_pt,
14200  Vector<Vector<FiniteElement*>>& output_boundary_face_element_pt,
14201  Vector<Vector<int>>& output_face_index_element,
14202  Vector<int>& output_connect_to_the_left,
14203  Vector<int>& output_connect_to_the_right)
14204  {
14205  // Get the left and right node of the current list of sorted nodes
14206  Node* left_node_pt = input_nodes.front();
14207  Node* right_node_pt = input_nodes.back();
14208 
14209  // Temporary storage for list of nodes, boundary elements, boundary
14210  // face elements and face element's indexes
14211  Vector<std::list<Node*>> tmp_sub_nodes;
14212  Vector<Vector<FiniteElement*>> tmp_sub_bnd_ele_pt;
14213  Vector<Vector<FiniteElement*>> tmp_sub_bnd_face_ele_pt;
14214  Vector<Vector<int>> tmp_sub_face_idx_ele;
14215 
14216  // Iterator for the list of input nodes
14217  std::list<Node*>::iterator it = input_nodes.begin();
14218 
14219  // Counter
14220  unsigned counter = 0;
14221 
14222  // Loop while not all nodes have been done
14223  while (it != input_nodes.end())
14224  {
14225  // Check if the current node is the final one
14226  it++;
14227  // Is the current node the final node?
14228  if (it == input_nodes.end())
14229  {
14230  // Break, add no more nodes
14231  break;
14232  }
14233  else
14234  {
14235  // Restore the iterator
14236  it--;
14237  }
14238 
14239  // Get a list of nonrepeated nodes
14240  std::list<Node*> sub_nodes;
14241  // The temporary vector of boundary elements associated with the
14242  // nodes
14243  Vector<FiniteElement*> sub_bnd_ele_pt;
14244  // The temporary vector of boundary face elements associated with
14245  // the nodes
14246  Vector<FiniteElement*> sub_bnd_face_ele_pt;
14247  // The temporary vector of face indexes associated with the
14248  // boundary elements
14249  Vector<int> sub_face_idx_ele;
14250 
14251  // Add the current node to the list
14252  sub_nodes.push_back(*it);
14253 
14254  // Add nodes until found a repeated node (the left or right
14255  // node) or until reaching the end of the list of nodes
14256  do
14257  {
14258  // Go to the next node
14259  ++it;
14260 
14261  // Add the new node
14262  sub_nodes.push_back((*it));
14263 
14264  // Add the boundary elements
14265  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter]);
14266 
14267  // Add the boundary face elements
14268  sub_bnd_face_ele_pt.push_back(input_boundary_face_element_pt[counter]);
14269 
14270  // Add the face indexes
14271  sub_face_idx_ele.push_back(input_face_index_element[counter]);
14272 
14273  // Increase the counter
14274  counter++;
14275 
14276  // Continue adding until reaching a repeated node or the end
14277  // of the list of nodes
14278  } while ((*it) != left_node_pt && (*it) != right_node_pt &&
14279  it != input_nodes.end());
14280 
14281  // Add the sub-set of nodes to the temporary storage
14282  tmp_sub_nodes.push_back(sub_nodes);
14283 
14284  // Add the boundary elements to the temporary storage
14285  tmp_sub_bnd_ele_pt.push_back(sub_bnd_ele_pt);
14286  // Add the boundary face elements to the temporary storage
14287  tmp_sub_bnd_face_ele_pt.push_back(sub_bnd_face_ele_pt);
14288  // Add the face indexes to the temporary storage
14289  tmp_sub_face_idx_ele.push_back(sub_face_idx_ele);
14290 
14291  } // while((*it) != input_nodes.end())
14292 
14293  // --------------------------------------------------
14294  // Now create as many shared boundaries as required
14295 
14296  // Get the number of sub-list of nodes created
14297  const unsigned n_sub_list = tmp_sub_nodes.size();
14298 
14299 #ifdef PARANOID
14300  if (n_sub_list > 1)
14301  {
14302  std::stringstream error_message;
14303  error_message
14304  << "The number of sub-list of nodes created from the shared\n"
14305  << "polyline with loops was (" << n_sub_list << ").\n"
14306  << "We can only handle one list which may still contain loops\n"
14307  << "(or repeated nodes)\n";
14308  throw OomphLibError(
14309  error_message.str(),
14310  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14311  OOMPH_EXCEPTION_LOCATION);
14312  }
14313 #endif
14314 
14315  // If there is only one list it may be because there are no loops or
14316  // there is only one loop (a circle)
14317  if (n_sub_list == 1 && (left_node_pt != right_node_pt))
14318  {
14319  // There are no loops, return just after filling the data
14320  // structures
14321 
14322  // This is the base case used most of the times
14323 
14324  // Set the vector of lists of nodes
14325  output_sorted_nodes_pt = tmp_sub_nodes;
14326  // Set the vector of boundary elements
14327  output_boundary_element_pt = tmp_sub_bnd_ele_pt;
14328  // Set the vector of boundary face elements
14329  output_boundary_face_element_pt = tmp_sub_bnd_face_ele_pt;
14330  // Set the vector of face indexes
14331  output_face_index_element = tmp_sub_face_idx_ele;
14332 
14333  // Set the connection flags, change them by the proper connection
14334  // flag
14335 
14336 #ifdef PARANOID
14337  if (input_connect_to_the_left == -2)
14338  {
14339  std::stringstream error_message;
14340  error_message
14341  << "The connection flag to the left (" << input_connect_to_the_left
14342  << ") indicates a connection\n"
14343  << "with the same polyline.\n However, only one sub-polyline was "
14344  << "found and no loops\nwere identified\n\n";
14345  throw OomphLibError(
14346  error_message.str(),
14347  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14348  OOMPH_EXCEPTION_LOCATION);
14349  }
14350 #endif
14351 
14352  // The left connection flag
14353  if (input_connect_to_the_left == -3)
14354  {
14355  output_connect_to_the_left.push_back(-1);
14356  }
14357  else
14358  {
14359  output_connect_to_the_left.push_back(input_connect_to_the_left);
14360  }
14361 
14362 #ifdef PARANOID
14363  if (input_connect_to_the_right == -2)
14364  {
14365  std::stringstream error_message;
14366  error_message
14367  << "The connection flag to the right (" << input_connect_to_the_right
14368  << ") indicates a connection\n"
14369  << "with the same polyline.\n However, only one sub-polyline was "
14370  << "found and no loops\nwere identified\n\n";
14371  throw OomphLibError(
14372  error_message.str(),
14373  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14374  OOMPH_EXCEPTION_LOCATION);
14375  }
14376 #endif
14377 
14378  // The right connection flag
14379  if (input_connect_to_the_right == -3)
14380  {
14381  output_connect_to_the_right.push_back(-1);
14382  }
14383  else
14384  {
14385  output_connect_to_the_right.push_back(input_connect_to_the_right);
14386  }
14387 
14388  // Return immediately
14389  return;
14390  }
14391 
14392  // The temporary storage for the shared boundary id
14393  unsigned tmp_shd_bnd_id = initial_shd_bnd_id;
14394 
14395  // -----------------------------------------------------------------
14396  // Check all the sub-list of nodes and create two shared boundaries
14397  // from those that make a loop (circle)
14398 
14399  // -----------------------------------------------------------
14400  // Get the left and right node of the first sub-list of nodes
14401  Node* left_sub_node_pt = tmp_sub_nodes[0].front();
14402  Node* right_sub_node_pt = tmp_sub_nodes[0].back();
14403 
14404  // Check if the sub-list of nodes creates a loop (circle)
14405  if (left_sub_node_pt == right_sub_node_pt)
14406  {
14407  // We need to create two shared polylines and therefore increase
14408  // the shared boundary id by two
14409 
14410  // The first and second half of nodes
14411  std::list<Node*> first_half_node_pt;
14412  std::list<Node*> second_half_node_pt;
14413  // The first and second half of boundary elements
14414  Vector<FiniteElement*> first_half_ele_pt;
14415  Vector<FiniteElement*> second_half_ele_pt;
14416  // The first and second half of boundary face elements
14417  Vector<FiniteElement*> first_half_ele_face_pt;
14418  Vector<FiniteElement*> second_half_ele_face_pt;
14419  // The first and second half of face indexes
14420  Vector<int> first_half_face_idx;
14421  Vector<int> second_half_face_idx;
14422 
14423  // Get the number of sub-nodes in the sub-list of nodes
14424  const unsigned n_sub_nodes = tmp_sub_nodes[0].size();
14425 
14426  // The number of sub-nodes for the first half of the shared
14427  // boundary
14428  const unsigned n_sub_nodes_half =
14429  static_cast<unsigned>(n_sub_nodes / 2.0);
14430 
14431  // Copy as many sub-nodes for the first half of the sub-polyline
14432 
14433  // Iterator to loop over the nodes
14434  std::list<Node*>::iterator it_sub = tmp_sub_nodes[0].begin();
14435 
14436  // Add the first node
14437  first_half_node_pt.push_back(*it_sub);
14438 
14439  // Skip the first node
14440  it_sub++;
14441 
14442  // Counter
14443  unsigned counter_nodes = 0;
14444  unsigned counter2 = 0;
14445 
14446  // Loop to copy the nodes
14447  for (; it_sub != tmp_sub_nodes[0].end(); it_sub++)
14448  {
14449  // Add the sub-node to the first half
14450  first_half_node_pt.push_back(*it_sub);
14451 
14452  // Add the boundary elements of the first half
14453  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
14454  // Add the boundary face elements of the first half
14455  first_half_ele_face_pt.push_back(tmp_sub_bnd_face_ele_pt[0][counter2]);
14456  // Add the face indexes of the first half
14457  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
14458 
14459  // Increase the counter of added nodes
14460  counter_nodes++;
14461 
14462  // Increase the other counter (of the elements/face)
14463  counter2++;
14464 
14465  if (counter_nodes == n_sub_nodes_half)
14466  {
14467  // Stop adding to the first half of nodes
14468  break;
14469  }
14470 
14471  } // Copy the first half of nodes
14472 
14473  // The second half
14474 
14475  // Add the first node of the second half
14476  second_half_node_pt.push_back(*it_sub);
14477 
14478  // Skip the first node of the second half
14479  it_sub++;
14480 
14481  // Loop to copy the nodes
14482  for (; it_sub != tmp_sub_nodes[0].end(); it_sub++)
14483  {
14484  // Add the sub-node to the first half
14485  second_half_node_pt.push_back(*it_sub);
14486 
14487  // Add the boundary elements of the first half
14488  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
14489  // Add the boundary face elements of the first half
14490  second_half_ele_face_pt.push_back(tmp_sub_bnd_face_ele_pt[0][counter2]);
14491  // Add the face indexes of the first half
14492  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
14493 
14494  // Increase the other counter
14495  counter2++;
14496 
14497  } // Copy the second half of nodes
14498 
14499  // Add the sub-list of nodes to the vector of lists of nodes
14500  output_sorted_nodes_pt.push_back(first_half_node_pt);
14501  output_sorted_nodes_pt.push_back(second_half_node_pt);
14502  // Add the sub-vector of elements to the vector of boundary
14503  // elements
14504  output_boundary_element_pt.push_back(first_half_ele_pt);
14505  output_boundary_element_pt.push_back(second_half_ele_pt);
14506  // Add the sub-vector of face elements to the vector of boundary
14507  // elements
14508  output_boundary_face_element_pt.push_back(first_half_ele_face_pt);
14509  output_boundary_face_element_pt.push_back(second_half_ele_face_pt);
14510  // Add the sub-vector of face indexes to the vector of face
14511  // indexes
14512  output_face_index_element.push_back(first_half_face_idx);
14513  output_face_index_element.push_back(second_half_face_idx);
14514 
14515  // Set the connection flags, change them by the proper connection
14516  // flag
14517 
14518  // ----------------------------------------------------------------
14519  // Connections flags for the first half
14520 
14521  // The left connection flag
14522 
14523  // Connected with nothing but required to stop adding nodes
14524  if (input_connect_to_the_left == -3)
14525  {
14526  // Set connected to nothing
14527  output_connect_to_the_left.push_back(-1);
14528  }
14529  // Connected with itself
14530  else if (input_connect_to_the_left == -2)
14531  {
14532  // Set connected to nothing, this is the base node
14533  output_connect_to_the_left.push_back(-1);
14534  }
14535  else
14536  {
14537  // Any other value keep it
14538  output_connect_to_the_left.push_back(input_connect_to_the_left);
14539  }
14540 
14541  // The right connection flag
14542 
14543  // Set connected to nothing, this is the base node
14544  output_connect_to_the_right.push_back(-1);
14545 
14546  // Increase the shared boundary id
14547  tmp_shd_bnd_id++;
14548 
14549  // ----------------------------------------------------------------
14550  // Connections flags for the second half
14551 
14552  // The left connection flag
14553 
14554  // Set connected to the previous boundary
14555  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
14556 
14557  // The right connection flag
14558 
14559  // Are we in the last sub-list of nodes, if that is the case we
14560  // need to respect the flag assigned to the right
14561  if (n_sub_list == 1)
14562  {
14563  if (input_connect_to_the_right == -3)
14564  {
14565  // Set connected to the previous shared boundary id
14566  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14567  }
14568  else if (input_connect_to_the_right == -2)
14569  {
14570  // Set connected to the previous shared boundary id
14571  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14572  }
14573  else if (input_connect_to_the_right == -1)
14574  {
14575  // Set connected to the previous shared boundary id
14576  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14577  }
14578  else
14579  {
14580  // Any other value keep it
14581  output_connect_to_the_right.push_back(input_connect_to_the_right);
14582  }
14583  } // if (n_sub_list == 1)
14584  else
14585  {
14586  // Set connected to the previous shared boundary id
14587  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14588  }
14589 
14590  // Increase the shared boundary id
14591  tmp_shd_bnd_id++;
14592 
14593  } // if (left_sub_node_pt == right_sub_node_pt)
14594 #ifdef PARANOID
14595  else
14596  {
14597  std::stringstream error_message;
14598  error_message
14599  << "The initial and final node in the current shared polyline are not\n"
14600  << "the same and the number of sublists is (" << n_sub_list << ").\n"
14601  << "We can not handle more than one sublist in the method to break\n"
14602  << "loops at the load balance stage\n\n";
14603  throw OomphLibError(
14604  error_message.str(),
14605  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14606  OOMPH_EXCEPTION_LOCATION);
14607  }
14608 #endif
14609  }
14610 
14611  // ======================================================================
14612  // Create the shared polyline and fill the data structured
14613  // that keep all the information associated with the creationg of the
14614  // shared boundary
14615  // ======================================================================
14616  template<class ELEMENT>
14618  const unsigned& my_rank,
14619  const unsigned& shd_bnd_id,
14620  const unsigned& iproc,
14621  const unsigned& jproc,
14622  std::list<Node*>& sorted_nodes,
14623  const int& root_edge_bnd_id,
14624  Vector<FiniteElement*>& bulk_bnd_ele_pt,
14625  Vector<int>& face_index_ele,
14626  Vector<Vector<TriangleMeshPolyLine*>>& unsorted_polylines_pt,
14627  const int& connect_to_the_left_flag,
14628  const int& connect_to_the_right_flag)
14629  {
14630  // ----------------------------------------------------------------
14631  // Associate the shared boundary with the respective processors
14632  // ----------------------------------------------------------------
14633 
14634  // Setup the global look-up scheme, where all processors know the
14635  // associations of others processors and the shared boundaries they
14636  // created
14637 
14638  // Set up the boundary shared by "iproc" with "jproc" processor
14639  Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
14640 
14641  // Set up the boundary shared by "jproc" with "iproc" processor
14642  Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
14643 
14644  // Specify the processors involved on the creation of the shared
14645  // boundary
14646  Vector<unsigned> processors(2);
14647  processors[0] = iproc;
14648  processors[1] = jproc;
14649  Shared_boundary_from_processors[shd_bnd_id] = processors;
14650 
14651  // ----------------------------------------------------------------
14652  // If one of the processor associated with the shared boundary is
14653  // the current processor then it needs to create a polyline from the
14654  // input sorted nodes, other processors can skip this part
14655  if (iproc == my_rank || jproc == my_rank)
14656  {
14657  // ------------------------------------------------------------
14658  // Create a vertices representation from the sorted nodes list
14659  // ------------------------------------------------------------
14660 
14661  // Get the number of nodes on the list
14662  const unsigned n_nodes = sorted_nodes.size();
14663  // The vector to store the vertices (assign space)
14664  Vector<Vector<double>> vertices(n_nodes);
14665 
14666  // Copy the vertices from the nodes
14667  unsigned counter = 0;
14668 
14669  for (std::list<Node*>::iterator it = sorted_nodes.begin();
14670  it != sorted_nodes.end();
14671  it++)
14672  {
14673  vertices[counter].resize(2);
14674  vertices[counter][0] = (*it)->x(0);
14675  vertices[counter][1] = (*it)->x(1);
14676  counter++;
14677  }
14678 
14679  // ---------------------------------------------
14680  // Create the polyline from the input vertices
14681  // ---------------------------------------------
14682  TriangleMeshPolyLine* polyline_pt =
14683  new TriangleMeshPolyLine(vertices, shd_bnd_id);
14684 
14685  // ---------------------------------------------
14686  // Establish the internal boundary information
14687  // ---------------------------------------------
14688 
14689  // Check if the shared boundary is overlapping (or is part) of an
14690  // internal boundary
14691  if (root_edge_bnd_id != -1)
14692  {
14693  // If the shared boundary is part of an internal boundary then
14694  // mark the shared boundary
14695  Shared_boundary_overlaps_internal_boundary[shd_bnd_id] =
14696  static_cast<unsigned>(root_edge_bnd_id);
14697  } // if (root_edge_bnd_id != -1)
14698 
14699  // ---------------------------------------------
14700  // Store the boundary elements and face indexes
14701  // ---------------------------------------------
14702 
14703  // Store the shared boundary elements
14704  const unsigned n_shared_boundary_elements = bulk_bnd_ele_pt.size();
14705 #ifdef PARANOID
14706  // Check that the number of shared boundy elements is the same as
14707  // the number of face indexes
14708  const unsigned n_face_index = face_index_ele.size();
14709  if (n_shared_boundary_elements != n_face_index)
14710  {
14711  std::ostringstream error_message;
14712  error_message
14713  << "The number of shared boundary elements is different from the\n"
14714  << "number of face indexes associated to the shared boundary\n"
14715  << "elements\n"
14716  << "Number of shared boundary elements: ("
14717  << n_shared_boundary_elements << ")\n"
14718  << "Number of face indexes: (" << n_face_index << ")\n\n";
14719  throw OomphLibError(error_message.str(),
14720  "TriangleMesh::create_shared_polyline()",
14721  OOMPH_EXCEPTION_LOCATION);
14722  } // if (n_shared_boundary_elements != n_face_index)
14723 #endif
14724 
14725  // Add the shared boundary elements and their respective face
14726  // indexes to their permanent containers
14727  for (unsigned i = 0; i < n_shared_boundary_elements; i++)
14728  {
14729  add_shared_boundary_element(shd_bnd_id, bulk_bnd_ele_pt[i]);
14730  add_face_index_at_shared_boundary(shd_bnd_id, face_index_ele[i]);
14731  } // for (i < nshared_boundary_elements)
14732 
14733  // Store the shared boundary nodes
14734  for (std::list<Node*>::iterator it = sorted_nodes.begin();
14735  it != sorted_nodes.end();
14736  it++)
14737  {
14738  add_shared_boundary_node(shd_bnd_id, (*it));
14739  } // for (it != sorted_nodes.end())
14740 
14741  // ----------------------------------------------------------
14742  // Create additional look-up schemes for the shared boundary
14743  // ----------------------------------------------------------
14744 
14745  // Updates bnd_id <---> curve section map
14746  this->Boundary_curve_section_pt[shd_bnd_id] = polyline_pt;
14747 
14748  // Check the size of the unsorted_polylines_pt structure. This
14749  // will have n_procs = 1 when it was called from the
14750  // create_new_shared_boundaries() methods
14751  const unsigned n_procs = unsorted_polylines_pt.size();
14752  if (n_procs > 1)
14753  {
14754  // Add the new created polyline to the list of unsorted
14755  // polylines
14756  unsorted_polylines_pt[iproc].push_back(polyline_pt);
14757 
14758  // ... do this on both processors involved in the creation of
14759  // the shared boundary
14760  unsorted_polylines_pt[jproc].push_back(polyline_pt);
14761  }
14762  else
14763  {
14764  // Add the new created polyline to the list of unsorted
14765  // polylines
14766  unsorted_polylines_pt[0].push_back(polyline_pt);
14767  }
14768 
14769  // Mark the polyline for deletion (when calling destructor)
14770  this->Free_curve_section_pt.insert(polyline_pt);
14771 
14772  // ----------------------------
14773  // Set connection information
14774  // ----------------------------
14775 
14776  // Check that the flags are correct, no connection or the boundary
14777  // id of the boundary to connect
14778 #ifdef PARANOID
14779  // Is the shared polyline not connected to the left
14780  if (connect_to_the_left_flag < 0)
14781  {
14782  // If not connected then should be specified by -1
14783  if (connect_to_the_left_flag != -1)
14784  {
14785  std::ostringstream error_message;
14786  error_message
14787  << "The only accepted values for the connection flags are:\n"
14788  << "POSITIVE values or -1, any other value is rejected, please\n"
14789  << "check that you previously called the methods to deal with\n"
14790  << "other flag values\n"
14791  << "The current flag value for connection to the left is: ("
14792  << connect_to_the_left_flag << ")\n\n";
14793  throw OomphLibError(error_message.str(),
14794  "TriangleMesh::create_shared_polyline()",
14795  OOMPH_EXCEPTION_LOCATION);
14796  } // if (connect_to_the_left_flag != -1)
14797  } // if (connect_to_the_left_flag < 0)
14798 
14799  // Is the shared polyline not connected to the right
14800  if (connect_to_the_right_flag < 0)
14801  {
14802  // If not connected then should be specified by -1
14803  if (connect_to_the_right_flag != -1)
14804  {
14805  std::ostringstream error_message;
14806  error_message
14807  << "The only accepted values for the connection flags are:\n"
14808  << "POSITIVE values or -1, any other value is rejected, please\n"
14809  << "check that you previously called the methods to deal with\n"
14810  << "other flag values\n"
14811  << "The current flag value for connection to the right is: ("
14812  << connect_to_the_right_flag << ")\n\n";
14813  throw OomphLibError(error_message.str(),
14814  "TriangleMesh::create_shared_polyline()",
14815  OOMPH_EXCEPTION_LOCATION);
14816  } // if (connect_to_the_right_flag != -1)
14817  } // if (connect_to_the_right_flag < 0)
14818 #endif
14819 
14820  // Set the connection to the left
14821  if (connect_to_the_left_flag != -1)
14822  {
14823  // Get the unsigned version of the boundary id to the left
14824  const unsigned bnd_id_connection_to_the_left =
14825  static_cast<unsigned>(connect_to_the_left_flag);
14826  // Set the initial vertex as connected
14827  polyline_pt->set_initial_vertex_connected();
14828  // Set the initial vertex connected boundary id
14829  polyline_pt->initial_vertex_connected_bnd_id() =
14830  bnd_id_connection_to_the_left;
14831  // Set the chunk number to zero
14832  polyline_pt->initial_vertex_connected_n_chunk() = 0;
14833 
14834  } // if (connect_to_the_left_flag != -1)
14835 
14836  // Set the connection to the right
14837  if (connect_to_the_right_flag != -1)
14838  {
14839  // Get the unsigned version of the boundary id to the right
14840  const unsigned bnd_id_connection_to_the_right =
14841  static_cast<unsigned>(connect_to_the_right_flag);
14842  // Set the final vertex as connected
14843  polyline_pt->set_final_vertex_connected();
14844  // Set the final vertex connected boundary id
14845  polyline_pt->final_vertex_connected_bnd_id() =
14846  bnd_id_connection_to_the_right;
14847  // Set the chunk number to zero
14848  polyline_pt->final_vertex_connected_n_chunk() = 0;
14849 
14850  } // if (connect_to_the_right_flag != -1)
14851 
14852  } // if (iproc == my_rank || jproc == my_rank)
14853  }
14854 
14855  //======================================================================
14856  /// Reset the boundary elements info. after load balance have
14857  /// taken place
14858  //======================================================================
14859  template<class ELEMENT>
14861  Vector<unsigned>& ntmp_boundary_elements,
14862  Vector<Vector<unsigned>>& ntmp_boundary_elements_in_region,
14863  Vector<FiniteElement*>& deleted_elements)
14864  {
14865  // Get the number of boundaries
14866  const unsigned nbound = this->nboundary();
14867 
14868  // Are there regions?
14869  const unsigned n_regions = this->nregion();
14870 
14871  // Loop over the boundaries
14872  for (unsigned b = 0; b < nbound; b++)
14873  {
14874  // Get the boundary elements and back them up
14875  // -----------------------------------------------------------------
14876  // Get the number of boundary elements (mixed with the old and new)
14877  const unsigned nbound_ele = this->nboundary_element(b);
14878  // Back-up the boundary elements
14879  Vector<FiniteElement*> backed_up_boundary_element_pt(nbound_ele);
14880  Vector<int> backed_up_face_index_at_boundary(nbound_ele);
14881  for (unsigned e = 0; e < nbound_ele; e++)
14882  {
14883  // Get the old boundary element
14884  backed_up_boundary_element_pt[e] = this->boundary_element_pt(b, e);
14885  // Get the old face index
14886  backed_up_face_index_at_boundary[e] =
14887  this->face_index_at_boundary(b, e);
14888  } // for (n < nold_boundary_elements)
14889 
14890  // Back up the elements in boundary for each region
14891  Vector<Vector<FiniteElement*>> backed_up_boundary_region_element_pt(
14892  n_regions);
14893  Vector<Vector<int>> backed_up_face_index_at_boundary_region(n_regions);
14894 
14895  // Loop over the regions and back up the boundary elements in
14896  // regions
14897  for (unsigned ir = 0; ir < n_regions; ir++)
14898  {
14899  // Get the region id
14900  const unsigned region_id =
14901  static_cast<unsigned>(this->region_attribute(ir));
14902  // Get the number of boundary region elements (mixed old and new)
14903  const unsigned nbnd_region_ele =
14904  this->nboundary_element_in_region(b, region_id);
14905 
14906  // Loop over the elements in the region
14907  for (unsigned e = 0; e < nbnd_region_ele; e++)
14908  {
14909  // Get the old boundary region element
14910  backed_up_boundary_region_element_pt[ir][e] =
14911  this->boundary_element_in_region_pt(b, region_id, e);
14912 
14913  // Get the old face index
14914  backed_up_face_index_at_boundary_region[ir][e] =
14915  this->face_index_at_boundary_in_region(b, region_id, e);
14916  } // for (e < nbnd_region_ele)
14917 
14918  } // for (ir < n_regions)
14919 
14920  // Clean all previous storages
14921  this->Boundary_element_pt[b].clear();
14922  this->Face_index_at_boundary[b].clear();
14923  if (n_regions > 0)
14924  {
14925  this->Boundary_region_element_pt[b].clear();
14926  this->Face_index_region_at_boundary[b].clear();
14927  }
14928 
14929  // -------------------------------------------------------------------
14930  // Now copy only the elements that are still alive, from those before
14931  // the re-establishment of halo and haloed elements
14932  // -------------------------------------------------------------------
14933  // Start with the boundary elements
14934  // Get the old number of boundary elements
14935  const unsigned nold_bnd_ele = ntmp_boundary_elements[b];
14936  // Loop over the boundary elements and check those still alive
14937  for (unsigned e = 0; e < nold_bnd_ele; e++)
14938  {
14939  FiniteElement* tmp_ele_pt = backed_up_boundary_element_pt[e];
14940  // Include only those elements still alive
14941  Vector<FiniteElement*>::iterator it = std::find(
14942  deleted_elements.begin(), deleted_elements.end(), tmp_ele_pt);
14943  // Only copy thoes elements not found on the deleted elements
14944  // container
14945  if (it == deleted_elements.end())
14946  {
14947  FiniteElement* add_ele_pt = backed_up_boundary_element_pt[e];
14948  this->Boundary_element_pt[b].push_back(add_ele_pt);
14949  const int face_index = backed_up_face_index_at_boundary[e];
14950  this->Face_index_at_boundary[b].push_back(face_index);
14951  } // if (tmp_ele_pt != 0)
14952 
14953  } // for (n < nold_bnd_ele)
14954 
14955  // ... continue with the boundary elements in specific regions
14956 
14957  // Loop over the regions
14958  for (unsigned ir = 0; ir < n_regions; ir++)
14959  {
14960  // Get the region id
14961  const unsigned region_id =
14962  static_cast<unsigned>(this->region_attribute(ir));
14963 
14964  // Get the old number of boundary elements in region
14965  const unsigned nold_bnd_region_ele =
14966  ntmp_boundary_elements_in_region[b][ir];
14967 
14968  // Loop over the boundary region elements and check those still
14969  // alive
14970  for (unsigned e = 0; e < nold_bnd_region_ele; e++)
14971  {
14972  // Get the element
14973  FiniteElement* tmp_ele_pt =
14974  backed_up_boundary_region_element_pt[ir][e];
14975  // Include only those elements still alive
14976  Vector<FiniteElement*>::iterator it = std::find(
14977  deleted_elements.begin(), deleted_elements.end(), tmp_ele_pt);
14978  // Only copy those elements not found on the deleted elements
14979  // container
14980  if (it == deleted_elements.end())
14981  {
14982  FiniteElement* add_ele_pt =
14983  backed_up_boundary_region_element_pt[ir][e];
14984  this->Boundary_region_element_pt[b][region_id].push_back(
14985  add_ele_pt);
14986  const int face_index =
14987  backed_up_face_index_at_boundary_region[ir][e];
14988  this->Face_index_region_at_boundary[b][region_id].push_back(
14989  face_index);
14990  } // if (tmp_ele_pt != 0)
14991 
14992  } // for (n < nbound_ele)
14993 
14994  } // for (ir < n_regions)
14995 
14996  // ----------------------------------------------------------------
14997  // Now copy all those elements created after the re-establishment
14998  // of halo and haloed elements
14999  // ----------------------------------------------------------------
15000  // Loop over the boundary elements
15001  for (unsigned e = nold_bnd_ele; e < nbound_ele; e++)
15002  {
15003  FiniteElement* add_ele_pt = backed_up_boundary_element_pt[e];
15004  this->Boundary_element_pt[b].push_back(add_ele_pt);
15005  const int face_index = backed_up_face_index_at_boundary[e];
15006  this->Face_index_at_boundary[b].push_back(face_index);
15007  } // for (e < nbound_ele)
15008 
15009  // Now add the boundary elements in regions
15010 
15011  // Loop over the regions
15012  for (unsigned ir = 0; ir < n_regions; ir++)
15013  {
15014  // Get the region id
15015  const unsigned region_id =
15016  static_cast<unsigned>(this->region_attribute(ir));
15017 
15018  // Get the old number of boundary elements in region
15019  const unsigned nold_bnd_region_ele =
15020  ntmp_boundary_elements_in_region[b][ir];
15021 
15022  // Get the new number of boundary elements in region
15023  const unsigned nbnd_region_ele =
15024  this->nboundary_element_in_region(b, region_id);
15025 
15026  // Loop over the boundary region elements and check those still
15027  // alive
15028  for (unsigned e = nold_bnd_region_ele; e < nbnd_region_ele; e++)
15029  {
15030  FiniteElement* add_ele_pt =
15031  backed_up_boundary_region_element_pt[ir][e];
15032  this->Boundary_region_element_pt[b][region_id].push_back(add_ele_pt);
15033  const int face_index = backed_up_face_index_at_boundary_region[ir][e];
15034  this->Face_index_region_at_boundary[b][region_id].push_back(
15035  face_index);
15036  } // for (e < nbnd_region_ele)
15037 
15038  } // for (ir < n_regions)
15039 
15040  } // for (b < nbound)
15041 
15042  // Lookup scheme has now been setup yet
15043  Lookup_for_elements_next_boundary_is_setup = true;
15044  }
15045 
15046 #endif // OOMPH_HAS_MPI
15047 
15048 #ifdef OOMPH_HAS_TRIANGLE_LIB
15049 
15050  //========================================================================
15051  /// Build a new TriangulateIO object based on target areas specified
15052  //========================================================================
15053  template<class ELEMENT>
15055  TriangulateIO& triangulate_io,
15056  const Vector<double>& target_area,
15057  struct TriangulateIO& triangle_refine)
15058  {
15059  // Initialize
15060  TriangleHelper::initialise_triangulateio(triangle_refine);
15061 
15062  // Store the global number of vertices and segments
15063  // in the list
15064  unsigned n_points = triangulate_io.numberofpoints;
15065  triangle_refine.numberofpoints = n_points;
15066 
15067  unsigned n_segments = triangulate_io.numberofsegments;
15068  triangle_refine.numberofsegments = n_segments;
15069 
15070  // Initialization of the TriangulateIO objects to store the values
15071  triangle_refine.pointlist =
15072  (double*)malloc(triangulate_io.numberofpoints * 2 * sizeof(double));
15073  triangle_refine.pointmarkerlist =
15074  (int*)malloc(triangulate_io.numberofpoints * sizeof(int));
15075  triangle_refine.segmentlist =
15076  (int*)malloc(triangulate_io.numberofsegments * 2 * sizeof(int));
15077  triangle_refine.segmentmarkerlist =
15078  (int*)malloc(triangulate_io.numberofsegments * sizeof(int));
15079 
15080  // Storing the point's coordinates in the list
15081  // and in two vectors with x and y coordinates
15082  Vector<double> x_coord(n_points);
15083  Vector<double> y_coord(n_points);
15084 
15085  for (unsigned count_point = 0; count_point < n_points * 2; count_point++)
15086  {
15087  triangle_refine.pointlist[count_point] =
15088  triangulate_io.pointlist[count_point];
15089 
15090  // Even vaules represent the x coordinate
15091  // Odd values represent the y coordinate
15092  if (count_point % 2 == 0)
15093  {
15094  x_coord[count_point / 2] = triangulate_io.pointlist[count_point];
15095  }
15096  else
15097  {
15098  y_coord[(count_point - 1) / 2] = triangulate_io.pointlist[count_point];
15099  }
15100  }
15101 
15102  // Store the point's markers in the list
15103  for (unsigned count_marker = 0; count_marker < n_points; count_marker++)
15104  {
15105  triangle_refine.pointmarkerlist[count_marker] =
15106  triangulate_io.pointmarkerlist[count_marker];
15107  }
15108 
15109  // Storing the segment's edges in the list
15110  for (unsigned count_seg = 0; count_seg < n_segments * 2; count_seg++)
15111  {
15112  triangle_refine.segmentlist[count_seg] =
15113  triangulate_io.segmentlist[count_seg];
15114  }
15115 
15116  // Store the segment's markers in the list
15117  for (unsigned count_markers = 0; count_markers < n_segments;
15118  count_markers++)
15119  {
15120  triangle_refine.segmentmarkerlist[count_markers] =
15121  triangulate_io.segmentmarkerlist[count_markers];
15122  }
15123 
15124  // Store the hole's center coordinates
15125  unsigned n_holes = triangulate_io.numberofholes;
15126  triangle_refine.numberofholes = n_holes;
15127 
15128  triangle_refine.holelist =
15129  (double*)malloc(triangulate_io.numberofholes * 2 * sizeof(double));
15130 
15131  // Loop over the holes to get centre coords
15132  for (unsigned count_hole = 0; count_hole < n_holes * 2; count_hole++)
15133  {
15134  triangle_refine.holelist[count_hole] =
15135  triangulate_io.holelist[count_hole];
15136  }
15137 
15138  // Store the triangles values
15139  unsigned n_triangles = triangulate_io.numberoftriangles;
15140  triangle_refine.numberoftriangles = n_triangles;
15141 
15142 #ifdef PARANOID
15143  if (n_triangles != target_area.size())
15144  {
15145  std::stringstream err;
15146  err << "Number of triangles in triangulate_io=" << n_triangles
15147  << " doesn't match\n"
15148  << "size of target area vector (" << target_area.size() << ")\n";
15149  throw OomphLibError(
15150  err.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15151  }
15152 #endif
15153 
15154  unsigned n_corners = triangulate_io.numberofcorners;
15155  triangle_refine.numberofcorners = n_corners;
15156 
15157  triangle_refine.trianglelist =
15158  (int*)malloc(triangulate_io.numberoftriangles * 3 * sizeof(int));
15159 
15160  // Store the triangle's corners in the list and get element sizes
15161  for (unsigned count_tri = 0; count_tri < n_triangles * 3; count_tri++)
15162  {
15163  triangle_refine.trianglelist[count_tri] =
15164  triangulate_io.trianglelist[count_tri];
15165  }
15166 
15167  // Store the triangle's area in the list
15168  triangle_refine.trianglearealist =
15169  (double*)malloc(triangulate_io.numberoftriangles * sizeof(double));
15170  for (unsigned count_area = 0; count_area < n_triangles; count_area++)
15171  {
15172  triangle_refine.trianglearealist[count_area] = target_area[count_area];
15173  }
15174 
15175  // Store the triangles attributes in the list
15176  triangle_refine.numberoftriangleattributes =
15177  triangulate_io.numberoftriangleattributes;
15178 
15179  triangle_refine.triangleattributelist = (double*)malloc(
15180  triangulate_io.numberoftriangles *
15181  triangulate_io.numberoftriangleattributes * sizeof(double));
15182  for (unsigned count_attribute = 0;
15183  count_attribute <
15184  (n_triangles * triangulate_io.numberoftriangleattributes);
15185  count_attribute++)
15186  {
15187  triangle_refine.triangleattributelist[count_attribute] =
15188  triangulate_io.triangleattributelist[count_attribute];
15189  }
15190  }
15191 
15192 #ifdef OOMPH_HAS_MPI
15193 
15194  // ===================================================================
15195  // The comparison class for the map that sorts the nodes on the
15196  // shared boundary (using a lexicographic order)
15197  // ===================================================================
15198  struct classcomp
15199  {
15200  // Tolerance for lower-left comparison
15201  static double Tol;
15202 
15203 
15204  // Comparison operator for "lower left" ordering
15205  bool operator()(const std::pair<double, double>& lhs,
15206  const std::pair<double, double>& rhs) const
15207  {
15208  double diff_y = lhs.second - rhs.second;
15209  if (diff_y < -Tol) // (lhs.second < rhs.second)
15210  {
15211  return true;
15212  }
15213  else
15214  {
15215  // Are they "equal" with 1.0e-14 tolerance?
15216  if (diff_y < Tol) // (lhs.second == rhs.second)
15217  {
15218 #ifdef PARANOID
15219  double diff_x = lhs.first - rhs.first;
15220  if (fabs(diff_x) < Tol)
15221  {
15222  std::ostringstream warning_message;
15223  warning_message
15224  << "Dodgy \"lower left\" (lexicographic) comparison "
15225  << "of points with cooordinates: "
15226  << " lhs = ( " << lhs.first << " , " << lhs.second << " ) \n"
15227  << " rhs = ( " << rhs.first << " , " << rhs.second << " ) \n"
15228  << "x and y coordinates differ by less than tolerance!\n"
15229  << "diff_x = " << diff_x << "\n"
15230  << "diff_y = " << diff_y << "\n"
15231  << "Tol = " << Tol << "\n";
15232  OomphLibError(warning_message.str(),
15233  OOMPH_CURRENT_FUNCTION,
15234  OOMPH_EXCEPTION_LOCATION);
15235  }
15236 #endif
15237  if (lhs.first < rhs.first)
15238  {
15239  return true;
15240  }
15241  else
15242  {
15243  return false;
15244  }
15245  }
15246  else
15247  {
15248  return false;
15249  }
15250  }
15251 
15252 
15253  // if (lhs.second < rhs.second)
15254  // {
15255  // return true;
15256  // }
15257  // else
15258  // {
15259  // // // Are "equal" with 1.0e-14 tolerance
15260  // // if (lhs.second - rhs.second < 1.0e-14)
15261  // // Are equal?
15262  // if (lhs.second == rhs.second)
15263  // {
15264  // if (lhs.first < rhs.first)
15265  // {
15266  // return true;
15267  // }
15268  // else
15269  // {
15270  // return false;
15271  // }
15272  // }
15273  // else
15274  // {
15275  // return false;
15276  // }
15277  // }
15278  }
15279 
15280  } Bottom_left_sorter; // struct classcomp
15281 
15282 
15283  // Assign value for tolerance
15284  double classcomp::Tol = 1.0e-14;
15285 
15286 
15287  //======================================================================
15288  // Sort the nodes on shared boundaries so that the processors that share
15289  // a boundary agree with the order of the nodes on the boundary
15290  //======================================================================
15291  template<class ELEMENT>
15293  {
15294  // Get the shared boundaries in this processor
15295  Vector<unsigned> my_rank_shared_boundaries_ids;
15296  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
15297 
15298  // Get the number of shared boundaries
15299  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
15300 
15301  // Loop over the shared boundaries
15302  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
15303  {
15304  // A map is used to sort the nodes using their coordinates as the key
15305  // of the map
15306  // std::map<std::pair<double, double>, Node*> sorted_nodes_pt;
15307  std::map<std::pair<double, double>, Node*, classcomp> sorted_nodes_pt;
15308 
15309 
15310 #ifdef PARANOID
15311 
15312  // Check min distance between nodes; had better be less than the
15313  // tolerance used for the bottom left sorting
15314  double min_distance_squared = DBL_MAX;
15315 
15316 #endif
15317 
15318  // Get the boundary id
15319  const unsigned b = my_rank_shared_boundaries_ids[i];
15320 
15321  // Get the number of nodes on the current boundary
15322  const unsigned nbnd_node = this->nshared_boundary_node(b);
15323 
15324  // Go through all the nodes on the boundary and temporarily store
15325  // them on the map container
15326  for (unsigned i_node = 0; i_node < nbnd_node; i_node++)
15327  {
15328  Node* node_pt = this->shared_boundary_node_pt(b, i_node);
15329  std::pair<double, double> vertex =
15330  std::make_pair(node_pt->x(0), node_pt->x(1));
15331  sorted_nodes_pt[vertex] = node_pt;
15332 
15333 
15334 #ifdef PARANOID
15335 
15336  // Check for minimum distance
15337  for (unsigned j_node = 0; j_node < nbnd_node; j_node++)
15338  {
15339  if (i_node != j_node)
15340  {
15341  Node* node2_pt = this->shared_boundary_node_pt(b, j_node);
15342 
15343  // Squared distance
15344  double squared_distance = 0.0;
15345  for (unsigned ii = 0; ii < 2; ii++)
15346  {
15347  squared_distance += (node_pt->x(ii) - node2_pt->x(ii)) *
15348  (node_pt->x(ii) - node2_pt->x(ii));
15349  }
15350  if (squared_distance < min_distance_squared)
15351  {
15352  min_distance_squared = squared_distance;
15353  }
15354  }
15355  }
15356 
15357  if (sqrt(min_distance_squared) < Bottom_left_sorter.Tol)
15358  {
15359  std::ostringstream warning_message;
15360  warning_message << "Minimum distance between nodes on boundary " << b
15361  << "\n"
15362  << "is " << sqrt(min_distance_squared)
15363  << " which is less than "
15364  << "Bottom_left_sorter.Tol = "
15365  << Bottom_left_sorter.Tol << "\n"
15366  << "This may screw up the ordering of the nodes on "
15367  "shared boundaries\n";
15368  OomphLibWarning(warning_message.str(),
15369  OOMPH_CURRENT_FUNCTION,
15370  OOMPH_EXCEPTION_LOCATION);
15371  }
15372 
15373 #endif
15374  }
15375 
15376  unsigned counter = 0;
15377  // Resize the sorted shared boundary node vector
15378  this->Sorted_shared_boundary_node_pt[b].resize(nbnd_node);
15379 
15380  // Now go through the map container, get the elements and store their
15381  // members on the Sorted_shared_boundary_node_pt container
15382  // The map has already sorted the nodes, now they keep the same sorting
15383  // on all processors
15384  for (std::map<std::pair<double, double>, Node*>::iterator it_map =
15385  sorted_nodes_pt.begin();
15386  it_map != sorted_nodes_pt.end();
15387  it_map++)
15388  {
15389  // Store the pointer to the node
15390  this->Sorted_shared_boundary_node_pt[b][counter++] = (*it_map).second;
15391  }
15392 
15393  } // for (i < nmy_rank_shd_bnd)
15394  }
15395 
15396  //========================================================================
15397  // Re-establish the shared boundary elements after the adaptation
15398  // process (the updating of shared nodes is optional and performed by
15399  // default)
15400  //========================================================================
15401  template<class ELEMENT>
15403  reset_shared_boundary_elements_and_nodes(const bool flush_elements,
15404  const bool update_elements,
15405  const bool flush_nodes,
15406  const bool update_nodes)
15407  {
15408  // Get the rank of the current processor
15409  const unsigned my_rank = this->communicator_pt()->my_rank();
15410 
15411  // Go through the boundaries know as shared boundaries and copy the
15412  // elements to the corresponding storage
15413 
15414  // Get the initial shared boundary id
15415  const unsigned initial_id = this->initial_shared_boundary_id();
15416 
15417  // Get the final shared boundary id
15418  const unsigned final_id = this->final_shared_boundary_id();
15419 
15420  if (flush_elements)
15421  {
15422  // Flush the shared boundaries storage for elements
15423  this->flush_shared_boundary_element();
15424  // .. and also flush the face indexes associated with the element
15425  this->flush_face_index_at_shared_boundary();
15426  } // if (flush_elements)
15427 
15428  if (flush_nodes)
15429  {
15430  // Flush the shared boundaries storage for nodes
15431  this->flush_shared_boundary_node();
15432  } // if (flush_nodes)
15433 
15434  for (unsigned b = initial_id; b < final_id; b++)
15435  {
15436  // Check if the boundary is on the current processor
15437  Vector<unsigned> procs_from_shrd_bnd;
15438  procs_from_shrd_bnd = this->shared_boundary_from_processors(b);
15439  bool current_processor_has_b_boundary = false;
15440  const unsigned n_procs_from_shrd_bnd = procs_from_shrd_bnd.size();
15441  for (unsigned p = 0; p < n_procs_from_shrd_bnd; p++)
15442  {
15443  if (procs_from_shrd_bnd[p] == my_rank)
15444  {
15445  current_processor_has_b_boundary = true;
15446  break; // break for (p < n_procs_from_shrd_bnd)
15447  }
15448  } // for (p < n_procs_from_shrd_bnd)
15449 
15450  if (current_processor_has_b_boundary)
15451  {
15452  if (update_elements)
15453  {
15454  const unsigned nboundary_ele = this->nboundary_element(b);
15455  for (unsigned e = 0; e < nboundary_ele; e++)
15456  {
15457  // Get the boundary element and add it to the shared
15458  // boundary elements structure
15459  FiniteElement* bnd_ele_pt = this->boundary_element_pt(b, e);
15460  this->add_shared_boundary_element(b, bnd_ele_pt);
15461  // ... do the same with the face index information
15462  int face_index = this->face_index_at_boundary(b, e);
15463  this->add_face_index_at_shared_boundary(b, face_index);
15464  } // for (e < nboundary_element)
15465  } // if (update_elements)
15466 
15467  if (update_nodes)
15468  {
15469  const unsigned nboundary_node = this->nboundary_node(b);
15470  for (unsigned n = 0; n < nboundary_node; n++)
15471  {
15472  Node* bnd_node_pt = this->boundary_node_pt(b, n);
15473  this->add_shared_boundary_node(b, bnd_node_pt);
15474  } // for (n < nboundary_node)
15475  } // if (update_nodes)
15476 
15477  } // if (current_processor_has_b_boundary)
15478  } // for (b < final_id)
15479  }
15480 
15481  //======================================================================
15482  // Sort the nodes on shared boundaries so that the processors that share
15483  // a boundary agree with the order of the nodes on the boundary
15484  //======================================================================
15485  template<class ELEMENT>
15487  {
15488  // Get the number of processors
15489  unsigned nproc = this->communicator_pt()->nproc();
15490  // Get the rank of the current processor
15491  unsigned my_rank = this->communicator_pt()->my_rank();
15492 
15493  // Get some timings
15494  double tt_start = 0.0;
15495  double tt_end = 0.0;
15496  if (Global_timings::Doc_comprehensive_timings)
15497  {
15498  tt_start = TimingHelpers::timer();
15499  }
15500 
15501  // -------------------------------------------------------------------
15502  // BEGIN: Get the node names and the shared nodes
15503  // -------------------------------------------------------------------
15504 
15505  // Container where to store the nodes on shared boundaries no
15506  // associated with the processor that receives the elements/nodes
15507  // other_proc_shd_bnd_node_pt[iproc][jproc][shd_bnd_id][index]
15508  Vector<Vector<Vector<std::map<unsigned, Node*>>>>
15509  other_proc_shd_bnd_node_pt(nproc);
15510  // Resize the container
15511  for (unsigned iproc = 0; iproc < nproc; iproc++)
15512  {
15513  // Resize the container
15514  other_proc_shd_bnd_node_pt[iproc].resize(nproc);
15515  for (unsigned jproc = 0; jproc < nproc; jproc++)
15516  {
15517  // Get the number of shared boundaries
15518  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
15519  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
15520  const unsigned nshared_bound = final_shd_bnd_id - initial_shd_bnd_id;
15521  other_proc_shd_bnd_node_pt[iproc][jproc].resize(nshared_bound);
15522  } // for (jproc < nproc)
15523 
15524  } // for (iproc < nproc)
15525 
15526  // Store the global node names
15527  // global_node_name[x][ ][ ] Global node number
15528  // global_node_name[ ][x][ ] Global node names
15529  // global_node_name[ ][ ][x] Global node info.
15530  Vector<Vector<Vector<unsigned>>> global_node_names;
15531 
15532  // Creates a map between the node name and the index of the global
15533  // node so we can access all its node names
15534  std::map<Vector<unsigned>, unsigned> node_name_to_global_index;
15535 
15536  // Store the global shared nodes pointers
15537  Vector<Node*> global_shared_node_pt;
15538 
15539  // Get the time for computation of global nodes names and shared
15540  // nodes
15541  double t_start_global_node_names_and_shared_nodes = TimingHelpers::timer();
15542 
15543  // Compute all the names of the nodes and fill in the
15544  // "other_proc_shd_bnd_node_pt" structure with the nodes that live
15545  // on this processor (my_rank) by looking over all their names
15546  compute_global_node_names_and_shared_nodes(other_proc_shd_bnd_node_pt,
15547  global_node_names,
15548  node_name_to_global_index,
15549  global_shared_node_pt);
15550 
15551  // Compute the number of elements before adding new ones
15552  const unsigned n_ele = this->nelement();
15553 
15554  if (Print_timings_level_adaptation > 1)
15555  {
15556  // The total time for computation of global nodes names and
15557  // shared nodes
15558  double t_final_global_node_names_and_shared_nodes =
15559  TimingHelpers::timer() - t_start_global_node_names_and_shared_nodes;
15560  oomph_info << "CPU for computing global node names and shared nodes "
15561  << "[n_ele=" << n_ele
15562  << "]: " << t_final_global_node_names_and_shared_nodes
15563  << std::endl;
15564  }
15565 
15566  // -------------------------------------------------------------------
15567  // END: Get the node names and the shared nodes
15568  // -------------------------------------------------------------------
15569 
15570  // -------------------------------------------------------------------
15571  // BEGIN: Using the global node names each processor sends info. of
15572  // the nodes shared with other processors regarding whether they are
15573  // on an original boundary or not. This is required so that at the
15574  // re-generation of halo(ed) elements stage they have the updated
15575  // information
15576  // -------------------------------------------------------------------
15577 
15578  // Get the time for sending info. of shared nodes on original
15579  // boundaries
15580  double t_start_send_info_shd_nodes_on_original_bnds =
15581  TimingHelpers::timer();
15582 
15583  // Send the boundary node info. of nodes on shared boundaries across
15584  // processors
15585  send_boundary_node_info_of_shared_nodes(
15586  global_node_names, node_name_to_global_index, global_shared_node_pt);
15587 
15588  if (Print_timings_level_adaptation > 1)
15589  {
15590  // The total time for sending info. of shared nodes lying on
15591  // original boundaries
15592  oomph_info
15593  << "CPU for sending info. of shared nodes on original boundaries: "
15594  << TimingHelpers::timer() - t_start_send_info_shd_nodes_on_original_bnds
15595  << std::endl;
15596  }
15597 
15598  // -------------------------------------------------------------------
15599  // END: Using the global node names each processor sends info. of
15600  // the nodes shared with other processors regarding whether they are
15601  // on an original boundary or not. This is required so that at the
15602  // re-generation of halo(ed) elements stage they have the updated
15603  // information
15604  // -------------------------------------------------------------------
15605 
15606  // -------------------------------------------------------------------
15607  // BEGIN: Identify the elements of the mesh that have nodes on the
15608  // shared boundaries
15609  // -------------------------------------------------------------------
15610 
15611  // Store the elements that have a node on a shared boundary with
15612  // other processors
15613  // ele_with_node_on_shd_bnd_pt[x][ ][ ]: iproc
15614  // ele_with_node_on_shd_bnd_pt[ ][x][ ]: ishd boundary with iproc
15615  // ele_with_node_on_shd_bnd_pt[ ][ ][x]: element with node on shared
15616  // boundary with iproc
15617  Vector<Vector<Vector<FiniteElement*>>> ele_with_node_on_shd_bnd_pt(nproc);
15618  // Resize the container with the number of shared boundaries within
15619  // each processor
15620 
15621  // loop over the processors
15622  for (unsigned iproc = 0; iproc < nproc; iproc++)
15623  {
15624  const unsigned n_shd_bnd_iproc = this->nshared_boundaries(my_rank, iproc);
15625  ele_with_node_on_shd_bnd_pt[iproc].resize(n_shd_bnd_iproc);
15626  } // for (iproc < nproc)
15627 
15628  // Go through all the elements and check whether any of their nodes
15629  // lies on any of the shared boundaries
15630 
15631  // loop over the elements
15632  for (unsigned e = 0; e < n_ele; e++)
15633  {
15634  // Get the element
15635  FiniteElement* ele_pt = this->finite_element_pt(e);
15636  // Get the number of nodes
15637  const unsigned n_nodes = ele_pt->nnode();
15638  // loop over the nodes and check whether any of them lies on a
15639  // shared boundary
15640  for (unsigned n = 0; n < n_nodes; n++)
15641  {
15642  // Get the node
15643  Node* node_pt = ele_pt->node_pt(n);
15644 
15645  // Now check whether the current node lies on a shared boundary
15646  // within any other processor
15647 
15648  // loop over the processors
15649  for (unsigned iproc = 0; iproc < nproc; iproc++)
15650  {
15651  // The number of boundaries shared with the current processor
15652  // (if iproc==my_rank then there are no shared boundaries
15653  // between them)
15654  const unsigned n_shd_bnd_iproc =
15655  this->nshared_boundaries(my_rank, iproc);
15656 
15657  // There are no info. with myself
15658  if (iproc != my_rank && n_shd_bnd_iproc > 0)
15659  {
15660  // Get the boundaries ids of the shared boundaries with
15661  // iproc processor
15662  Vector<unsigned> shd_bnd_ids =
15663  this->shared_boundaries_ids(my_rank, iproc);
15664 
15665  // Loop over shd bnds with processor "iproc"
15666  for (unsigned isb = 0; isb < n_shd_bnd_iproc; isb++)
15667  {
15668  const unsigned shd_bnd_id = shd_bnd_ids[isb];
15669  const unsigned n_ele_shd_bnd =
15670  this->nshared_boundary_element(shd_bnd_id);
15671 
15672  // Check if the node is on this boundary only if there are
15673  // elements on it
15674  if (n_ele_shd_bnd > 0 &&
15675  this->is_node_on_shared_boundary(shd_bnd_id, node_pt))
15676  {
15677  // Add the element into those that have a
15678  // node on the current shared boundary
15679  ele_with_node_on_shd_bnd_pt[iproc][isb].push_back(ele_pt);
15680 
15681  } // Are there elements on the boundary and the node lies
15682  // on this boundary
15683 
15684  } // for (isb < n_shd_bnd_iproc)
15685 
15686  } // if (iproc != my_rank && n_shd_bnd_iproc > 0)
15687 
15688  } // for (iproc < nproc)
15689 
15690  } // for (n < n_nodes)
15691 
15692  } // for (e < n_ele)
15693 
15694  // -------------------------------------------------------------------
15695  // END: Identify the elements of the mesh that have nodes on the
15696  // shared boundaries
15697  // -------------------------------------------------------------------
15698 
15699  // -------------------------------------------------------------------
15700  // BEGIN: Create the halo(ed) elements. Loop over the processors and
15701  // the shared boundaries within each processor. Get the elements on
15702  // the shared boundaries, mark them as haloed in this processor and
15703  // as halo on the element that will receive the info.
15704  // -------------------------------------------------------------------
15705 
15706  // ********************************************************************
15707  // General strategy:
15708  // 1) Go through all the elements on the shared boundaries, mark these
15709  // elements as haloed, same as their nodes.
15710  // 2) Package the info. of the nodes and the elements.
15711  // 3) Send and receive the info across processors
15712  // 4) Unpackage it and create halo elements and nodes as indicated by
15713  // the received info.
15714  // ********************************************************************
15715 
15716  // Keep track of the currently created nodes within each
15717  // processor. We need to keep track of these nodes so they can be
15718  // referred at a second stage.
15719  Vector<Vector<Node*>> iproc_currently_created_nodes_pt(nproc);
15720 
15721  // Get the time to re-generate halo(ed) elements/nodes (first stage)
15722  double t_start_regenerate_halo_ed_elements_nodes_first_stage =
15723  TimingHelpers::timer();
15724 
15725  // Go through all processors
15726  for (unsigned iproc = 0; iproc < nproc; iproc++)
15727  {
15728  // Send and receive info. to/from other processors
15729  if (iproc != my_rank)
15730  {
15731  // Get the number of boundaries shared with the send proc (iproc)
15732  const unsigned nshared_boundaries_with_iproc =
15733  this->nshared_boundaries(my_rank, iproc);
15734 
15735  if (nshared_boundaries_with_iproc > 0)
15736  {
15737  // ******************************************************************
15738  // Stage 1
15739  // ******************************************************************
15740  // Step (1) Mark the elements adjacent to the shared boundaries as
15741  // haloed, mark the nodes on these elements as haloed nodes
15742  // Step (2) Create packages of information indicating the generation
15743  // of halo elements and nodes
15744  // ******************************************************************
15745 
15746  // Clean send and receive buffers
15747  Flat_packed_unsigneds.clear();
15748  Flat_packed_doubles.clear();
15749 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15750  Flat_packed_unsigneds_string.clear();
15751 #endif
15752 
15753  // Get the boundaries ids shared with "iproc"
15754  Vector<unsigned> bound_shared_with_iproc;
15755  bound_shared_with_iproc = this->shared_boundaries_ids(my_rank, iproc);
15756 
15757  // Loop over shared boundaries with processor "iproc"
15758  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
15759  {
15760  const unsigned bnd_id = bound_shared_with_iproc[bs];
15761  // DEBP(bnd_id);
15762  const unsigned nel_bnd = this->nshared_boundary_element(bnd_id);
15763  // DEBP(nel_bnd);
15764 
15765  // Container to store the elements marked as haloed
15766  Vector<FiniteElement*> haloed_element;
15767 
15768  // All the elements adjacent to the boundary should be
15769  // marked as haloed elements
15770  if (nel_bnd > 0)
15771  {
15772  // Map to know which element have been already added
15773  std::map<FiniteElement*, bool> already_added;
15774 
15775  // Loop over the elements adjacent to boundary "bnd_id"
15776  for (unsigned e = 0; e < nel_bnd; e++)
15777  {
15778  // Get pointer to the element adjacent to boundary bnd_id
15779  FiniteElement* ele_pt =
15780  this->shared_boundary_element_pt(bnd_id, e);
15781 
15782  // Check if the element has been already added. Elemets
15783  // are repeated if they have two faces on the shared
15784  // boundary
15785  if (!already_added[ele_pt])
15786  {
15787  // Add the element to the container of haloed elements
15788  haloed_element.push_back(ele_pt);
15789  // Mark the element as already added
15790  already_added[ele_pt] = true;
15791  }
15792 
15793  } // for (e < nel_bnd)
15794 
15795  // In addition to the elements on the boundary we also
15796  // need to mark (as haloed) any element on the mesh with a
15797  // node on the shared boundary
15798 
15799  // Get the number of elements with a node on the current
15800  // shared boundary
15801  const unsigned n_ele_with_node_on_shd_bnd =
15802  ele_with_node_on_shd_bnd_pt[iproc][bs].size();
15803  // loop and add the elements that have a node on the
15804  // current shared boundary with the current processor
15805  for (unsigned iele = 0; iele < n_ele_with_node_on_shd_bnd; iele++)
15806  {
15807  // Get the element
15808  FiniteElement* ele_pt =
15809  ele_with_node_on_shd_bnd_pt[iproc][bs][iele];
15810  // Check if it has not been already added
15811  if (!already_added[ele_pt])
15812  {
15813  // Add it!!
15814  haloed_element.push_back(ele_pt);
15815  // Mark it as done
15816  already_added[ele_pt] = true;
15817  } // if (!already_added[ele_pt])
15818 
15819  } // for (iele < n_ele_with_node_on_shd_bnd)
15820 
15821  } // if (nel_bnd > 0)
15822 
15823  // Get the total number of haloed elements
15824  const unsigned nhaloed_ele = haloed_element.size();
15825  // DEBP(nhaloed_ele);
15826  // DEBP(my_rank);
15827  // DEBP(iproc);
15828  // The very first data of the flat packed is the number of haloed
15829  // elements, this will be the number of halo element to create on
15830  // the receiver processor
15831  Flat_packed_unsigneds.push_back(nhaloed_ele);
15832 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15833  std::stringstream junk;
15834  junk << "Number of haloed elements " << nhaloed_ele;
15835  Flat_packed_unsigneds_string.push_back(junk.str());
15836 #endif
15837 
15838  // Loop over the marked haloed elements
15839  for (unsigned e = 0; e < nhaloed_ele; e++)
15840  {
15841  // Get pointer to the marked haloed element
15842  FiniteElement* ele_pt = haloed_element[e];
15843  const unsigned nroot_haloed_ele =
15844  this->nroot_haloed_element(iproc);
15845 
15846  // Check if the element has been already added to the
15847  // halo(ed) scheme
15848  GeneralisedElement* gen_ele_pt = ele_pt;
15849  const unsigned haloed_ele_index =
15850  this->try_to_add_root_haloed_element_pt(iproc, gen_ele_pt);
15851 
15852  // Was the element added or only returned the index of the
15853  // element
15854  if (nroot_haloed_ele == haloed_ele_index)
15855  {
15856  Flat_packed_unsigneds.push_back(1);
15857 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15858  Flat_packed_unsigneds_string.push_back(
15859  "Haloed element needs to be constructed");
15860 #endif
15861 
15862  // Get additional info. related with the haloed element
15863  get_required_elemental_information_helper(iproc, ele_pt);
15864 
15865  // Get the nodes on the element
15866  const unsigned nnodes = ele_pt->nnode();
15867  for (unsigned j = 0; j < nnodes; j++)
15868  {
15869  Node* node_pt = ele_pt->node_pt(j);
15870 
15871  // Package the info. of the nodes
15872  // The destination processor goes in the arguments
15873  add_haloed_node_helper(iproc, node_pt);
15874 
15875  } // for (j < nnodes)
15876  } // add the element and send its nodes
15877  else // The haloed element already exists
15878  {
15879  Flat_packed_unsigneds.push_back(0);
15880 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15881  Flat_packed_unsigneds_string.push_back(
15882  "Haloed element already exists");
15883 #endif
15884  Flat_packed_unsigneds.push_back(haloed_ele_index);
15885 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15886  Flat_packed_unsigneds_string.push_back(
15887  "Index of existing haloed element");
15888 #endif
15889  } // else (next_haloed_ele == external_haloed_ele_index)
15890  } // for (e < nel_bnd)
15891 
15892  } // for (bs < nshared_boundaries_with_iproc)
15893 
15894  // *******************************************************************
15895  // Stage (2)
15896  // *******************************************************************
15897  // Step (1) Send and receive the data to create halo elements and
15898  // nodes
15899  // *******************************************************************
15900  // The processor to which send the elements
15901  int send_proc = static_cast<int>(iproc);
15902  // The processor from which receive the elements
15903  int recv_proc = static_cast<int>(iproc);
15904  send_and_receive_elements_nodes_info(send_proc, recv_proc);
15905 
15906  // *******************************************************************
15907  // Stage (3)
15908  // *******************************************************************
15909  // Step (1) Unpackage the info and create the halo elements and nodes
15910  // *******************************************************************
15911 
15912  // Reset the counters
15913  Counter_for_flat_packed_doubles = 0;
15914  Counter_for_flat_packed_unsigneds = 0;
15915 
15916  // Loop over shared boundaries with processor "iproc"
15917  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
15918  {
15919  // Get the number of halo element to be created
15920  const unsigned nhaloed_ele =
15921  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
15922 
15923 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15924  oomph_info
15925  << "Rec:" << Counter_for_flat_packed_unsigneds
15926  << " Number of elements need to be constructed "
15927  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
15928  << std::endl;
15929 #endif
15930 
15931  // Loop over boundaries shared with processor "urecv_proc"
15932  for (unsigned e = 0; e < nhaloed_ele; e++)
15933  {
15934  // Create halo element from received info. of "iproc"
15935  // processor on the current processor
15936  create_halo_element(iproc,
15937  iproc_currently_created_nodes_pt[iproc],
15938  other_proc_shd_bnd_node_pt,
15939  global_node_names,
15940  node_name_to_global_index,
15941  global_shared_node_pt);
15942 
15943  } // for (e < nhaloed_ele)
15944 
15945  } // for (bs < nshared_boundaries_with_iproc)
15946 
15947  } // if (nshared_bound_recv_proc > 0)
15948 
15949  } // if (iproc != my_rank)
15950 
15951  } // for (iproc < nproc) (general loop to send and receive info.)
15952 
15953  if (Print_timings_level_adaptation > 1)
15954  {
15955  // Get the time to re-generate halo(ed) elements/nodes (first stage)
15956  double t_final_regenerate_halo_ed_elements_nodes_first_stage =
15957  TimingHelpers::timer() -
15958  t_start_regenerate_halo_ed_elements_nodes_first_stage;
15959 
15960  oomph_info << "CPU for re-generating halo(ed) elements/nodes "
15961  << "(first stage) [n_ele=" << n_ele << "]: "
15962  << t_final_regenerate_halo_ed_elements_nodes_first_stage
15963  << std::endl;
15964  }
15965 
15966  // -------------------------------------------------------------------
15967  // END: Create the halo(ed) elements. Loop over the processors and
15968  // the shared boundaries within each processor. Get the elements on
15969  // the shared boundaries, mark them as haloed in this processor and
15970  // as halo on the element that will receive the info.
15971  // -------------------------------------------------------------------
15972 
15973  // -------------------------------------------------------------------
15974  // BEGIN: Create any additional haloed element, those that dont lie
15975  // on a shared boundary but that shared a node with other processor
15976  // -------------------------------------------------------------------
15977 
15978  // Get the time to re-generate halo(ed) elements/nodes (second stage)
15979  double t_start_regenerate_halo_ed_elements_nodes_second_stage =
15980  TimingHelpers::timer();
15981 
15982  // Create any additional halo(ed) elements between processors that
15983  // have no shared boundaries but that have shared nodes
15984  reset_halo_haloed_scheme_helper(other_proc_shd_bnd_node_pt,
15985  iproc_currently_created_nodes_pt,
15986  global_node_names,
15987  node_name_to_global_index,
15988  global_shared_node_pt);
15989 
15990  if (Print_timings_level_adaptation > 1)
15991  {
15992  // Get the time to re-generate halo(ed) elements/nodes (second stage)
15993  double t_final_regenerate_halo_ed_elements_nodes_second_stage =
15994  TimingHelpers::timer() -
15995  t_start_regenerate_halo_ed_elements_nodes_second_stage;
15996 
15997  oomph_info << "CPU for re-generating halo(ed) elements/nodes "
15998  << "(second stage) [n_ele=" << n_ele << "]: "
15999  << t_final_regenerate_halo_ed_elements_nodes_second_stage
16000  << std::endl;
16001  }
16002 
16003  // -------------------------------------------------------------------
16004  // END: Create any additional haloed element, those that dont lie on
16005  // a shared boundary but that shared a node with other processor
16006  // -------------------------------------------------------------------
16007 
16008  // Clean send and receive buffers
16009  Flat_packed_unsigneds.clear();
16010  Flat_packed_doubles.clear();
16011 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
16012  Flat_packed_unsigneds_string.clear();
16013 #endif
16014 
16015  // Document the timings for reseting halo and haloed scheme (without
16016  // classification of halo and haloed nodes)
16017  if (Print_timings_level_adaptation > 1)
16018  {
16019  tt_end = TimingHelpers::timer();
16020  oomph_info << "CPU for resetting halo-haloed scheme (without "
16021  "classification of halo and haloed nodes): "
16022  << tt_end - tt_start << std::endl;
16023  }
16024 
16025  // ------------------------------------------------------------------
16026  // BEGIN: Classify halo(ed) elements and nodes
16027  // ------------------------------------------------------------------
16028  const bool report_stats = true;
16029  DocInfo tmp_doc_info;
16030  tmp_doc_info.disable_doc();
16031 
16032  // Classify nodes
16033  this->classify_halo_and_haloed_nodes(tmp_doc_info, report_stats);
16034 
16035  // Document the timings for reseting halo and haloed scheme (with
16036  // classification of halo and haloed nodes)
16037  if (Print_timings_level_adaptation > 1)
16038  {
16039  tt_end = TimingHelpers::timer();
16040  oomph_info << "CPU for resetting halo-haloed scheme (with classification "
16041  "of halo and haloed nodes): "
16042  << tt_end - tt_start << std::endl;
16043  }
16044 
16045  // ------------------------------------------------------------------
16046  // END: Classify halo(ed) elements and nodes
16047  // ------------------------------------------------------------------
16048  }
16049 
16050  //======================================================================
16051  // Compute the alias of the nodes on shared boundaries in this
16052  // (my_rank) processor with other processors. Also compute the alias
16053  // of nodes on shared boundaries of other processors with other
16054  // processors (useful when there is an element that requires to be
16055  // sent to this (my_rank) processor because there is a shared node
16056  // between this (my_rank) and other processors BUT there is not a
16057  // shared boundary between this and the other processor
16058  // ======================================================================
16059  template<class ELEMENT>
16062  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
16063  other_proc_shd_bnd_node_pt,
16064  Vector<Vector<Vector<unsigned>>>& global_node_names,
16065  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
16066  Vector<Node*>& global_shared_node_pt)
16067  {
16068  // Get the number of processors
16069  const unsigned nproc = this->communicator_pt()->nproc();
16070  // Get the rank of the current processor
16071  const unsigned my_rank = this->communicator_pt()->my_rank();
16072  // Get the communicator of the mesh
16073  OomphCommunicator* comm_pt = this->communicator_pt();
16074 
16075  // ---------------------------------------------------------------
16076  // BEGIN: Get the elements adjacent to shared boundaries and give
16077  // a unique node number to the nodes on the shared boundaries in
16078  // this processor
16079  // ---------------------------------------------------------------
16080 
16081  // Counter for the nodes on shared boundaries in this (my_rank)
16082  // processor
16083  unsigned counter_nodes = 0;
16084  // Keep track of visited nodes
16085  std::map<Node*, bool> done_node;
16086  // ... and its local node number
16087  std::map<Node*, unsigned> local_node_number;
16088  // ... and the inverted relation from local node number to node_pt
16089  Vector<Node*> local_node_pt;
16090 
16091  // Stores the j-th node name associated with the i-th local node
16092  // on shared boundaries in this processor (my_rank)
16093  // local_node_names[i][j][0] = my_rank (this processor)
16094  // local_node_names[i][j][1] = iproc (the processor with which there
16095  // is a shared boundary)
16096  // local_node_names[i][j][2] = the shared boundary id between this
16097  // (my_rank) processor and iproc
16098  // processor
16099  // local_node_names[i][j][3] = the node index on the shared boundary
16100  // local_node_names[i][j][4] = the local node index (i). This may
16101  // be unnecessary since we alread know the
16102  // index but we also send this info. to
16103  // the root processor that is why we store
16104  // them here
16105  Vector<Vector<Vector<unsigned>>> local_node_names;
16106 
16107  // loop over the processors
16108  for (unsigned iproc = 0; iproc < nproc; iproc++)
16109  {
16110  // There are not shared boundaries with myself
16111  if (iproc != my_rank)
16112  {
16113  // Get the number of shared boundaries with iproc
16114  const unsigned n_shd_bnds_with_iproc =
16115  this->nshared_boundaries(my_rank, iproc);
16116 
16117  // Get the boundaries ids shared with iproc
16118  Vector<unsigned> bnd_shd_with_iproc =
16119  this->shared_boundaries_ids(my_rank, iproc);
16120 
16121  // Loop over the shared boundaries with processor iproc
16122  for (unsigned ishd = 0; ishd < n_shd_bnds_with_iproc; ishd++)
16123  {
16124  // Keep track of visited nodes with this shared boundary
16125  std::map<Node*, bool> done_node_shd_bnd;
16126  // The boundary id
16127  unsigned shd_bnd_id = bnd_shd_with_iproc[ishd];
16128  // Get the number of element on the shared boundary
16129  const unsigned n_shd_bnd_ele =
16130  this->nshared_boundary_element(shd_bnd_id);
16131 
16132  // loop over the elements adjacent to the shared boundary
16133  for (unsigned e = 0; e < n_shd_bnd_ele; e++)
16134  {
16135  // Get the element
16136  FiniteElement* ele_pt =
16137  this->shared_boundary_element_pt(shd_bnd_id, e);
16138 
16139  // Get the number of nodes on the element
16140  const unsigned n_nodes = ele_pt->nnode();
16141 
16142  // loop over the nodes of the current element
16143  for (unsigned n = 0; n < n_nodes; n++)
16144  {
16145  // Get the node
16146  Node* node_pt = ele_pt->node_pt(n);
16147 
16148  // Has the node been visited with this shared boundary?
16149  // And, is this a node on the shd_bnd_id shared boundary
16150  // with processor iproc?
16151  if (!done_node_shd_bnd[node_pt] &&
16152  this->is_node_on_shared_boundary(shd_bnd_id, node_pt))
16153  {
16154  // Mark the done as done with this shared boundary
16155  done_node_shd_bnd[node_pt] = true;
16156 
16157  // Get the index of the node on the shared boundary
16158  // -------------------------------------------------
16159  // Get the number of nodes on the shared boundary
16160  const unsigned n_nodes_shd_bnd =
16161  nsorted_shared_boundary_node(shd_bnd_id);
16162 
16163  // The index
16164  unsigned index = 0;
16165 
16166 #ifdef PARANOID
16167  // Flag to know if the node has been found
16168  bool found_node_on_shared_boundary = false;
16169 #endif
16170  // Loop over the nodes on the shared boundary to find
16171  // the node
16172  for (unsigned k = 0; k < n_nodes_shd_bnd; k++)
16173  {
16174  // Get the k-th node on the shared boundary
16175  Node* shd_bnd_node_pt =
16176  sorted_shared_boundary_node_pt(shd_bnd_id, k);
16177 
16178  // Is the same node?
16179  if (shd_bnd_node_pt == node_pt)
16180  {
16181  // This is the index
16182  index = k;
16183 #ifdef PARANOID
16184  // Mark as found
16185  found_node_on_shared_boundary = true;
16186 #endif
16187  break; // break
16188 
16189  } // if (shd_bnd_node_pt == node_pt)
16190 
16191  } // for (k < n_nodes_shd_bnd)
16192 
16193 #ifdef PARANOID
16194  if (!found_node_on_shared_boundary)
16195  {
16196  std::ostringstream error_message;
16197  error_message << "The index of the node on boundary ("
16198  << shd_bnd_id << ") was not found.\n"
16199  << "These are the node coordinates\n"
16200  << "(" << node_pt->x(0) << "," << node_pt->x(1)
16201  << ").\n";
16202  throw OomphLibError(error_message.str(),
16203  OOMPH_CURRENT_FUNCTION,
16204  OOMPH_EXCEPTION_LOCATION);
16205  }
16206 #endif
16207 
16208  // Create the node name
16209  Vector<unsigned> node_name(5);
16210  node_name[0] = my_rank;
16211  node_name[1] = iproc;
16212  node_name[2] = shd_bnd_id;
16213  node_name[3] = index;
16214  // The node number is filled in the following if/else
16215  // node_name[4] = ?;
16216 
16217  // Has the node already been visited?
16218  if (!done_node[node_pt])
16219  {
16220  // If not ...
16221 
16222  // Add the node to the local nodes
16223  local_node_pt.push_back(node_pt);
16224 
16225  // Assign a local node number to the node
16226  local_node_number[node_pt] = counter_nodes;
16227  // Store the local node number
16228  node_name[4] = counter_nodes;
16229  // Increase the counter of nodes
16230  counter_nodes++;
16231  // ... and mark it as visited
16232  done_node[node_pt] = true;
16233 
16234  // Push back the node name (the first
16235  // one found for this node)
16236  Vector<Vector<unsigned>> first_node_name(1);
16237  first_node_name[0] = node_name;
16238  local_node_names.push_back(first_node_name);
16239  }
16240  else
16241  {
16242  // If yes ...
16243 
16244  // Get the local node number
16245  unsigned node_number = local_node_number[node_pt];
16246 
16247  // Store the local node number
16248  node_name[4] = node_number;
16249 
16250  // Push back the node name for the
16251  // node number
16252  local_node_names[node_number].push_back(node_name);
16253  }
16254 
16255  } // Is on shared boundary?
16256 
16257  } // for (n < nnodes)
16258 
16259  } // for (e < n_shd_bnd_ele)
16260 
16261  } // for (ishd < n_shd_bnds_with_iproc)
16262 
16263  } // if (iproc != my_rank)
16264 
16265  } // for (iproc < nproc)
16266 
16267  // ---------------------------------------------------------------
16268  // END: Get the elements adjacent to shared boundaries and give
16269  // a unique node number to the nodes on the shared boundaries in
16270  // this processor
16271  // ---------------------------------------------------------------
16272 
16273  // ---------------------------------------------------------------
16274  // BEGIN: Package the names of the local nodes
16275  // ---------------------------------------------------------------
16276  // Counter for the number of names of the nodes
16277  unsigned n_total_local_names = 0;
16278  // Get the number of local nodes
16279  const unsigned n_local_nodes = local_node_names.size();
16280  // loop over the number of local nodes and get the number of names
16281  // of each node
16282  for (unsigned i = 0; i < n_local_nodes; i++)
16283  {
16284  // Get the number of names of the i-th local node
16285  const unsigned n_inode_names = local_node_names[i].size();
16286  // ... and add them to the total number of local names
16287  n_total_local_names += n_inode_names;
16288  } // for (i < n_local_nodes)
16289 
16290  // We store five data per node name (my_rank,iproc,shd_bnd_id,idx,node#)
16291  // where node# is the node number on this processor (my_rank)
16292  const unsigned n_info_per_node_name = 5;
16293  // Storage for the flat package
16294  Vector<unsigned> flat_packed_send_udata(n_total_local_names *
16295  n_info_per_node_name);
16296  // A counter
16297  unsigned counter = 0;
16298  // loop over the local nodes
16299  for (unsigned i = 0; i < n_local_nodes; i++)
16300  {
16301  // Get the number of names of the i-th local node
16302  const unsigned n_inode_names = local_node_names[i].size();
16303  // loop over the names of the i-th local node
16304  for (unsigned j = 0; j < n_inode_names; j++)
16305  {
16306  // Store this processor id (my_rank)
16307  flat_packed_send_udata[counter++] = local_node_names[i][j][0];
16308  // Store the processor with which the shared boundary exist
16309  flat_packed_send_udata[counter++] = local_node_names[i][j][1];
16310  // Store the shared boundary id
16311  flat_packed_send_udata[counter++] = local_node_names[i][j][2];
16312  // Store the index of the node on the shared boundary
16313  flat_packed_send_udata[counter++] = local_node_names[i][j][3];
16314  // Store the local node number on this processor (my_rank)
16315  flat_packed_send_udata[counter++] = local_node_names[i][j][4];
16316  } // for (j < n_inode_names)
16317 
16318  } // for (i < n_local_nodes)
16319 
16320  // Reset the counter
16321  counter = 0;
16322 
16323  // The number of data that will be sent to root from this
16324  // (my_rank) processor
16325  const unsigned n_udata_send_to_root = flat_packed_send_udata.size();
16326 
16327  // ---------------------------------------------------------------
16328  // END: Package the names of the local nodes
16329  // ---------------------------------------------------------------
16330  // ---------------------------------------------------------------
16331  // BEGIN: Send the data to the root processor
16332  // ---------------------------------------------------------------
16333 
16334  // The root processor is in charge of computing all the node names
16335  // of the nodes on the shared boundaries
16336 
16337  // Choose the root processor
16338  const unsigned root_processor = 0;
16339 
16340  // The vector where the root processor receives how many names
16341  // will receive from the other processors
16342  Vector<unsigned> root_n_names_per_processor(nproc);
16343 
16344  // Send the number of names that the root processor will receive
16345  // from each processor
16346  MPI_Gather(&n_total_local_names,
16347  1,
16348  MPI_UNSIGNED,
16349  &root_n_names_per_processor[0],
16350  1,
16351  MPI_UNSIGNED,
16352  root_processor,
16353  comm_pt->mpi_comm());
16354 
16355  // Get the total number of data to receive from all processor in
16356  // root
16357  unsigned root_n_total_udata_receive = 0;
16358  Vector<int> root_n_udata_to_receive(nproc, 0);
16359  for (unsigned iproc = 0; iproc < nproc; iproc++)
16360  {
16361  root_n_udata_to_receive[iproc] =
16362  root_n_names_per_processor[iproc] * n_info_per_node_name;
16363  root_n_total_udata_receive += root_n_udata_to_receive[iproc];
16364  }
16365 
16366  // Stores and compute the offsets (in root) for the data received
16367  // from each processor
16368  Vector<int> root_uoffsets_receive(nproc, 0);
16369  root_uoffsets_receive[0] = 0;
16370  for (unsigned iproc = 1; iproc < nproc; iproc++)
16371  {
16372  // Compute the offset to obtain the data from each processor
16373  root_uoffsets_receive[iproc] =
16374  root_uoffsets_receive[iproc - 1] + root_n_udata_to_receive[iproc - 1];
16375  }
16376 
16377  // Create at least one entry so we don't get a seg fault below
16378  if (flat_packed_send_udata.size() == 0)
16379  {
16380  flat_packed_send_udata.resize(1);
16381  }
16382 
16383  // Vector where to receive the info on root from all processors
16384  Vector<unsigned> root_flat_packed_receive_udata(root_n_total_udata_receive);
16385  // Only root receive data, the others dont, then resize the
16386  // container to have at least one entry
16387  if (my_rank != root_processor)
16388  {
16389  // Create at least one entry so we don't get a seg fault below
16390  if (root_flat_packed_receive_udata.size() == 0)
16391  {
16392  root_flat_packed_receive_udata.resize(1);
16393  }
16394  } // if (my_rank!=root_processor)
16395 
16396  // Send the info. to the root processor
16397  MPI_Gatherv(&flat_packed_send_udata[0], // Flat package to send
16398  // info. from each
16399  // processor
16400  n_udata_send_to_root, // Total number of data send
16401  // from each processor to root
16402  MPI_UNSIGNED,
16403  &root_flat_packed_receive_udata[0], // Container where
16404  // to receive the
16405  // info. from all
16406  // processors
16407  &root_n_udata_to_receive[0], // Number of data to
16408  // receive from each
16409  // processor
16410  &root_uoffsets_receive[0], // The offset to store the
16411  // info. from each
16412  // processor
16413  MPI_UNSIGNED,
16414  root_processor, // The processor that receives all the
16415  // info.
16416  comm_pt->mpi_comm());
16417 
16418  // Clear and resize the flat package to send
16419  flat_packed_send_udata.clear();
16420  flat_packed_send_udata.resize(0);
16421  // ---------------------------------------------------------------
16422  // END: Send the data to the root processor
16423  // ---------------------------------------------------------------
16424 
16425  // Container where root stores the info. that will be sent to all
16426  // processors. This includes the number of global nodes, the
16427  // number of names for each global node and the names
16428  Vector<unsigned> flat_packed_root_send_receive_udata;
16429 
16430  // ---------------------------------------------------------------
16431  // BEGIN: Unpackage the info. received on root. Compute the alias
16432  // of the nodes
16433  // ---------------------------------------------------------------
16434  if (my_rank == root_processor)
16435  {
16436  // Compute all the names of a node
16437  // root_global_node_name[x][ ][ ] Global node number
16438  // root_global_node_name[ ][x][ ] Global node names
16439  // root_global_node_name[ ][ ][x] Global node info.
16440  Vector<Vector<Vector<unsigned>>> root_global_node_names;
16441 
16442  // Store the info. extracted from the flat package sent to
16443  // root
16444  // root_local_node_names[x][ ] Node name
16445  // root_local_node_names[ ][x] Node info
16446  Vector<Vector<unsigned>> root_local_node_names;
16447 
16448  // Extract all the node names
16449  unsigned rcounter = 0;
16450  // loop over the processors
16451  for (unsigned iproc = 0; iproc < nproc; iproc++)
16452  {
16453  // Get the number of node names received from iproc
16454  const unsigned n_local_names_iproc = root_n_names_per_processor[iproc];
16455  for (unsigned i = 0; i < n_local_names_iproc; i++)
16456  {
16457  // Get the i-thnode name from iproc
16458  Vector<unsigned> node_name(n_info_per_node_name);
16459  for (unsigned j = 0; j < n_info_per_node_name; j++)
16460  {
16461  node_name[j] = root_flat_packed_receive_udata[rcounter++];
16462  }
16463 
16464  // Add the i-th node name
16465  root_local_node_names.push_back(node_name);
16466 
16467  } // for (i < n_local_names_iproc)
16468 
16469  } // for (iproc < nproc)
16470 
16471  // Get the number of node names received
16472  const unsigned n_root_local_node_names = root_local_node_names.size();
16473 
16474  // For each name of the node identify the position of its
16475  // counter-part
16476 
16477  // Given a node name on the iproc,
16478  // (iproc, jproc, ishd_bnd, idx, local_node_number1)
16479  // its counter part must live in jproc, so we look for the
16480  // node name
16481  // (jproc, iproc, ishd_bnd, idx, local_node_number2)
16482 
16483  // Store the index of the node name counter-part
16484  Vector<unsigned> node_name_counter_part(n_root_local_node_names);
16485 
16486  // Keep track of the names of nodes already done
16487  std::map<Vector<unsigned>, bool> done_name;
16488 
16489  // loop over the names of the nodes received from all
16490  // processors
16491  for (unsigned i = 0; i < n_root_local_node_names; i++)
16492  {
16493  // Get the i-th node name
16494  Vector<unsigned> node_name = root_local_node_names[i];
16495 
16496  // Check if this name node has been already done
16497  if (!done_name[node_name])
16498  {
16499  // Mark it as done
16500  done_name[node_name] = true;
16501 #ifdef PARANOID
16502  // Flag to indicate the counter-part name node was
16503  // found
16504  bool found_both_names_node = false;
16505 #endif
16506  // Find the counter-part name node (start from j+1
16507  // since all previous have been found, otherwise we
16508  // would not be here)
16509  for (unsigned j = i + 1; j < n_root_local_node_names; j++)
16510  {
16511  Vector<unsigned> node_name_r = root_local_node_names[j];
16512 
16513  // Check if this name node has been already done
16514  if (!done_name[node_name_r])
16515  {
16516  // Check whether this node is the
16517  // counter-part of the current name node
16518  if (node_name[0] == node_name_r[1] &&
16519  node_name[1] == node_name_r[0] &&
16520  node_name[2] == node_name_r[2] &&
16521  node_name[3] == node_name_r[3])
16522  {
16523  // Mark the name as node
16524  done_name[node_name_r] = true;
16525  // Store the index of the counter-part of
16526  // the current node name
16527  node_name_counter_part[i] = j;
16528  // ... and indicate the current node name
16529  // as the index of the counter-part
16530  node_name_counter_part[j] = i;
16531 #ifdef PARANOID
16532  // The node has been found
16533  found_both_names_node = true;
16534 #endif
16535  // Break the loop to find the
16536  // counter-part
16537  break;
16538  }
16539 
16540  } // if (!done_name[node_name_r])
16541 
16542  } // for (j < n_root_local_node_names)
16543 #ifdef PARANOID
16544  // Check whether the node counter-part was found
16545  if (!found_both_names_node)
16546  {
16547  std::ostringstream error_message;
16548  error_message << "The counter-part of the current name node was "
16549  << "not found,\nthe current node name is:\n"
16550  << "iproc:(" << node_name[0] << ")\n"
16551  << "jproc:(" << node_name[1] << ")\n"
16552  << "ishd_bnd:(" << node_name[2] << ")\n"
16553  << "index:(" << node_name[3] << ")\n";
16554  throw OomphLibError(error_message.str(),
16555  OOMPH_CURRENT_FUNCTION,
16556  OOMPH_EXCEPTION_LOCATION);
16557  } // if (!found_both_names_node)
16558 #endif
16559 
16560  } // if (!done_name[node_name])
16561 
16562  } // for (i < n_root_local_node_names)
16563 
16564  // -----------------------------------------------------------
16565  // Look for all the names of each node received and store them
16566  // in the "global node names" container
16567 
16568  // Keep track of the names of nodes already done
16569  done_name.clear();
16570  // loop over the names of the nodes received from all
16571  // processors
16572  for (unsigned i = 0; i < n_root_local_node_names; i++)
16573  {
16574  // Get the i-th node name
16575  Vector<unsigned> node_name = root_local_node_names[i];
16576 
16577  // Check if this name node has been already done
16578  if (!done_name[node_name])
16579  {
16580  // Store all the names of the current node
16581  Vector<Vector<unsigned>> all_node_names;
16582 
16583  // Add the name of the node as the initial node name
16584  all_node_names.push_back(node_name);
16585 
16586  // Get the index of the counter-part
16587  unsigned idx_c = node_name_counter_part[i];
16588  // Get the counter-part of the node name
16589  Vector<unsigned> node_name_r = root_local_node_names[idx_c];
16590 
16591  // Add the name of the counter-part of the node
16592  all_node_names.push_back(node_name_r);
16593  // We do not mark it as done since we are interested in
16594  // the names that the counter-part may generate
16595 
16596  // Get the number of names for the current node (two at
16597  // the first time)
16598  unsigned n_current_names = all_node_names.size();
16599  // Counter to ensure to visit all the names of the current
16600  // node
16601  unsigned icounter = 0;
16602 
16603  // Visit all the names of the current node
16604  while (icounter < n_current_names)
16605  {
16606  // Get the current node name
16607  Vector<unsigned> current_node_name = all_node_names[icounter];
16608 
16609  // Search for other names for the current name of the
16610  // node, but first check if this has been already
16611  // visited
16612  if (!done_name[current_node_name])
16613  {
16614  // Mark it as done
16615  done_name[current_node_name] = true;
16616 
16617  // loop over the names of the nodes (start from the
16618  // j+1 position, all previous node names have all
16619  // their names already assigned)
16620  for (unsigned j = i + 1; j < n_root_local_node_names; j++)
16621  {
16622  // Get the j-th node name
16623  Vector<unsigned> other_node_name = root_local_node_names[j];
16624 
16625  // Is this name node already done
16626  if (!done_name[other_node_name])
16627  {
16628  // Is this another name for the current name node?
16629  if ((current_node_name[0] == other_node_name[0]) &&
16630  (current_node_name[4] == other_node_name[4]))
16631  {
16632  // Mark it as done. If we search again using the
16633  // "other_node_name" as the current node name we
16634  // are not going to find new nodes to add
16635  done_name[other_node_name] = true;
16636  // Before adding it check that it is not already
16637  // part of the names of the node
16638  Vector<Vector<unsigned>>::iterator it =
16639  std::find(all_node_names.begin(),
16640  all_node_names.end(),
16641  other_node_name);
16642  if (it == all_node_names.end())
16643  {
16644  all_node_names.push_back(other_node_name);
16645  // Get the index of the counter-part
16646  unsigned k = node_name_counter_part[j];
16647  // Get the counter-part of the node name
16648  Vector<unsigned> other_node_name_r =
16649  root_local_node_names[k];
16650  // Add the name of the counter-part of the
16651  // node only if it has not been previously
16652  // done
16653  if (!done_name[other_node_name_r])
16654  {
16655  all_node_names.push_back(other_node_name_r);
16656  }
16657  }
16658 
16659  } // // Is this another name for the current name
16660  // node?
16661 
16662  } // if (!done_name[other_node_name])
16663 
16664  } // for (j < n_root_local_node_names)
16665 
16666  } // if (!done_name[current_node_name])
16667 
16668  // Get the number of names
16669  n_current_names = all_node_names.size();
16670  // Increase the icounter to indicate we have visited the
16671  // current name of the node
16672  icounter++;
16673 
16674  } // while(icounter < n_current_names)
16675 
16676  // We now have all the names for the i-th global node
16677  root_global_node_names.push_back(all_node_names);
16678 
16679  } // if (!done_name[node_name])
16680 
16681  } // for (i < n_root_local_node_names)
16682 
16683  // -------------------------------------------------------------
16684  // Prepare the info to be sent to all processors. The number
16685  // of global nodes, the number of names for each global node,
16686  // and their respective names
16687  // -------------------------------------------------------------
16688 
16689  // Clear the container
16690  flat_packed_root_send_receive_udata.clear();
16691  // Get the number of global nodes
16692  const unsigned n_global_nodes = root_global_node_names.size();
16693  // ... and store this info. to be sent from root to all
16694  // processors
16695  flat_packed_root_send_receive_udata.push_back(n_global_nodes);
16696 
16697  // loop over the nodes
16698  for (unsigned i = 0; i < n_global_nodes; i++)
16699  {
16700  // Get the names of the i-th global node
16701  Vector<Vector<unsigned>> global_inode_names = root_global_node_names[i];
16702  // Get the number of names for the i-th global node
16703  const unsigned n_names_global_inode = global_inode_names.size();
16704  // ... and store this info. to be sent from root to all
16705  // processors
16706  flat_packed_root_send_receive_udata.push_back(n_names_global_inode);
16707  // loop over the names of the global i-th node
16708  for (unsigned j = 0; j < n_names_global_inode; j++)
16709  {
16710  // loop over the info. associated with each name
16711  for (unsigned k = 0; k < n_info_per_node_name; k++)
16712  {
16713  // Store the name info. of the current name in the
16714  // container to be sent from root to all processors
16715  flat_packed_root_send_receive_udata.push_back(
16716  global_inode_names[j][k]);
16717  } // for (k < n_info_per_node_name)
16718 
16719  } // for (j < n_names_inode)
16720 
16721  } // for (i < n_global_nodes)
16722 
16723  } // if (my_rank == root_processor)
16724 
16725  // ----------------------------------------------------------------
16726  // END: Unpackage the info. received on root. Compute the alias
16727  // of the nodes and prepare the info. to be sent back from
16728  // root to all processors
16729  // ----------------------------------------------------------------
16730 
16731  // ---------------------------------------------------------------
16732  // BEGIN: Send the info. back to all processors, unpackage the
16733  // info. and create the map from node name to global node
16734  // index
16735  // ---------------------------------------------------------------
16736  // The number of data that root send to other processors.
16737  unsigned root_n_udata_sent_to_all_proc =
16738  flat_packed_root_send_receive_udata.size();
16739 
16740  MPI_Bcast(&root_n_udata_sent_to_all_proc, // Data to send and
16741  // receive
16742  1,
16743  MPI_UNSIGNED,
16744  root_processor,
16745  comm_pt->mpi_comm());
16746 
16747  // Resize the container if this is a processor that receives data
16748  if (my_rank != root_processor)
16749  {
16750  flat_packed_root_send_receive_udata.resize(root_n_udata_sent_to_all_proc);
16751  }
16752 
16753  // Send the info. from root and receive it on all processors
16754  MPI_Bcast(&flat_packed_root_send_receive_udata[0], // Info. sent
16755  // from root to
16756  // all
16757  // processors
16758  root_n_udata_sent_to_all_proc, // Number of data sent
16759  // from root to each
16760  // procesor
16761  MPI_UNSIGNED,
16762  root_processor, // The processor that sends all the info.
16763  comm_pt->mpi_comm());
16764 
16765  // Counter to extract the info.
16766  counter = 0;
16767  // Read the number of global nodes
16768  const unsigned n_global_nodes =
16769  flat_packed_root_send_receive_udata[counter++];
16770  // Store the global names of the nodes
16771  // global_node_name[x][ ][ ] Global node number
16772  // global_node_name[ ][x][ ] Global node names
16773  // global_node_name[ ][ ][x] Global node info.
16774  // Vector<Vector<Vector<unsigned> > > global_node_names(n_global_nodes);
16775  // Resize the input vector
16776  global_node_names.resize(n_global_nodes);
16777  // Now loop until all global nodes info. has been read
16778  unsigned n_read_global_nodes = 0;
16779  while (n_read_global_nodes < n_global_nodes)
16780  {
16781  // Read the number of names for the current global node
16782  const unsigned n_names_global_inode =
16783  flat_packed_root_send_receive_udata[counter++];
16784  // Counter for the global node
16785  const unsigned i = n_read_global_nodes;
16786  // Resize the container
16787  global_node_names[i].resize(n_names_global_inode);
16788  // loop over the names of the global inode
16789  for (unsigned j = 0; j < n_names_global_inode; j++)
16790  {
16791  // Resize the container
16792  global_node_names[i][j].resize(n_info_per_node_name);
16793  // loop over the info. of the j-th node name of the i-th
16794  // global node
16795  for (unsigned k = 0; k < n_info_per_node_name; k++)
16796  {
16797  // Read the k-th node info. from the j-th node name of
16798  // the i-th global node
16799  global_node_names[i][j][k] =
16800  flat_packed_root_send_receive_udata[counter++];
16801 
16802  } // for (k < n_info_per_node_name)
16803 
16804  // Create the map from the node name to the global node
16805  // index
16806  Vector<unsigned> node_name(n_info_per_node_name - 1);
16807  node_name[0] = global_node_names[i][j][0];
16808  node_name[1] = global_node_names[i][j][1];
16809  node_name[2] = global_node_names[i][j][2];
16810  node_name[3] = global_node_names[i][j][3];
16811  // Do not add the local index since it will not longer be
16812  // used. Additionally, we will not know the local node
16813  // index outside this method
16814  // node_name[4] = global_node_names[i][j][4];
16815  node_name_to_global_index[node_name] = i;
16816 
16817  } // for (j < n_names_global_inode)
16818 
16819  // Increase the counter for read global nodes
16820  n_read_global_nodes++;
16821 
16822  } // while (n_read_global_nodes < n_global_nodes)
16823 
16824 #ifdef PARANOID
16825  // Check we have read all the info.
16826  if (counter != root_n_udata_sent_to_all_proc)
16827  {
16828  std::ostringstream error_stream;
16829  error_stream
16830  << "The info. received from root regarding the global names of "
16831  << "the nodes\nwas not completely read.\n"
16832  << "The number of data sent/received from root is: ("
16833  << root_n_udata_sent_to_all_proc << ")\n"
16834  << "The number of data read from the received info. is: (" << counter
16835  << ")\n\n";
16836  throw OomphLibError(
16837  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
16838  } // if (counter != root_n_udata_sent_to_all_proc)
16839 #endif
16840 
16841  // ---------------------------------------------------------------
16842  // END: Send the info. back to all processors, unpackage the info.
16843  // and create the map from node name to global node index
16844  // ---------------------------------------------------------------
16845 
16846  // ---------------------------------------------------------------
16847  // BEGIN: Add the info. from the global node names into the
16848  // info. of the local node names. We do this because the
16849  // local node names have pointers to the nodes.
16850  // Additionally, create a map from the node name to the
16851  // index of its global node
16852  // ---------------------------------------------------------------
16853 
16854  // Resize the global shared node pointers container
16855  global_shared_node_pt.resize(n_global_nodes, 0);
16856 
16857  // loop over the number of global nodes
16858  for (unsigned i = 0; i < n_global_nodes; i++)
16859  {
16860  // Flag to indicate that the iglobal node is part of the nodes
16861  // on the current processor
16862  bool is_this_a_local_node_name = false;
16863  unsigned local_node_number;
16864  // Get the number of names of the i-th global node
16865  const unsigned n_names_global_inode = global_node_names[i].size();
16866  // loop over the names of the i-th global node
16867  for (unsigned j = 0; j < n_names_global_inode; j++)
16868  {
16869  // Get the node name info.
16870  const unsigned iproc = global_node_names[i][j][0];
16871  local_node_number = global_node_names[i][j][4];
16872 
16873  // Check if this node name lives on this processor
16874  if (my_rank == iproc)
16875  {
16876  // The node is part of the local node names
16877  is_this_a_local_node_name = true;
16878  // Break
16879  break;
16880  } // if (my_rank == iproc)
16881 
16882  } // for (j < n_names_global_inode)
16883 
16884  // If the node is part of the local nodes then add the
16885  // additional names of the node in the local container
16886  if (is_this_a_local_node_name)
16887  {
16888 #ifdef PARANOID
16889  // Check that the global node include at least all the names
16890  // of the node on this processor
16891  const unsigned n_names_local_node =
16892  local_node_names[local_node_number].size();
16893  unsigned n_names_found_on_global_name_node = 0;
16894 #endif
16895 
16896  // Add the pointer of the node into the global shared node
16897  // pointers container
16898  global_shared_node_pt[i] = local_node_pt[local_node_number];
16899 
16900  // Add all the global names of the node onto the local node
16901  // names
16902 
16903  // loop again over the names of the i-th global node
16904  for (unsigned j = 0; j < n_names_global_inode; j++)
16905  {
16906  // Get the node name info.
16907  const unsigned iproc = global_node_names[i][j][0];
16908 
16909  // Is this a node name on this processor?
16910  if (iproc != my_rank)
16911  {
16912  // Add the name
16913  local_node_names[local_node_number].push_back(
16914  global_node_names[i][j]);
16915  }
16916 #ifdef PARANOID
16917  else
16918  {
16919  const unsigned jproc = global_node_names[i][j][1];
16920  const unsigned ishd_bnd = global_node_names[i][j][2];
16921  const unsigned idx = global_node_names[i][j][3];
16922  const unsigned n_local_node = global_node_names[i][j][4];
16923  // loop over the names of the local node
16924  for (unsigned k = 0; k < n_names_local_node; k++)
16925  {
16926  if ((local_node_names[local_node_number][k][0] == iproc) &&
16927  (local_node_names[local_node_number][k][1] == jproc) &&
16928  (local_node_names[local_node_number][k][2] == ishd_bnd) &&
16929  (local_node_names[local_node_number][k][3] == idx) &&
16930  (local_node_names[local_node_number][k][4] == n_local_node))
16931  {
16932  // Increase the number of local nodes found on the
16933  // global nodes
16934  n_names_found_on_global_name_node++;
16935  } // found global node on local nodes
16936 
16937  } // for (k < n_names_local_node)
16938 
16939  } // if (iproc != my_rank)
16940 #endif
16941 
16942  } // for (j < n_names_global_inode)
16943 
16944 #ifdef PARANOID
16945  // The number of local nodes names must be the same as the the
16946  // number of global nodes names associated with this processor
16947  // (my_rank, that start with iproc = my_rank)
16948  if (n_names_local_node != n_names_found_on_global_name_node)
16949  {
16950  std::ostringstream error_stream;
16951  error_stream << "The local node names corresponding to the local "
16952  << "node (" << local_node_number << ") were\n"
16953  << "not found on the global node names.\n\n"
16954  << "These are the names of the local node\n"
16955  << "Name k: iproc, jproc, ishd_bnd, idx. #node\n";
16956  for (unsigned k = 0; k < n_names_local_node; k++)
16957  {
16958  error_stream << "Name(" << k
16959  << "): " << local_node_names[local_node_number][k][0]
16960  << ", " << local_node_names[local_node_number][k][1]
16961  << ", " << local_node_names[local_node_number][k][2]
16962  << ", " << local_node_names[local_node_number][k][3]
16963  << ", " << local_node_names[local_node_number][k][4]
16964  << "\n";
16965  }
16966 
16967  error_stream << "\n\nThese are the names of the global node\n"
16968  << "Name k: iproc, jproc, ishd_bnd, idx. #node\n";
16969  for (unsigned k = 0; k < n_names_global_inode; k++)
16970  {
16971  error_stream << "Name(" << k << "): " << global_node_names[i][k][0]
16972  << ", " << global_node_names[i][k][1] << ", "
16973  << global_node_names[i][k][2] << ", "
16974  << global_node_names[i][k][3] << ", "
16975  << global_node_names[i][k][4] << "\n";
16976  }
16977 
16978  throw OomphLibError(error_stream.str(),
16979  OOMPH_CURRENT_FUNCTION,
16980  OOMPH_EXCEPTION_LOCATION);
16981  }
16982 #endif
16983 
16984  } // if (is_this_a_local_node_name)
16985 
16986  } // for (i < n_global_nodes)
16987 
16988  // ---------------------------------------------------------------
16989  // END: Add the info. from the global node names into the info.
16990  // of the local node names. We do this because the local
16991  // node names have pointers to the nodes
16992  // ---------------------------------------------------------------
16993 
16994  // ---------------------------------------------------------------
16995  // BEGIN: Fill the data structure other_proc_shd_bnd_node_pt with
16996  // the local nodes.
16997  // ---------------------------------------------------------------
16998 
16999  // Loop over the local nodes and fill the
17000  // other_proc_shd_bnd_node_pt container with the corresponding
17001  // info. NOTE: We are using the old size of the local node names,
17002  // before adding the names of the global nodes so we only loop
17003  // over the local nodes and not global.
17004 
17005  // Compute the local shared boudary id
17006  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
17007 
17008  // loop over the local nodes names
17009  for (unsigned i = 0; i < n_local_nodes; i++)
17010  {
17011  // Get the number of names for the i-th local node
17012  const unsigned n_names = local_node_names[i].size();
17013  // Get a pointer to the first name of the node found on this
17014  // processor (this ensures that the node lives on this
17015  // processor)
17016  Node* node_pt = local_node_pt[i];
17017  // loop over the names of the i-th local node and add an entry
17018  // to the other_proc_shd_bnd_node_pt structure
17019  for (unsigned j = 0; j < n_names; j++)
17020  {
17021  // Get the node name info.
17022  const unsigned iproc = local_node_names[i][j][0];
17023  const unsigned jproc = local_node_names[i][j][1];
17024  const unsigned ishd_bnd =
17025  local_node_names[i][j][2] - initial_shd_bnd_id;
17026  const unsigned index = local_node_names[i][j][3];
17027  // We can ignore the last entry, it was just used to compute
17028  // the global node number by the root processor
17029 
17030  // Get the smallest processor number
17031  if (iproc < jproc)
17032  {
17033  other_proc_shd_bnd_node_pt[iproc][jproc][ishd_bnd][index] = node_pt;
17034  }
17035  else
17036  {
17037  other_proc_shd_bnd_node_pt[jproc][iproc][ishd_bnd][index] = node_pt;
17038  }
17039 
17040  } // for (j < n_names)
17041 
17042  } // for (i < n_local_node_names)
17043 
17044  // ---------------------------------------------------------------
17045  // END: Fill the data structure other_proc_shd_bnd_node_pt with
17046  // the local nodes.
17047  // ---------------------------------------------------------------
17048  }
17049 
17050  //======================================================================
17051  // Get the original boundaries to which is associated each
17052  // shared node, and send the info. to the related processors. We
17053  // need to do this so that at the reset of halo(ed) info. stage,
17054  // the info. is updated
17055  template<class ELEMENT>
17057  Vector<Vector<Vector<unsigned>>>& global_node_names,
17058  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
17059  Vector<Node*>& global_shared_node_pt)
17060  {
17061  // Get the rank and number of processors
17062  const unsigned nproc = this->communicator_pt()->nproc();
17063  const unsigned my_rank = this->communicator_pt()->my_rank();
17064 
17065  // The number of nodes on shared boundaries
17066  const unsigned n_nodes_on_shd_bnds = global_node_names.size();
17067  // ---------------------------------------------------------
17068  // BEGIN: Get the shared nodes between each of processors
17069  // ---------------------------------------------------------
17070 
17071  // Store the nodes on shared boundaries in this processor with other
17072  // processors
17073  Vector<std::set<Node*>> node_on_shd_bnd_pt(nproc);
17074 
17075  // A map to get access to the global shared node number from the
17076  // node pointer
17077  std::map<Node*, unsigned> node_pt_to_global_shd_bnd_index;
17078 
17079  // loop over the global nodes names and get only those in this
17080  // processor
17081  for (unsigned i = 0; i < n_nodes_on_shd_bnds; i++)
17082  {
17083  // Get the number of names of the current node on shared
17084  // boundaries
17085  const unsigned n_names = global_node_names[i].size();
17086  // loop over the names
17087  for (unsigned j = 0; j < n_names; j++)
17088  {
17089  // Store the node name
17090  Vector<unsigned> node_name(4);
17091  node_name[0] = global_node_names[i][j][0];
17092  node_name[1] = global_node_names[i][j][1];
17093  node_name[2] = global_node_names[i][j][2];
17094  node_name[3] = global_node_names[i][j][3];
17095 
17096  // Check whether the node is in the current processor
17097  if (node_name[0] == my_rank)
17098  {
17099  // Check with which processor the node is shared
17100  const unsigned jproc = node_name[1];
17101 
17102 #ifdef PARANOID
17103  std::map<Vector<unsigned>, unsigned>::iterator it =
17104  node_name_to_global_index.find(node_name);
17105  if (it != node_name_to_global_index.end())
17106  {
17107  // Check whether the global node index correspond with that
17108  // of the current global node name
17109  if (i != (*it).second)
17110  {
17111  std::ostringstream error_message;
17112  error_message
17113  << "The global node number " << (*it).second
17114  << ") obtained from the current node\n"
17115  << "name is not the same as the current node number (" << i
17116  << ").\n\n"
17117  << "Node name:\n"
17118  << "iproc:" << node_name[0] << "\n"
17119  << "jproc:" << node_name[1] << "\n"
17120  << "shd_bnd_id:" << node_name[2] << "\n"
17121  << "index:" << node_name[3] << "\n\n";
17122  throw OomphLibError(error_message.str(),
17123  OOMPH_CURRENT_FUNCTION,
17124  OOMPH_EXCEPTION_LOCATION);
17125  }
17126  }
17127  else
17128  {
17129  std::ostringstream error_message;
17130  error_message
17131  << "The node name is not registerd as living in this processor.\n"
17132  << "Node name:\n"
17133  << "iproc:" << node_name[0] << "\n"
17134  << "jproc:" << node_name[1] << "\n"
17135  << "shd_bnd_id:" << node_name[2] << "\n"
17136  << "index:" << node_name[3] << "\n\n";
17137  throw OomphLibError(error_message.str(),
17138  OOMPH_CURRENT_FUNCTION,
17139  OOMPH_EXCEPTION_LOCATION);
17140  }
17141 
17142 #endif // #ifdef PARANOID
17143 
17144  // Get the node pointer
17145  Node* node_pt = global_shared_node_pt[i];
17146 
17147 #ifdef PARANOID
17148  if (node_pt == 0)
17149  {
17150  std::ostringstream error_message;
17151  error_message << "There is not global shared node within this\n"
17152  << "global node number (" << i
17153  << "). The global shared\n"
17154  << "node pointer is null\n\n";
17155  throw OomphLibError(error_message.str(),
17156  OOMPH_CURRENT_FUNCTION,
17157  OOMPH_EXCEPTION_LOCATION);
17158  }
17159 #endif // #ifdef PARANOID
17160 
17161  // Add the node to the nodes on shared boundaries in this
17162  // processor
17163  node_on_shd_bnd_pt[jproc].insert(node_pt);
17164 
17165  // And store the global node index
17166  node_pt_to_global_shd_bnd_index[node_pt] = i;
17167 
17168  } // if (node_name[0]==my_rank)
17169  else if (node_name[1] == my_rank)
17170  {
17171  // Check with which processor the node is shared
17172  const unsigned jproc = node_name[0];
17173 
17174 #ifdef PARANOID
17175  std::map<Vector<unsigned>, unsigned>::iterator it =
17176  node_name_to_global_index.find(node_name);
17177  if (it != node_name_to_global_index.end())
17178  {
17179  // Check whether the global node index correspond with that
17180  // of the current global node name
17181  if (i != (*it).second)
17182  {
17183  std::ostringstream error_message;
17184  error_message
17185  << "The global node number " << (*it).second
17186  << ") obtained from the current node\n"
17187  << "name is not the same as the current node number (" << i
17188  << ").\n\n"
17189  << "Node name:\n"
17190  << "iproc:" << node_name[0] << "\n"
17191  << "jproc:" << node_name[1] << "\n"
17192  << "shd_bnd_id:" << node_name[2] << "\n"
17193  << "index:" << node_name[3] << "\n\n";
17194  throw OomphLibError(error_message.str(),
17195  OOMPH_CURRENT_FUNCTION,
17196  OOMPH_EXCEPTION_LOCATION);
17197  }
17198  }
17199  else
17200  {
17201  std::ostringstream error_message;
17202  error_message
17203  << "The node name is not registerd as living in this processor.\n"
17204  << "Node name:\n"
17205  << "iproc:" << node_name[0] << "\n"
17206  << "jproc:" << node_name[1] << "\n"
17207  << "shd_bnd_id:" << node_name[2] << "\n"
17208  << "index:" << node_name[3] << "\n\n";
17209  throw OomphLibError(error_message.str(),
17210  OOMPH_CURRENT_FUNCTION,
17211  OOMPH_EXCEPTION_LOCATION);
17212  }
17213 
17214 #endif // #ifdef PARANOID
17215 
17216  // Get the node pointer
17217  Node* node_pt = global_shared_node_pt[i];
17218 
17219 #ifdef PARANOID
17220  if (node_pt == 0)
17221  {
17222  std::ostringstream error_message;
17223  error_message << "There is not global shared node within this\n"
17224  << "global node number (" << i
17225  << "). The global shared\n"
17226  << "node pointer is null\n\n";
17227  throw OomphLibError(error_message.str(),
17228  OOMPH_CURRENT_FUNCTION,
17229  OOMPH_EXCEPTION_LOCATION);
17230  }
17231 #endif // #ifdef PARANOID
17232 
17233  // Add the node to the nodes on shared boundaries in this
17234  // processor
17235  node_on_shd_bnd_pt[jproc].insert(node_pt);
17236 
17237  // And store the global node index
17238  node_pt_to_global_shd_bnd_index[node_pt] = i;
17239  }
17240 
17241  } // for (j < n_names)
17242 
17243  } // for (i < n_nodes_on_shd_bnds)
17244 
17245  // ---------------------------------------------------------
17246  // END: Get the shared nodes between each of processors
17247  // ---------------------------------------------------------
17248 
17249  // ---------------------------------------------------------
17250  // BEGIN: Get the original boundaries associated to each
17251  // node on a shared boundary
17252  // ---------------------------------------------------------
17253 
17254  // Store the global shared node number
17255  Vector<Vector<unsigned>> global_node_on_shared_bound(nproc);
17256  // Store the boundaries associated with the global shared node
17257  // number
17258  Vector<Vector<Vector<unsigned>>> global_node_original_boundaries(nproc);
17259  // Store the zeta boundary coordinate of the nodes on original
17260  // boundaries
17261  Vector<Vector<Vector<double>>> global_node_zeta_coordinate(nproc);
17262 
17263  // loop over the processors
17264  for (unsigned iproc = 0; iproc < nproc; iproc++)
17265  {
17266  // Get the nodes added to be shared with the iproc processor
17267  std::set<Node*> nodes_shared_pt = node_on_shd_bnd_pt[iproc];
17268 
17269  // loop over the nodes
17270  for (std::set<Node*>::iterator it = nodes_shared_pt.begin();
17271  it != nodes_shared_pt.end();
17272  it++)
17273  {
17274  // Get the node
17275  Node* node_pt = (*it);
17276  // Store the boundaries on which it is stored
17277  Vector<unsigned> on_original_boundaries;
17278  // For each boundary get the corresponding z value of the node
17279  // on the boundary
17280  Vector<double> zeta_coordinate;
17281  // Get the number of boudandaries
17282  const unsigned n_bnd = this->initial_shared_boundary_id();
17283  // loop over the boundaries and register the boundaries to which
17284  // it is associated
17285  for (unsigned bb = 0; bb < n_bnd; bb++)
17286  {
17287  // Is the node on original boundary bb?
17288  if (node_pt->is_on_boundary(bb))
17289  {
17290  // Then save it as being on boundary bb
17291  on_original_boundaries.push_back(bb);
17292  // Get the boundary coordinate
17293  Vector<double> zeta(1);
17294  node_pt->get_coordinates_on_boundary(bb, zeta);
17295  // Save the boundary coordinate
17296  zeta_coordinate.push_back(zeta[0]);
17297  }
17298 
17299  } // for (bb < n_bnd)
17300 
17301  // Is the node on an original boundary
17302  if (on_original_boundaries.size() > 0)
17303  {
17304  // Get the global shared node number
17305  std::map<Node*, unsigned>::iterator it_index =
17306  node_pt_to_global_shd_bnd_index.find(node_pt);
17307 #ifdef PARANOID
17308  if (it_index == node_pt_to_global_shd_bnd_index.end())
17309  {
17310  std::ostringstream error_message;
17311  error_message
17312  << "We could not find the global shared node index associated\n"
17313  << "with the node pointer with vertices coordinates:\n"
17314  << "(" << node_pt->x(0) << ", " << node_pt->x(1) << ")\n\n";
17315  throw OomphLibError(error_message.str(),
17316  OOMPH_CURRENT_FUNCTION,
17317  OOMPH_EXCEPTION_LOCATION);
17318  }
17319 #endif
17320  // The global shared node index
17321  const unsigned global_shared_node_number = (*it_index).second;
17322  // Store the global shared node number
17323  global_node_on_shared_bound[iproc].push_back(
17324  global_shared_node_number);
17325  // And store the original boundaries to which it is associated
17326  global_node_original_boundaries[iproc].push_back(
17327  on_original_boundaries);
17328  // and the corresponding zeta coordinate
17329  global_node_zeta_coordinate[iproc].push_back(zeta_coordinate);
17330  }
17331 
17332  } // loop over nodes on shared boundaries with iproc
17333 
17334  } // for (iproc < nproc)
17335 
17336  // ---------------------------------------------------------
17337  // END: Get the original boundaries associated to each
17338  // node on a shared boundary
17339  // ---------------------------------------------------------
17340 
17341  // ---------------------------------------------------------
17342  // BEGIN: Send the info. to the corresponding processors,
17343  // package the info, send it and receive it in the
17344  // corresponding processor, unpackage and set the
17345  // boundaries associated with the received nodes
17346  // ---------------------------------------------------------
17347 
17348  // Get the communicator of the mesh
17349  OomphCommunicator* comm_pt = this->communicator_pt();
17350 
17351  // Set MPI info
17352  MPI_Status status;
17353  MPI_Request request;
17354 
17355  // loop over the processors
17356  for (unsigned iproc = 0; iproc < nproc; iproc++)
17357  {
17358  // The number of nodes shared between the pair of processors
17359  const unsigned n_shd_nodes_my_rank_iproc =
17360  node_on_shd_bnd_pt[iproc].size();
17361 
17362  // Are there shared nodes between these pair of processors
17363  // (my_rank, iproc)? Also ensure not to send info. within myself
17364  if (n_shd_nodes_my_rank_iproc > 0 && iproc != my_rank)
17365  {
17366  // The flat package to send the info, to the iproc processor
17367  Vector<unsigned> flat_package_unsigned_send;
17368  // The very first entry is the number of nodes shared by the
17369  // pair of processors (my_rank, iproc)
17370  flat_package_unsigned_send.push_back(n_shd_nodes_my_rank_iproc);
17371 
17372  // Get the number of shared nodes on original boundaries
17373  const unsigned n_global_shared_node_on_original_boundary =
17374  global_node_on_shared_bound[iproc].size();
17375 
17376  // The second data is the number of shared nodes on original
17377  // boundaries
17378  flat_package_unsigned_send.push_back(
17379  n_global_shared_node_on_original_boundary);
17380 
17381  // ... also send the zeta coordinates associated with the
17382  // original boundaries
17383  Vector<double> flat_package_double_send;
17384 
17385  // loop over the nodes shared between this pair of processors
17386  for (unsigned i = 0; i < n_global_shared_node_on_original_boundary; i++)
17387  {
17388  // Get the global shared node index
17389  const unsigned global_shared_node_index =
17390  global_node_on_shared_bound[iproc][i];
17391 
17392  // Put in the package the shared node index of the current
17393  // node
17394  flat_package_unsigned_send.push_back(global_shared_node_index);
17395 
17396  // Get the original boundaries to which the node is associated
17397  Vector<unsigned> on_original_boundaries =
17398  global_node_original_boundaries[iproc][i];
17399 
17400  // Get the associated zeta boundary coordinates
17401  Vector<double> zeta_coordinate =
17402  global_node_zeta_coordinate[iproc][i];
17403 
17404  // Get the number of original boundaries to which the node is
17405  // associated
17406  const unsigned n_original_boundaries = on_original_boundaries.size();
17407 
17408  // Put in the package the number of original boundaries the
17409  // node is associated
17410  flat_package_unsigned_send.push_back(n_original_boundaries);
17411 
17412  // loop over the original boundaries ids and include them in
17413  // the package
17414  for (unsigned j = 0; j < n_original_boundaries; j++)
17415  {
17416  // Put in the package each of the original boundaries to
17417  // which it is associated
17418  flat_package_unsigned_send.push_back(on_original_boundaries[j]);
17419  // The zeta coordinate on the boundary
17420  flat_package_double_send.push_back(zeta_coordinate[j]);
17421  } // for (j < n_original_boundaries)
17422 
17423  } // for (i < n_global_shared_node_on_original_boundary)
17424 
17425  // Send data UNSIGNED -----------------------------------------
17426  // Get the size of the package to communicate to the iproc
17427  // processor
17428  const unsigned n_udata_send = flat_package_unsigned_send.size();
17429  int n_udata_send_int = n_udata_send;
17430 
17431  // Send/receive data to/from iproc processor
17432  MPI_Isend(&n_udata_send_int,
17433  1,
17434  MPI_UNSIGNED,
17435  iproc,
17436  1,
17437  comm_pt->mpi_comm(),
17438  &request);
17439 
17440  int n_udata_received_int = 0;
17441  MPI_Recv(&n_udata_received_int,
17442  1,
17443  MPI_UNSIGNED,
17444  iproc,
17445  1,
17446  comm_pt->mpi_comm(),
17447  &status);
17448  MPI_Wait(&request, MPI_STATUS_IGNORE);
17449 
17450  if (n_udata_send != 0)
17451  {
17452  MPI_Isend(&flat_package_unsigned_send[0],
17453  n_udata_send,
17454  MPI_UNSIGNED,
17455  iproc,
17456  2,
17457  comm_pt->mpi_comm(),
17458  &request);
17459  }
17460 
17461  const unsigned n_udata_received =
17462  static_cast<unsigned>(n_udata_received_int);
17463 
17464  // Where to receive the data from the iproc processor
17465  Vector<unsigned> flat_package_unsigned_receive(n_udata_received);
17466 
17467  if (n_udata_received != 0)
17468  {
17469  MPI_Recv(&flat_package_unsigned_receive[0],
17470  n_udata_received,
17471  MPI_UNSIGNED,
17472  iproc,
17473  2,
17474  comm_pt->mpi_comm(),
17475  &status);
17476  }
17477 
17478  if (n_udata_send != 0)
17479  {
17480  MPI_Wait(&request, MPI_STATUS_IGNORE);
17481  }
17482 
17483  // Send data DOUBLE -----------------------------------------
17484  // Get the size of the package to communicate to the iproc
17485  // processor
17486  const unsigned n_ddata_send = flat_package_double_send.size();
17487  int n_ddata_send_int = n_ddata_send;
17488 
17489  // Send/receive data to/from iproc processor
17490  MPI_Isend(&n_ddata_send_int,
17491  1,
17492  MPI_UNSIGNED,
17493  iproc,
17494  1,
17495  comm_pt->mpi_comm(),
17496  &request);
17497 
17498  int n_ddata_received_int = 0;
17499  MPI_Recv(&n_ddata_received_int,
17500  1,
17501  MPI_UNSIGNED,
17502  iproc,
17503  1,
17504  comm_pt->mpi_comm(),
17505  &status);
17506  MPI_Wait(&request, MPI_STATUS_IGNORE);
17507 
17508  if (n_ddata_send != 0)
17509  {
17510  MPI_Isend(&flat_package_double_send[0],
17511  n_ddata_send,
17512  MPI_DOUBLE,
17513  iproc,
17514  2,
17515  comm_pt->mpi_comm(),
17516  &request);
17517  }
17518 
17519  const unsigned n_ddata_received =
17520  static_cast<unsigned>(n_ddata_received_int);
17521 
17522  // Where to receive the data from the iproc processor
17523  Vector<double> flat_package_double_receive(n_ddata_received);
17524 
17525  if (n_ddata_received != 0)
17526  {
17527  MPI_Recv(&flat_package_double_receive[0],
17528  n_ddata_received,
17529  MPI_DOUBLE,
17530  iproc,
17531  2,
17532  comm_pt->mpi_comm(),
17533  &status);
17534  }
17535 
17536  if (n_ddata_send != 0)
17537  {
17538  MPI_Wait(&request, MPI_STATUS_IGNORE);
17539  }
17540 
17541  // Unpackage -------------------------------------------------
17542  // ... and associate the nodes to the corresponding original
17543  // boundaries
17544 
17545  // The number of nodes to be received
17546  unsigned n_shared_nodes_received = flat_package_unsigned_receive[0];
17547 
17548  // Increase and decrease the number of received shared nodes to
17549  // avoid the warning when compiling without PARANOID
17550  n_shared_nodes_received++;
17551  n_shared_nodes_received--;
17552 
17553 #ifdef PARANOID
17554  if (n_shd_nodes_my_rank_iproc != n_shared_nodes_received)
17555  {
17556  std::ostringstream error_message;
17557  error_message
17558  << "The number of shared nodes between the pair of processors is\n"
17559  << "not the same\n"
17560  << "N.shared nodes proc (" << my_rank << ") with proc (" << iproc
17561  << "): (" << n_shd_nodes_my_rank_iproc << "\n"
17562  << "N.shared nodes proc (" << iproc << ") with proc (" << my_rank
17563  << "): (" << n_shared_nodes_received << "\n\n"
17564  << "You should have got the same error in proc: (" << iproc
17565  << ")\n\n";
17566  throw OomphLibError(error_message.str(),
17567  OOMPH_CURRENT_FUNCTION,
17568  OOMPH_EXCEPTION_LOCATION);
17569  } // if (n_shd_nodes_my_rank_iproc != n_shared_nodes_received)
17570 #endif
17571 
17572  // Skip the number of nodes on shared boundaries on original
17573  // boundaries received (that is why next lines are commented)
17574 
17575  // The number of nodes on shared boundaries on original
17576  // boundaries
17577  // const unsigned n_shared_nodes_on_original_boundaries_received =
17578  // flat_package_unsigned_receive[1];
17579 
17580  // loop over the received info.
17581  unsigned current_index_data = 2;
17582  unsigned current_index_ddata = 0;
17583  while (current_index_data < n_udata_received)
17584  {
17585  // The global shared node number
17586  const unsigned global_shared_node_index =
17587  flat_package_unsigned_receive[current_index_data++];
17588 
17589  // The pointer to the node
17590  Node* node_pt = 0;
17591 
17592  // The number of original boundaries the node is associated
17593  // with
17594  const unsigned n_original_boundaries =
17595  flat_package_unsigned_receive[current_index_data++];
17596 
17597  // Get the node pointer
17598  node_pt = global_shared_node_pt[global_shared_node_index];
17599 #ifdef PARANOID
17600  if (node_pt == 0)
17601  {
17602  std::ostringstream error_message;
17603  error_message
17604  << "The global shared node (" << global_shared_node_index << ") "
17605  << "could not be found in this processor!!!\n"
17606  << "However, it was found in processor (" << iproc << "). The "
17607  << "data may be no synchronised,\ntherefore "
17608  << "we may be looking for a global shared node number that "
17609  << "do not\ncorrespond with the one that was sent by "
17610  << "processor (" << iproc << ")\n\n";
17611  throw OomphLibError(error_message.str(),
17612  OOMPH_CURRENT_FUNCTION,
17613  OOMPH_EXCEPTION_LOCATION);
17614  }
17615 #endif // #ifdef PARANOID
17616 
17617  // loop over the number of original boundaries and associate
17618  // the node to each of those boundaries
17619  for (unsigned i = 0; i < n_original_boundaries; i++)
17620  {
17621  // Get the original boundary to which the node is associated
17622  // with
17623  const unsigned original_bound_id =
17624  flat_package_unsigned_receive[current_index_data++];
17625 
17626  // Associate the node with the boundary
17627  this->add_boundary_node(original_bound_id, node_pt);
17628 
17629  // Get the zeta boundary coordinate
17630  Vector<double> zeta(1);
17631  zeta[0] = flat_package_double_receive[current_index_ddata++];
17632  node_pt->set_coordinates_on_boundary(original_bound_id, zeta);
17633  }
17634 
17635  } // while(current_data < n_data_received)
17636 
17637  } // if ((node_on_shd_bnd_pt(iproc) > 0) && iproc!=my_rank)
17638 
17639  } // for (iproc < nproc)
17640 
17641  // ---------------------------------------------------------
17642  // END: Send the info. to the corresponding processors,
17643  // package the info, send it and receive it in the
17644  // corresponding processor, unpackage and set the
17645  // boundaries associated with the received nodes
17646  // ---------------------------------------------------------
17647  }
17648 
17649  //======================================================================
17650  // In charge of creating additional halo(ed) elements on those
17651  // processors that have no shared boundaries in common but have
17652  // shared nodes
17653  // ======================================================================
17654  template<class ELEMENT>
17656  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
17657  other_proc_shd_bnd_node_pt,
17658  Vector<Vector<Node*>>& iproc_currently_created_nodes_pt,
17659  Vector<Vector<Vector<unsigned>>>& global_node_names,
17660  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
17661  Vector<Node*>& global_shared_node_pt)
17662  {
17663  // Get the rank and number of processors
17664  const unsigned nproc = this->communicator_pt()->nproc();
17665  const unsigned my_rank = this->communicator_pt()->my_rank();
17666 
17667  // ---------------------------------------------------------------
17668  // BEGIN: Create a map to check whether a node is on the global
17669  // shared nodes. Also set a map to obtain the global
17670  // shared node index (this index is the same as the global
17671  // node name)
17672  // ---------------------------------------------------------------
17673  std::map<Node*, bool> is_global_shared_node;
17674  std::map<Node*, unsigned> global_shared_node_index;
17675 
17676  // Get the number of global shared nodes
17677  const unsigned n_global_shared_nodes = global_shared_node_pt.size();
17678  // loop over the global shared nodes
17679  for (unsigned i = 0; i < n_global_shared_nodes; i++)
17680  {
17681  // Get the node
17682  Node* node_pt = global_shared_node_pt[i];
17683  // Indicate this is a shared global node
17684  is_global_shared_node[node_pt] = true;
17685  // Set the map to obtain the index of the global shared node
17686  global_shared_node_index[node_pt] = i;
17687 
17688  } // for (i < n_global_shared_nodes)
17689 
17690  // ---------------------------------------------------------------
17691  // END: Create a map to check whether a node is on the global
17692  // shared nodes. Also set a map to obtain the global
17693  // shared node index (this index is the same as the global
17694  // node name)
17695  // ---------------------------------------------------------------
17696 
17697  // ---------------------------------------------------------------
17698  // BEGIN: Loop over the haloed elements and check whether the nodes
17699  // on the haloed elements are part of the global shared
17700  // nodes. If that is the case then check whether the
17701  // element should be sent to the processors with which the
17702  // node is shared
17703  // ---------------------------------------------------------------
17704 
17705  // Elements that may be sent to other processors
17706  Vector<std::set<GeneralisedElement*>> additional_elements_pt(nproc);
17707 
17708  // loop over the processors
17709  for (unsigned iproc = 0; iproc < nproc; iproc++)
17710  {
17711  if (iproc != my_rank)
17712  {
17713  // Get the haloed element with iproc
17714  Vector<GeneralisedElement*> haloed_ele_pt =
17715  this->root_haloed_element_pt(iproc);
17716 
17717  // Get the number of haloed elements
17718  const unsigned n_haloed_ele = this->nroot_haloed_element(iproc);
17719 
17720  // loop over the haloed elements with iproc
17721  for (unsigned ihd = 0; ihd < n_haloed_ele; ihd++)
17722  {
17723  // A pointer to the generalised element
17724  GeneralisedElement* gele_pt = haloed_ele_pt[ihd];
17725  // Get the finite element representation of the element
17726  FiniteElement* ele_pt = dynamic_cast<FiniteElement*>(gele_pt);
17727  // Get the number of nodes
17728  const unsigned n_nodes = ele_pt->nnode();
17729  // loop over the nodes of the element
17730  for (unsigned n = 0; n < n_nodes; n++)
17731  {
17732  // Get the node
17733  Node* node_pt = ele_pt->node_pt(n);
17734  // Is the node a global shared node?
17735  if (is_global_shared_node[node_pt])
17736  {
17737  // Get the index of the global shared node
17738  const unsigned global_index = global_shared_node_index[node_pt];
17739  // Get the global names of the node
17740  Vector<Vector<unsigned>> iglobal_names =
17741  global_node_names[global_index];
17742 
17743  // Get the number of names
17744  const unsigned n_names = iglobal_names.size();
17745  // loop over the names and check which processors share
17746  // this node (the processors to which the element may be
17747  // sent
17748  for (unsigned j = 0; j < n_names; j++)
17749  {
17750  // Get the processors to which the element should be
17751  // sent
17752  const unsigned proc1 = iglobal_names[j][0];
17753  const unsigned proc2 = iglobal_names[j][1];
17754  // Add the element to the set of additional elements to
17755  // sent from proc1 to proc2
17756  additional_elements_pt[proc1].insert(gele_pt);
17757  additional_elements_pt[proc2].insert(gele_pt);
17758 
17759  } // for (j < n_names)
17760 
17761  } // if (is_global_shared_node[node_pt])
17762 
17763  } // for (n < n_nodes)
17764 
17765  } // for (ihd < n_haloed_ele)
17766 
17767  } // if (iproc!=my_rank)
17768 
17769  } // for (iproc < nproc)
17770 
17771  // ---------------------------------------------------------------
17772  // Now check whether the element should really be sent to the
17773  // indicated processors
17774 
17775  // The elements from this (my_rank) processor that will be sent to
17776  // other processors
17777  Vector<Vector<FiniteElement*>> send_haloed_ele_pt(nproc);
17778 
17779  // loop over the processors
17780  for (unsigned iproc = 0; iproc < nproc; iproc++)
17781  {
17782  if (iproc != my_rank)
17783  {
17784  // Get the set of element that may be sent to the iproc
17785  // processor
17786  std::set<GeneralisedElement*> iproc_ele_pt =
17787  additional_elements_pt[iproc];
17788  // loop over the element that may be sent to the iproc
17789  // processor
17790  for (std::set<GeneralisedElement*>::iterator it = iproc_ele_pt.begin();
17791  it != iproc_ele_pt.end();
17792  it++)
17793  {
17794  // Get a pointer to the element
17795  GeneralisedElement* gele_pt = (*it);
17796 
17797  // Get the haloed element with iproc
17798  Vector<GeneralisedElement*> haloed_ele_pt =
17799  this->root_haloed_element_pt(iproc);
17800 
17801  // Get the number of haloed elements
17802  const unsigned n_haloed_ele = this->nroot_haloed_element(iproc);
17803 
17804  // Flag to indicate whether the element has been already sent
17805  // to the iproc processor
17806  bool send_ele_to_iproc_processor = true;
17807  // loop over the haloed elements with iproc and check whether
17808  // the element has been already sent to iproc (if it is
17809  // already a haloed element with iproc then it has been
17810  // already sent)
17811  for (unsigned ihd = 0; ihd < n_haloed_ele; ihd++)
17812  {
17813  // A pointer to the generalised element
17814  GeneralisedElement* ghd_ele_pt = haloed_ele_pt[ihd];
17815  if (gele_pt == ghd_ele_pt)
17816  {
17817  // Mark the element as not required to be sent
17818  send_ele_to_iproc_processor = false;
17819  // Break the loop that searchs for the element on the
17820  // haloed elements with iproc
17821  break;
17822  }
17823 
17824  } // for (ihd < n_haloed_ele)
17825 
17826  // Do we need to sent the element?
17827  if (send_ele_to_iproc_processor)
17828  {
17829  // Get the finite element representation of the element
17830  FiniteElement* ele_pt = dynamic_cast<FiniteElement*>(gele_pt);
17831  // Add the element to those that will be sent to the iproc
17832  // processor
17833  send_haloed_ele_pt[iproc].push_back(ele_pt);
17834  }
17835 
17836  } // loop over the elements that may be sent to the iproc
17837  // processor
17838 
17839  } // if (iproc!=my_rank)
17840 
17841  } // for (iproc < nproc)
17842 
17843  // ---------------------------------------------------------------
17844  // END: Loop over the haloed element and check whether the nodes
17845  // on the haloed elements are part of the global shared
17846  // nodes. If that is the case then check whether the element
17847  // should be sent to the processors with which the node is
17848  // shared
17849  // ---------------------------------------------------------------
17850 
17851  // ============================================================
17852  // Now send the additional elements
17853  // ============================================================
17854  // Loop over the processors to send data
17855  for (unsigned iproc = 0; iproc < nproc; iproc++)
17856  {
17857  // There are no elements to send with myself
17858  if (iproc != my_rank)
17859  {
17860  // Get the number of additional haloed elements to send
17861  const unsigned n_additional_haloed_ele =
17862  send_haloed_ele_pt[iproc].size();
17863 
17864  // Clear send and receive buffers
17865  Flat_packed_unsigneds.clear();
17866  Flat_packed_doubles.clear();
17867 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17868  Flat_packed_unsigneds_string.clear();
17869 #endif
17870 
17871  // The very first data of the flat packed is the number of
17872  // additional haloed elements, this will be the number of
17873  // additional halo elements to create on the receiver processor
17874  Flat_packed_unsigneds.push_back(n_additional_haloed_ele);
17875 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17876  std::stringstream junk;
17877  junk << "Number of haloed elements " << nhaloed_ele;
17878  Flat_packed_unsigneds_string.push_back(junk.str());
17879 #endif
17880 
17881  // Loop over the additioanl haloed elements
17882  for (unsigned e = 0; e < n_additional_haloed_ele; e++)
17883  {
17884  // Get pointer to the additional haloed element
17885  FiniteElement* ele_pt = send_haloed_ele_pt[iproc][e];
17886  const unsigned nroot_haloed_ele = this->nroot_haloed_element(iproc);
17887 
17888  // Check if the element has been already added to the
17889  // halo(ed) scheme
17890 
17891  // Get the generalised version of the element
17892  GeneralisedElement* gen_ele_pt = ele_pt;
17893  // Try to add the haloed element
17894  const unsigned haloed_ele_index =
17895  this->try_to_add_root_haloed_element_pt(iproc, gen_ele_pt);
17896 
17897  // Was the element added or only returned the index of the
17898  // element
17899  if (nroot_haloed_ele == haloed_ele_index)
17900  {
17901  Flat_packed_unsigneds.push_back(1);
17902 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17903  Flat_packed_unsigneds_string.push_back(
17904  "Haloed element needs to be constructed");
17905 #endif
17906 
17907  // Get additional info. related with the haloed element
17908  get_required_elemental_information_helper(iproc, ele_pt);
17909 
17910  // Get the nodes on the element
17911  const unsigned nnodes = ele_pt->nnode();
17912  for (unsigned j = 0; j < nnodes; j++)
17913  {
17914  Node* node_pt = ele_pt->node_pt(j);
17915 
17916  // Package the info. of the nodes
17917  // The destination processor goes in the arguments
17918  add_haloed_node_helper(iproc, node_pt);
17919 
17920  } // for (j < nnodes)
17921 
17922  } // add the element and send its nodes
17923  else // The haloed element already exists
17924  {
17925  Flat_packed_unsigneds.push_back(0);
17926 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17927  Flat_packed_unsigneds_string.push_back(
17928  "Haloed element already exists");
17929 #endif
17930  Flat_packed_unsigneds.push_back(haloed_ele_index);
17931 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17932  Flat_packed_unsigneds_string.push_back(
17933  "Index of existing haloed element");
17934 #endif
17935  } // else (next_haloed_ele == external_haloed_ele_index)
17936 
17937  } // for (e < n_additional_haloed_ele)
17938 
17939  // Send and received the additional haloed elements (all
17940  // processors send and receive)
17941 
17942  // The processor to which send the elements
17943  int send_proc = static_cast<int>(iproc);
17944  // The processor from which receive the elements
17945  int recv_proc = static_cast<int>(iproc);
17946  send_and_receive_elements_nodes_info(send_proc, recv_proc);
17947 
17948  // Reset the counters
17949  Counter_for_flat_packed_doubles = 0;
17950  Counter_for_flat_packed_unsigneds = 0;
17951 
17952  // Get the number of additional halo element to be created
17953  const unsigned n_additional_halo_ele =
17954  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
17955 
17956 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17957  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
17958  << " Number of elements need to be constructed "
17959  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
17960  << std::endl;
17961 #endif
17962 
17963  // Create the additional halo elements
17964  for (unsigned e = 0; e < n_additional_halo_ele; e++)
17965  {
17966  // Create halo element from received info. of "iproc"
17967  // processor on the current processor
17968  create_halo_element(iproc,
17969  iproc_currently_created_nodes_pt[iproc],
17970  other_proc_shd_bnd_node_pt,
17971  global_node_names,
17972  node_name_to_global_index,
17973  global_shared_node_pt);
17974 
17975  } // for (e < n_additional_halo_ele)
17976 
17977  } // if (iproc != my_rank)
17978 
17979  } // for (iproc < nproc)
17980  }
17981 
17982  // *********************************************************************
17983  // Start communication functions
17984  // *********************************************************************
17985 
17986  //========start of get_required_elemental_information_helper==============
17987  /// Helper function to get the required elemental information from
17988  /// an haloed element. This info. involves the association of the element
17989  /// to a boundary or region.
17990  //========================================================================
17991  template<class ELEMENT>
17993  ELEMENT>::get_required_elemental_information_helper(unsigned& iproc,
17994  FiniteElement* ele_pt)
17995  {
17996  // Check if the element is associated with the original boundaries
17997  const unsigned nbound = this->initial_shared_boundary_id();
17998 
17999  // ------------------------------------------------------------------
18000  // Stores the information regarding the boundaries associated to the
18001  // element (it that is the case)
18002  Vector<unsigned> associated_boundaries;
18003  Vector<unsigned> face_index_on_boundary;
18004 
18005  unsigned counter_face_indexes = 0;
18006 
18007  for (unsigned b = 0; b < nbound; b++)
18008  {
18009  // Get the number of elements associated to boundary i
18010  const unsigned nboundary_ele = nboundary_element(b);
18011  for (unsigned e = 0; e < nboundary_ele; e++)
18012  {
18013  if (ele_pt == this->boundary_element_pt(b, e))
18014  {
18015  // Keep track of the boundaries associated to the element
18016  associated_boundaries.push_back(b);
18017  // Get the face index
18018  face_index_on_boundary.push_back(face_index_at_boundary(b, e));
18019  counter_face_indexes++;
18020 #ifdef PARANOID
18021  if (counter_face_indexes > 2)
18022  {
18023  std::stringstream error_message;
18024  error_message
18025  << "A triangular element can not have more than two of its faces "
18026  << "on a boundary!!!\n\n";
18027  throw OomphLibError(error_message.str(),
18028  OOMPH_CURRENT_FUNCTION,
18029  OOMPH_EXCEPTION_LOCATION);
18030  }
18031 #else
18032  // Already found 2 face indexes on the same boundary?
18033  if (counter_face_indexes == 2)
18034  {
18035  break;
18036  }
18037 #endif // #ifdef PARANOID
18038 
18039  } // if (ele_pt == this->boundary_element_pt(b,e))
18040 
18041  } // (e < nboundary_ele)
18042 
18043  } // (b < nbound)
18044 
18045  // If the element is associated to any boundary then package all the
18046  // relevant info
18047  const unsigned nassociated_boundaries = associated_boundaries.size();
18048  if (nassociated_boundaries > 0)
18049  {
18050  Flat_packed_unsigneds.push_back(1);
18051 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18052  Flat_packed_unsigneds_string.push_back(
18053  "The element is a boundary element");
18054 #endif
18055  Flat_packed_unsigneds.push_back(nassociated_boundaries);
18056 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18057  std::stringstream junk;
18058  junk << "The elements is associated to " << nassociated_boundaries
18059  << " boundaries";
18060  Flat_packed_unsigneds_string.push_back(junk.str());
18061 #endif
18062 
18063  // Package the ids of the associated boundaries and the
18064  // corresponding face index for each boundary (if the element is a
18065  // corner element, it will have two faces associated to the
18066  // boundary)
18067  for (unsigned i = 0; i < nassociated_boundaries; i++)
18068  {
18069  unsigned b = associated_boundaries[i];
18070  Flat_packed_unsigneds.push_back(b);
18071 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18072  std::stringstream junk;
18073  junk << "Element associated to boundary " << b << " of "
18074  << nassociated_boundaries << " total associated boundaries";
18075  Flat_packed_unsigneds_string.push_back(junk.str());
18076 #endif
18077  unsigned f = face_index_on_boundary[i];
18078  Flat_packed_unsigneds.push_back(f);
18079 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18080  std::stringstream junk2;
18081  junk2 << "Face index " << f << " for associated boundary " << b;
18082  Flat_packed_unsigneds_string.push_back(junk2.str());
18083 #endif
18084  }
18085 
18086  // If the element is associated to any boundary then we should
18087  // check if the mesh has regions, if that is the case then we need
18088  // to check to which region the boundary element does belong
18089 
18090  // If the mesh has regions we should look for the element
18091  // associated to a boundary and a specified region
18092  Vector<Vector<unsigned>> associated_boundaries_and_regions;
18093  Vector<unsigned> face_index_on_boundary_and_region;
18094 
18095  // Now check for the case when we have regions in the mesh
18096  const unsigned n_regions = this->nregion();
18097  if (n_regions > 1)
18098  {
18099  // Used to count the number of faces associated with
18100  // boundary-regions
18101  unsigned counter_face_indexes_in_regions = 0;
18102  // Loop over the boundaries
18103  for (unsigned b = 0; b < nbound; b++)
18104  {
18105  // Go through each region by getting the region id
18106  for (unsigned i_reg = 0; i_reg < n_regions; i_reg++)
18107  {
18108  // Get thre region id associated with the (i_reg)-th region
18109  const unsigned region_id =
18110  static_cast<unsigned>(this->Region_attribute[i_reg]);
18111 
18112  // Loop over all elements associated with the current boundary
18113  // and the i_reg-th region and check if the element is part of
18114  // any region
18115  const unsigned nele_in_region =
18116  this->nboundary_element_in_region(b, region_id);
18117  for (unsigned ee = 0; ee < nele_in_region; ee++)
18118  {
18119  // Check if the boundary-region element is the same as the
18120  // element
18121  if (ele_pt ==
18122  this->boundary_element_in_region_pt(b, region_id, ee))
18123  {
18124  // Storage for the boundary and region associated to the
18125  // element
18126  Vector<unsigned> bound_and_region(2);
18127 
18128  // Keep track of the boundaries associated to the element
18129  bound_and_region[0] = b;
18130  // Keep track of the regions associated to the element
18131  bound_and_region[1] = region_id;
18132  // Add the boundaries and regions in the storage to be
18133  // sent to other processors
18134  associated_boundaries_and_regions.push_back(bound_and_region);
18135  // Get the face index and keep track of it
18136  face_index_on_boundary_and_region.push_back(
18137  this->face_index_at_boundary_in_region(b, region_id, ee));
18138 
18139  // Increase the number of faces of the element associated
18140  // to boundary-regions
18141  counter_face_indexes_in_regions++;
18142 
18143 #ifdef PARANOID
18144  if (counter_face_indexes_in_regions > 2)
18145  {
18146  std::stringstream error_message;
18147  error_message << "A triangular element can not have more "
18148  "than two of its\n"
18149  << "faces on a boundary!!!\n\n";
18150  throw OomphLibError(error_message.str(),
18151  OOMPH_CURRENT_FUNCTION,
18152  OOMPH_EXCEPTION_LOCATION);
18153  } // if (counter_face_indexes_in_regions > 2)
18154 #endif
18155 
18156  } // The element is a boundary-region element
18157 
18158  } // for (ee < nele_in_region)
18159 
18160  } // for (i_reg < n_regions)
18161 
18162  } // for (b < nbound)
18163 
18164  } // if (n_regions > 1)
18165 
18166  // Now package the info. to be sent to other processors
18167  const unsigned nassociated_boundaries_and_regions =
18168  associated_boundaries_and_regions.size();
18169  if (nassociated_boundaries_and_regions > 0)
18170  {
18171  Flat_packed_unsigneds.push_back(1);
18172 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18173  Flat_packed_unsigneds_string.push_back(
18174  "The element is associated to boundaries and regions");
18175 #endif
18176 
18177  Flat_packed_unsigneds.push_back(nassociated_boundaries_and_regions);
18178 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18179  std::stringstream junk;
18180  junk << "The element is associated to "
18181  << nassociated_boundaries_and_regions << " boundaries-regions";
18182  Flat_packed_unsigneds_string.push_back(junk.str());
18183 #endif
18184 
18185  // Package the ids of the associated boundaries, regions and the
18186  // corresponding face index for each boundary-region (if the
18187  // element is a corner element, it will have two faces
18188  // associated to the boundary-region)
18189  for (unsigned i = 0; i < nassociated_boundaries_and_regions; i++)
18190  {
18191  const unsigned b = associated_boundaries_and_regions[i][0];
18192  Flat_packed_unsigneds.push_back(b);
18193 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18194  std::stringstream junk;
18195  junk << "Element associated to boundary " << b << " of "
18196  << nassociated_boundaries_and_regions
18197  << " total associated boundaries-regions";
18198  Flat_packed_unsigneds_string.push_back(junk.str());
18199 #endif
18200 
18201  const unsigned r = associated_boundaries_and_regions[i][1];
18202  Flat_packed_unsigneds.push_back(r);
18203 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18204  std::stringstream junk2;
18205  junk2 << "Element associated to region " << r << " of "
18206  << nassociated_boundaries_and_regions
18207  << " total associated boundaries-regions";
18208  Flat_packed_unsigneds_string.push_back(junk2.str());
18209 #endif
18210 
18211  const unsigned f = face_index_on_boundary_and_region[i];
18212  Flat_packed_unsigneds.push_back(f);
18213 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18214  std::stringstream junk3;
18215  junk3 << "Face index " << f << " for associated boundary-region ("
18216  << b << "-" << r << ")";
18217  Flat_packed_unsigneds_string.push_back(junk3.str());
18218 #endif
18219  } // for (i < nassociated_boundaries_and_regions)
18220  } // if (nassociated_boundaries_and_regions > 0)
18221  else
18222  {
18223  Flat_packed_unsigneds.push_back(0);
18224 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18225  Flat_packed_unsigneds_string.push_back(
18226  "The element is NOT associated to boundaries and regions");
18227 #endif
18228  } // else if (nassociated_boundaries_and_regions > 0)
18229  }
18230  else
18231  {
18232  Flat_packed_unsigneds.push_back(0);
18233 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18234  Flat_packed_unsigneds_string.push_back(
18235  "The element is not associated to any original boundary");
18236 #endif
18237  }
18238 
18239  // ------------------------------------------------------------
18240  // Now review if the element is associated to a shared boundary
18241 
18242  // Store the shared boundaries, and therefore the face indexes
18243  // associated to the element
18244  Vector<unsigned> associated_shared_boundaries;
18245  Vector<unsigned> face_index_on_shared_boundary;
18246 
18247  // Get the shared boundaries in this processor
18248  Vector<unsigned> my_rank_shared_boundaries_ids;
18249  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
18250 
18251  // Get the number of shared boundaries
18252  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
18253  // Loop over the shared boundaries
18254  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
18255  {
18256  // Get the boundary id
18257  const unsigned sb = my_rank_shared_boundaries_ids[i];
18258 
18259  // Get the number of elements associated to shared boundary sb
18260  const unsigned nboundary_ele = this->nshared_boundary_element(sb);
18261  for (unsigned e = 0; e < nboundary_ele; e++)
18262  {
18263  if (ele_pt == this->shared_boundary_element_pt(sb, e))
18264  {
18265  // Keep track of the boundaries associated to the element
18266  associated_shared_boundaries.push_back(sb);
18267  // Get the face index
18268  face_index_on_shared_boundary.push_back(
18269  this->face_index_at_shared_boundary(sb, e));
18270  }
18271  } // (e < nboundary_ele)
18272  } // (i < nmy_rank_shd_bnd)
18273 
18274  // If the element is associated to a shared boundary then package
18275  // all the relevant info
18276  const unsigned nassociated_shared_boundaries =
18277  associated_shared_boundaries.size();
18278  if (nassociated_shared_boundaries > 0)
18279  {
18280  Flat_packed_unsigneds.push_back(3);
18281 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18282  Flat_packed_unsigneds_string.push_back(
18283  "The element is a shared boundary element");
18284 #endif
18285  Flat_packed_unsigneds.push_back(nassociated_shared_boundaries);
18286 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18287  std::stringstream junk;
18288  junk << "The elements is associated to " << nassociated_shared_boundaries
18289  << "shared boundaries";
18290  Flat_packed_unsigneds_string.push_back(junk.str());
18291 #endif
18292 
18293  // Package the ids of the associated boundaries
18294  for (unsigned i = 0; i < nassociated_shared_boundaries; i++)
18295  {
18296  const unsigned b = associated_shared_boundaries[i];
18297  Flat_packed_unsigneds.push_back(b);
18298 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18299  std::stringstream junk;
18300  junk << "Element associated to shared boundary " << b << " of "
18301  << nassociated_shared_boundaries << " total associated boundaries";
18302  Flat_packed_unsigneds_string.push_back(junk.str());
18303 #endif
18304 
18305  const unsigned f = face_index_on_shared_boundary[i];
18306  Flat_packed_unsigneds.push_back(f);
18307 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18308  std::stringstream junk2;
18309  junk2 << "Face index " << f << " for associated shared boundary " << b;
18310  Flat_packed_unsigneds_string.push_back(junk2.str());
18311 #endif
18312  }
18313  }
18314  else
18315  {
18316  Flat_packed_unsigneds.push_back(0);
18317 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18318  Flat_packed_unsigneds_string.push_back(
18319  "The element is not associated to any shared boundary");
18320 #endif
18321  }
18322  }
18323 
18324  //========start of get_required_nodal_information_helper==================
18325  /// Helper function to get the required nodal information from an
18326  /// haloed node so that a fully-functional halo node (and therefore element)
18327  /// can be created on the receiving process
18328  //========================================================================
18329  template<class ELEMENT>
18331  unsigned& iproc, Node* nod_pt)
18332  {
18333  unsigned my_rank = this->communicator_pt()->my_rank();
18334  const unsigned nproc = this->communicator_pt()->nproc();
18335 
18336  // Tell the halo copy of this node how many values there are
18337  // [NB this may be different for nodes within the same element, e.g.
18338  // when using Lagrange multipliers]
18339  unsigned n_val = nod_pt->nvalue();
18340  Flat_packed_unsigneds.push_back(n_val);
18341 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18342  Flat_packed_unsigneds_string.push_back("Number of values");
18343 #endif
18344 
18345  unsigned n_dim = nod_pt->ndim();
18346 
18347  // Default number of previous values to 1
18348  unsigned n_prev = 1;
18349  if (this->Time_stepper_pt != 0)
18350  {
18351  // Add number of history values to n_prev
18352  n_prev = this->Time_stepper_pt->ntstorage();
18353  }
18354 
18355  // -----------------------------------------------------
18356  // Is the node on an original boundary?
18357  // Store the original boundaries where the node may be
18358  Vector<unsigned> original_boundaries;
18359  // Loop over the original boundaries of the mesh and check if live
18360  // on one of them
18361  const unsigned n_bnd = this->initial_shared_boundary_id();
18362  for (unsigned bb = 0; bb < n_bnd; bb++)
18363  {
18364  // Which boundaries (could be more than one) is it on?
18365  if (nod_pt->is_on_boundary(bb))
18366  {
18367  original_boundaries.push_back(bb);
18368  }
18369  }
18370 
18371  const unsigned n_original_boundaries = original_boundaries.size();
18372  // Is the node on any original boundary?
18373  if (n_original_boundaries > 0)
18374  {
18375  // Indicate that the node is on an original boundary
18376  Flat_packed_unsigneds.push_back(2);
18377 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18378  Flat_packed_unsigneds_string.push_back(
18379  "Node is on the original boundaries");
18380 #endif
18381 
18382  Flat_packed_unsigneds.push_back(n_original_boundaries);
18383 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18384  std::stringstream junk;
18385  junk << "Node is on " << n_original_boundaries << " original boundaries";
18386  Flat_packed_unsigneds_string.push_back(junk.str());
18387 #endif
18388 
18389  // Loop over the original boundaries the node is on
18390  for (unsigned i = 0; i < n_original_boundaries; i++)
18391  {
18392  Flat_packed_unsigneds.push_back(original_boundaries[i]);
18393 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18394  std::stringstream junk;
18395  junk << "Node is on boundary " << original_boundaries[i] << " of "
18396  << nb;
18397  Flat_packed_unsigneds_string.push_back(junk.str());
18398 #endif
18399  // Get the boundary coordinate of the node
18400  Vector<double> zeta(1);
18401  nod_pt->get_coordinates_on_boundary(original_boundaries[i], zeta);
18402  Flat_packed_doubles.push_back(zeta[0]);
18403  }
18404  }
18405  else
18406  {
18407  // Indicate that the node is NOT on an original boundary
18408  Flat_packed_unsigneds.push_back(0);
18409 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18410  Flat_packed_unsigneds_string.push_back(
18411  "Node is on any original boundary");
18412 #endif
18413  }
18414 
18415  // -------------------------------------------------------
18416  // Is the node on shared boundaries?
18417  bool node_on_shared_boundary = false;
18418  // Loop over the shared boundaries with the iproc processors and
18419  // check if live on one of them
18420  const unsigned n_shd_bnd = this->nshared_boundaries(my_rank, iproc);
18421  for (unsigned bb = 0; bb < n_shd_bnd; bb++)
18422  {
18423  // Get the boundary id
18424  unsigned i_bnd = this->shared_boundaries_ids(my_rank, iproc, bb);
18425  // Which boundaries (could be more than one) is it on?
18426  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
18427  {
18428  node_on_shared_boundary = true;
18429  break;
18430  }
18431  }
18432 
18433  // If the node live on any of the shared boundaries with the iproc
18434  // processor then just get the node number according to the
18435  // sorted_shared_boundary_node_pt() scheme and send it accross
18436  if (node_on_shared_boundary)
18437  {
18438  Flat_packed_unsigneds.push_back(1);
18439 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18440  Flat_packed_unsigneds_string.push_back("Node is on shared boundary");
18441 #endif
18442 
18443  // Store the shared boundaries where the node is on
18444  Vector<unsigned> shd_boundaries;
18445  // Loop over the shared boundaries with the iproc processor
18446  for (unsigned bb = 0; bb < n_shd_bnd; bb++)
18447  {
18448  // Get the boundary id
18449  const unsigned i_bnd = this->shared_boundaries_ids(my_rank, iproc, bb);
18450  // Which boundaries (could be more than one) is it on?
18451  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
18452  {
18453  shd_boundaries.push_back(i_bnd);
18454  }
18455  }
18456 
18457  // Get the number of shared boundaries the node is on
18458  const unsigned n_shd_bnd_is_on = shd_boundaries.size();
18459  // Send the number of shared boundaries the node is on
18460  Flat_packed_unsigneds.push_back(n_shd_bnd_is_on);
18461 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18462  std::stringstream junk;
18463  junk << "Node is on " << n_shd_bnd_is_on << " shared boundaries";
18464  Flat_packed_unsigneds_string.push_back(junk.str());
18465 #endif
18466 
18467  // Loop over the shared boundaries to send their ids
18468  for (unsigned i = 0; i < n_shd_bnd_is_on; i++)
18469  {
18470  Flat_packed_unsigneds.push_back(shd_boundaries[i]);
18471 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18472  std::stringstream junk;
18473  junk << "Node is on boundary " << shd_boundaries[i] << " of " << nb;
18474  Flat_packed_unsigneds_string.push_back(junk.str());
18475 #endif
18476  }
18477 
18478  // Given that the node is on at least one boundary get the index
18479  // of the node in one of the boundaries and send this index
18480  unsigned shared_boundary_id = shd_boundaries[0];
18481  // Get the number of nodes on the given shared boundary
18482  const unsigned n_nodes_on_shared_boundary =
18483  nsorted_shared_boundary_node(shared_boundary_id);
18484  // Store the index of the node on the shared boundary
18485  unsigned index_node_on_shared_boundary;
18486 #ifdef PARANOID
18487  // Flag to know if the node has been found
18488  bool found_index_node_on_shared_boundary = false;
18489 #endif
18490  // Loop over the nodes on the shared boundary to find the node
18491  for (unsigned i = 0; i < n_nodes_on_shared_boundary; i++)
18492  {
18493  // Get the i-th node on the shared boundary
18494  Node* shared_node_pt =
18495  sorted_shared_boundary_node_pt(shared_boundary_id, i);
18496  // Is the node we are looking for
18497  if (shared_node_pt == nod_pt)
18498  {
18499  // Store the index
18500  index_node_on_shared_boundary = i;
18501 #ifdef PARANOID
18502  // Mark as found
18503  found_index_node_on_shared_boundary = true;
18504 #endif
18505  break; // break
18506  }
18507 
18508  } // for (i < nnodes_on_shared_boundary)
18509 
18510 #ifdef PARANOID
18511  if (!found_index_node_on_shared_boundary)
18512  {
18513  std::ostringstream error_message;
18514  error_message << "The index of the node on boundary ("
18515  << shared_boundary_id << ") was not found.\n"
18516  << "The node coordinates are (" << nod_pt->x(0) << ","
18517  << nod_pt->x(1) << ").\n";
18518  throw OomphLibError(
18519  error_message.str(),
18520  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18521  OOMPH_EXCEPTION_LOCATION);
18522  }
18523 #endif
18524  // Send the index of the node on the shared boundary
18525  Flat_packed_unsigneds.push_back(index_node_on_shared_boundary);
18526 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18527  std::stringstream junk2;
18528  junk2 << "Node index on boundary " << boundaries[0] << " is "
18529  << index_node_on_shared_boundary;
18530  Flat_packed_unsigneds_string.push_back(junk2.str());
18531 #endif
18532 
18533  } // if (node_on_shared_boundary)
18534  else
18535  {
18536  // The node is not on a shared boundary
18537  Flat_packed_unsigneds.push_back(0);
18538 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18539  Flat_packed_unsigneds_string.push_back(
18540  "Node is not on a shared boundary");
18541 #endif
18542  }
18543 
18544  // ----------------------------------------------------------------
18545  // Is the node on any shared boundary where the receiver processor
18546  // is not involved?
18547 
18548  // Now check if the node is on a shared boundary created by the
18549  // current processor (my_rank) and other processor different that
18550  // the iproc processor. This info. will help to complete the sending
18551  // of halo(ed) information between processors
18552 
18553  // Flag to know if the node is on a shared boundary with other
18554  // processor
18555  bool node_on_shared_boundary_with_other_processors = false;
18556  // Count the number of other shared boundaries it could be on
18557  unsigned nshared_boundaries_with_other_processors_have_node = 0;
18558 
18559  // Loop over the shared boundaries of the sent processor (my_rank)
18560  // and other processors (jproc)
18561  for (unsigned jproc = 0; jproc < nproc; jproc++)
18562  {
18563  // Do not search with the iproc processor , that was done before
18564  // above because we are sending info to that processor
18565  if (jproc != iproc)
18566  {
18567  // Get the number of shared boundaries with the jproc processor
18568  const unsigned n_jshd_bnd = this->nshared_boundaries(my_rank, jproc);
18569  // Loop over the shared boundaries
18570  for (unsigned bb = 0; bb < n_jshd_bnd; bb++)
18571  {
18572  // Get the boundary id
18573  const unsigned j_shd_bnd =
18574  this->shared_boundaries_ids(my_rank, jproc, bb);
18575  // Is the node part of this boundary?
18576  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
18577  {
18578  // DEBP("Sending to");
18579  // DEBP(iproc);
18580  // DEBP("Pair of procs where other shared");
18581  // DEBP(my_rank);
18582  // DEBP(jproc);
18583  // DEBP(i_bnd);
18584  node_on_shared_boundary_with_other_processors = true;
18585  // Increase the counter for the number of shared boundaries
18586  // with other processors the node is on
18587  nshared_boundaries_with_other_processors_have_node++;
18588  } // if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt)
18589 
18590  } // for (bb<n_jshd_bnd)
18591 
18592  } // if (jproc != iproc)
18593 
18594  } // for (jproc < nproc)
18595 
18596  // If the node is on a shared boundary with another processor
18597  // (my_rank, jproc), then send the flag and look for the info.
18598  if (node_on_shared_boundary_with_other_processors)
18599  {
18600  Flat_packed_unsigneds.push_back(4);
18601 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18602  Flat_packed_unsigneds_string.push_back(
18603  "Node is on shared boundary no related with the received processor: 4");
18604 #endif
18605 
18606  // The number of packages of information that will be sent to the
18607  // "iproc" processor. This helps to know how many packages of data
18608  // read from the received processor
18609  Flat_packed_unsigneds.push_back(
18610  nshared_boundaries_with_other_processors_have_node);
18611 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18612  std::stringstream junk;
18613  junk << "Number of other shared boundaries that the node is on: "
18614  << nshared_boundaries_with_other_processors_have_node;
18615  Flat_packed_unsigneds_string.push_back(junk.str());
18616 #endif
18617 
18618  // Counter to ensure that the correct number of data has been sent
18619  unsigned counter_shd_bnd_with_other_procs_have_node = 0;
18620  // Loop over the shared boundaries with other processors and get:
18621  // 1) The processors defining the shared boundary
18622  // 2) The shared boundary id
18623  // 3) The index of the node on the shared boundary
18624  Vector<unsigned> other_processor_1;
18625  Vector<unsigned> other_processor_2;
18626  Vector<unsigned> shd_bnd_ids;
18627  Vector<unsigned> indexes;
18628  // Loop over the processors again
18629  for (unsigned jproc = 0; jproc < nproc; jproc++)
18630  {
18631  // Do not search with the iproc processor, that was done before
18632  // above
18633  if (jproc != iproc)
18634  {
18635  // Get the number of shared boundaries with the jproc
18636  // processor
18637  const unsigned n_jshd_bnd = this->nshared_boundaries(my_rank, jproc);
18638  for (unsigned bb = 0; bb < n_jshd_bnd; bb++)
18639  {
18640  // Get the boundary id
18641  const unsigned j_shd_bnd =
18642  this->shared_boundaries_ids(my_rank, jproc, bb);
18643  // Is the node part of this boundary?
18644  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
18645  {
18646  // Include the first processor
18647  other_processor_1.push_back(my_rank);
18648  // Include the second processor
18649  other_processor_2.push_back(jproc);
18650  // Include the shared boundary id
18651  shd_bnd_ids.push_back(j_shd_bnd);
18652  // Increase the counter for found shared boundaries with
18653  // other processors
18654  counter_shd_bnd_with_other_procs_have_node++;
18655  }
18656 
18657  } // for (bb < nshared_bnd)
18658 
18659  } // if (jproc != iproc)
18660 
18661  } // for (jproc < nproc)
18662 
18663  // Get the indexes of the node on all the shared boundaries where
18664  // it was found
18665  const unsigned n_other_processors = other_processor_1.size();
18666  // Loop over the processors where the node was found
18667  for (unsigned i = 0; i < n_other_processors; i++)
18668  {
18669  // Get the shared boundary id
18670  unsigned shd_bnd_id = shd_bnd_ids[i];
18671  // Get the number of nodes on that shared boundary
18672  const unsigned n_nodes_on_shd_bnd =
18673  nsorted_shared_boundary_node(shd_bnd_id);
18674 
18675 #ifdef PARANOID
18676  bool found_index_node_on_shared_boundary = false;
18677 #endif
18678  for (unsigned i = 0; i < n_nodes_on_shd_bnd; i++)
18679  {
18680  // Get the i-th shared boundary node
18681  Node* shared_node_pt = sorted_shared_boundary_node_pt(shd_bnd_id, i);
18682  // Is the same node?
18683  if (shared_node_pt == nod_pt)
18684  {
18685  // DEBP(i_node);
18686  // DEBP(nod_pt->x(0));
18687  // DEBP(nod_pt->x(1));
18688  // Include the index of the node
18689  indexes.push_back(i);
18690 #ifdef PARANOID
18691  // Mark as found the node
18692  found_index_node_on_shared_boundary = true;
18693 #endif
18694  break;
18695  } // if (shared_node_pt == nod_pt)
18696 
18697  } // for (i < n_nodes_on_shd_bnd)
18698 
18699 #ifdef PARANOID
18700  if (!found_index_node_on_shared_boundary)
18701  {
18702  std::ostringstream error_message;
18703  error_message << "The index of the node on boundary (" << shd_bnd_id
18704  << "), shared by other processors\nwas not found.\n"
18705  << "The node coordinates are (" << nod_pt->x(0) << ","
18706  << nod_pt->x(1) << ").\n";
18707  throw OomphLibError(
18708  error_message.str(),
18709  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18710  OOMPH_EXCEPTION_LOCATION);
18711  }
18712 #endif
18713  } // for (i < n_other_processors)
18714 
18715  // Now send the info. but first check that the number of found
18716  // nodes be the same that the previously found shared boundaries
18717  // with the node
18718 #ifdef PARANOID
18719  if (counter_shd_bnd_with_other_procs_have_node !=
18720  nshared_boundaries_with_other_processors_have_node)
18721  {
18722  std::ostringstream error_message;
18723  error_message << "The number of shared boundaries where the node is on "
18724  << "is different:\n"
18725  << "nshared_boundaries_with_other_processors_have_node: ("
18726  << nshared_boundaries_with_other_processors_have_node
18727  << ")\n"
18728  << "counter_shd_bnd_with_other_procs_have_node: ("
18729  << counter_shd_bnd_with_other_procs_have_node << ")\n";
18730  throw OomphLibError(
18731  error_message.str(),
18732  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18733  OOMPH_EXCEPTION_LOCATION);
18734  } // if (counter_shd_bnd_with_other_procs_have_node !=
18735  // nshared_boundaries_with_other_processors_have_node)
18736 #endif
18737 
18738  // Loop over the info. to send it
18739  for (unsigned i = 0; i < n_other_processors; i++)
18740  {
18741  Flat_packed_unsigneds.push_back(other_processor_1[i]);
18742 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18743  std::stringstream junk1;
18744  junk1 << "Processor where the other shared boundary "
18745  << "has the node: " << other_processor_1[i];
18746  Flat_packed_unsigneds_string.push_back(junk1.str());
18747 #endif
18748 
18749  Flat_packed_unsigneds.push_back(other_processor_2[i]);
18750 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18751  std::stringstream junk2;
18752  junk2 << "Processor where the other shared boundary "
18753  << "has the node: " << other_processor_2[i];
18754  Flat_packed_unsigneds_string.push_back(junk2.str());
18755 #endif
18756 
18757  Flat_packed_unsigneds.push_back(shd_bnd_ids[i]);
18758 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18759  std::stringstream junk3;
18760  junk3 << "Other shared boundary id where the node is on"
18761  << boundaries[i];
18762  Flat_packed_unsigneds_string.push_back(junk3.str());
18763 #endif
18764 
18765  Flat_packed_unsigneds.push_back(indexes[i]);
18766 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18767  std::stringstream junk4;
18768  junk4 << "Node index on other shared boundary " << boundaries[i]
18769  << " is " << indexes[i];
18770  Flat_packed_unsigneds_string.push_back(junk4.str());
18771 #endif
18772 
18773  } // for (i < n_other_processors)
18774 
18775  } // if (node_on_shared_boundary_with_other_processors)
18776  else
18777  {
18778  Flat_packed_unsigneds.push_back(0);
18779 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18780  Flat_packed_unsigneds_string.push_back(
18781  "Node is on any shared boundary with other processors");
18782 #endif
18783  } // else if (node_on_shared_boundary_with_other_processors)
18784 
18785  // Now check if it is required to send the info. of the node. If the
18786  // node is not on a shared boundary with the iproc processor then we
18787  // need to send the info.
18788 
18789  if (!node_on_shared_boundary)
18790  {
18791  // Send all the info. to create it
18792 
18793  // Is the Node algebraic? If so, send its ref values and
18794  // an indication of its geometric objects if they are stored
18795  // in the algebraic mesh
18796  AlgebraicNode* alg_nod_pt = dynamic_cast<AlgebraicNode*>(nod_pt);
18797  if (alg_nod_pt != 0)
18798  {
18799  // The external mesh should be algebraic
18800  AlgebraicMesh* alg_mesh_pt = dynamic_cast<AlgebraicMesh*>(this);
18801 
18802  // Get default node update function ID
18803  unsigned update_id = alg_nod_pt->node_update_fct_id();
18804  Flat_packed_unsigneds.push_back(update_id);
18805 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18806  Flat_packed_unsigneds_string.push_back("Alg Node update id");
18807 #endif
18808 
18809  // Get reference values at default...
18810  unsigned n_ref_val = alg_nod_pt->nref_value();
18811  Flat_packed_unsigneds.push_back(n_ref_val);
18812 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18813  Flat_packed_unsigneds_string.push_back("Alg Node n ref values");
18814 #endif
18815  for (unsigned i_ref_val = 0; i_ref_val < n_ref_val; i_ref_val++)
18816  {
18817  Flat_packed_doubles.push_back(alg_nod_pt->ref_value(i_ref_val));
18818  }
18819 
18820  // Access geometric objects at default...
18821  unsigned n_geom_obj = alg_nod_pt->ngeom_object();
18822  Flat_packed_unsigneds.push_back(n_geom_obj);
18823 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18824  Flat_packed_unsigneds_string.push_back("Alg Node n geom objects");
18825 #endif
18826  for (unsigned i_geom = 0; i_geom < n_geom_obj; i_geom++)
18827  {
18828  GeomObject* geom_obj_pt = alg_nod_pt->geom_object_pt(i_geom);
18829 
18830  // Check this against the stored geometric objects in mesh
18831  unsigned n_geom_list = alg_mesh_pt->ngeom_object_list_pt();
18832 
18833  // Default found index to zero
18834  unsigned found_geom_object = 0;
18835  for (unsigned i_list = 0; i_list < n_geom_list; i_list++)
18836  {
18837  if (geom_obj_pt == alg_mesh_pt->geom_object_list_pt(i_list))
18838  {
18839  found_geom_object = i_list;
18840  }
18841  }
18842  Flat_packed_unsigneds.push_back(found_geom_object);
18843 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18844  Flat_packed_unsigneds_string.push_back("Found geom object");
18845 #endif
18846  }
18847  } // (if alg_nod_pt!=0)
18848 
18849  // Is it a SolidNode?
18850  SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(nod_pt);
18851  if (solid_nod_pt != 0)
18852  {
18853  unsigned n_solid_val = solid_nod_pt->variable_position_pt()->nvalue();
18854  for (unsigned i_val = 0; i_val < n_solid_val; i_val++)
18855  {
18856  for (unsigned t = 0; t < n_prev; t++)
18857  {
18858  Flat_packed_doubles.push_back(
18859  solid_nod_pt->variable_position_pt()->value(t, i_val));
18860  }
18861  }
18862 
18863  Vector<double> values_solid_node;
18864  solid_nod_pt->add_values_to_vector(values_solid_node);
18865  const unsigned nvalues_solid_node = values_solid_node.size();
18866  Flat_packed_unsigneds.push_back(nvalues_solid_node);
18867 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18868  std::stringstream junk;
18869  junk << "Number of values solid node: " << nvalues_solid_node;
18870  Flat_packed_unsigneds_string.push_back(junk.str());
18871 #endif
18872  for (unsigned i = 0; i < nvalues_solid_node; i++)
18873  {
18874  Flat_packed_doubles.push_back(values_solid_node[i]);
18875  }
18876  }
18877 
18878  // Finally copy info required for all node types
18879  for (unsigned i_val = 0; i_val < n_val; i_val++)
18880  {
18881  for (unsigned t = 0; t < n_prev; t++)
18882  {
18883  Flat_packed_doubles.push_back(nod_pt->value(t, i_val));
18884  }
18885  }
18886 
18887  // Now do positions
18888  for (unsigned idim = 0; idim < n_dim; idim++)
18889  {
18890  for (unsigned t = 0; t < n_prev; t++)
18891  {
18892  Flat_packed_doubles.push_back(nod_pt->x(t, idim));
18893  }
18894  }
18895 
18896  } // if (!node_on_shared_boundary)
18897  }
18898 
18899  //==========start of add_haloed_node_helper===============================
18900  /// Helper to add external haloed node that is not a master
18901  //========================================================================
18902  template<class ELEMENT>
18904  Node* nod_pt)
18905  {
18906  // Attempt to add this node as a haloed node
18907  const unsigned n_haloed_nod = this->nhaloed_node(iproc);
18908  const unsigned haloed_node_index =
18909  this->try_to_add_haloed_node_pt(iproc, nod_pt);
18910 
18911  // If it was added then the new index should match the size of the storage
18912  if (haloed_node_index == n_haloed_nod)
18913  {
18914  Flat_packed_unsigneds.push_back(1);
18915 
18916 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18917  std::stringstream junk;
18918  junk << "Node needs to be constructed [size="
18919  << Flat_packed_unsigneds.size() << "]; last entry: "
18920  << Flat_packed_unsigneds[Flat_packed_unsigneds.size() - 1];
18921  Flat_packed_unsigneds_string.push_back(junk.str());
18922 #endif
18923 
18924  // This helper function gets all the required information for the
18925  // specified node and stores it into MPI-sendable information
18926  // so that a halo copy can be made on the receiving process
18927  get_required_nodal_information_helper(iproc, nod_pt);
18928  }
18929  else // It was already added
18930  {
18931  Flat_packed_unsigneds.push_back(0);
18932 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18933  std::stringstream junk;
18934  junk << "Node was already added [size=" << Flat_packed_unsigneds.size()
18935  << "]; last entry: "
18936  << Flat_packed_unsigneds[Flat_packed_unsigneds.size() - 1];
18937 
18938  Flat_packed_unsigneds_string.push_back(junk.str());
18939 #endif
18940 
18941  // This node is already a haloed node, so tell
18942  // the other process its index in the equivalent halo storage
18943  Flat_packed_unsigneds.push_back(haloed_node_index);
18944 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18945  Flat_packed_unsigneds_string.push_back("haloed node index");
18946 #endif
18947  }
18948  }
18949 
18950  //================= send_and_receive_haloed_info =======================
18951  /// Send the information of the elements that will be created on the other
18952  /// processor
18953  //======================================================================
18954  template<class ELEMENT>
18956  int& send_proc, int& recv_proc)
18957  {
18958  // Get the communicator of the mesh
18959  OomphCommunicator* comm_pt = this->communicator_pt();
18960 
18961  // Set MPI info
18962  MPI_Status status;
18963  MPI_Request request;
18964 
18965  // Prepare vectors to receive information
18966  Vector<double> received_double_values;
18967  Vector<unsigned> received_unsigned_values;
18968 
18969  // Send the double values associated with halo(ed) elements and nodes
18970  //-------------------------------------------------------------------
18971  unsigned send_count_double_values = Flat_packed_doubles.size();
18972  MPI_Isend(&send_count_double_values,
18973  1,
18974  MPI_UNSIGNED,
18975  send_proc,
18976  1,
18977  comm_pt->mpi_comm(),
18978  &request);
18979 
18980  int receive_count_double_values = 0;
18981  MPI_Recv(&receive_count_double_values,
18982  1,
18983  MPI_INT,
18984  recv_proc,
18985  1,
18986  comm_pt->mpi_comm(),
18987  &status);
18988  MPI_Wait(&request, MPI_STATUS_IGNORE);
18989 
18990  if (send_count_double_values != 0)
18991  {
18992  MPI_Isend(&Flat_packed_doubles[0],
18993  send_count_double_values,
18994  MPI_DOUBLE,
18995  send_proc,
18996  2,
18997  comm_pt->mpi_comm(),
18998  &request);
18999  }
19000  if (receive_count_double_values != 0)
19001  {
19002  received_double_values.resize(receive_count_double_values);
19003  MPI_Recv(&received_double_values[0],
19004  receive_count_double_values,
19005  MPI_DOUBLE,
19006  recv_proc,
19007  2,
19008  comm_pt->mpi_comm(),
19009  &status);
19010  }
19011  if (send_count_double_values != 0)
19012  {
19013  MPI_Wait(&request, MPI_STATUS_IGNORE);
19014  }
19015 
19016  // Now send unsigned values associated with halo(ed) elements and nodes
19017  //---------------------------------------------------------------------
19018  unsigned send_count_unsigned_values = Flat_packed_unsigneds.size();
19019 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19020  unsigned send_count_unsigned_string = Flat_packed_unsigneds_string.size();
19021 #ifdef PARANOID
19022  if (send_count_unsigned_string != send_count_unsigned_values)
19023  {
19024  std::ostringstream error_message;
19025  error_message << "The number of unsigned values to send to processor ("
19026  << send_proc
19027  << ") is different from the\nnumber of annotated strings "
19028  << "for the communication\n\n";
19029  throw OomphLibError(
19030  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
19031  }
19032 #endif // #ifdef PARANOID
19033 #endif
19034  MPI_Isend(&send_count_unsigned_values,
19035  1,
19036  MPI_UNSIGNED,
19037  send_proc,
19038  14,
19039  comm_pt->mpi_comm(),
19040  &request);
19041 
19042  int receive_count_unsigned_values = 0;
19043  MPI_Recv(&receive_count_unsigned_values,
19044  1,
19045  MPI_INT,
19046  recv_proc,
19047  14,
19048  comm_pt->mpi_comm(),
19049  &status);
19050 
19051  MPI_Wait(&request, MPI_STATUS_IGNORE);
19052 
19053  if (send_count_unsigned_values != 0)
19054  {
19055  MPI_Isend(&Flat_packed_unsigneds[0],
19056  send_count_unsigned_values,
19057  MPI_UNSIGNED,
19058  send_proc,
19059  15,
19060  comm_pt->mpi_comm(),
19061  &request);
19062 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19063  for (unsigned i = 0; i < send_count_unsigned_values; i++)
19064  {
19065  oomph_info << "Sent:" << i << " to orig_proc:" << send_proc << " "
19066  << Flat_packed_unsigneds_string[i] << ": "
19067  << Flat_packed_unsigneds[i] << std::endl;
19068  }
19069 #endif
19070  }
19071  if (receive_count_unsigned_values != 0)
19072  {
19073  received_unsigned_values.resize(receive_count_unsigned_values);
19074  MPI_Recv(&received_unsigned_values[0],
19075  receive_count_unsigned_values,
19076  MPI_UNSIGNED,
19077  recv_proc,
19078  15,
19079  comm_pt->mpi_comm(),
19080  &status);
19081  }
19082 
19083  if (send_count_unsigned_values != 0)
19084  {
19085  MPI_Wait(&request, MPI_STATUS_IGNORE);
19086  }
19087 
19088  // Copy across into original containers -- these can now
19089  //------------------------------------------------------
19090  // be processed by create_external_halo_elements() to generate
19091  //------------------------------------------------------------
19092  // external halo elements
19093  //------------------------
19094  Flat_packed_doubles.resize(receive_count_double_values);
19095  for (int ii = 0; ii < receive_count_double_values; ii++)
19096  {
19097  Flat_packed_doubles[ii] = received_double_values[ii];
19098  }
19099  Flat_packed_unsigneds.resize(receive_count_unsigned_values);
19100  for (int ii = 0; ii < receive_count_unsigned_values; ii++)
19101  {
19102  Flat_packed_unsigneds[ii] = received_unsigned_values[ii];
19103  }
19104  }
19105 
19106  //=====================================================================
19107  /// Creates (halo) element on the loop process based on the
19108  /// information received from each processor
19109  //=====================================================================
19110  template<class ELEMENT>
19112  unsigned& iproc,
19113  Vector<Node*>& new_nodes_on_domain,
19114  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
19115  other_proc_shd_bnd_node_pt,
19116  Vector<Vector<Vector<unsigned>>>& global_node_names,
19117  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
19118  Vector<Node*>& global_shared_node_pt)
19119  {
19120 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19121  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19122  << " Bool: New element needs to be constructed "
19123  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19124  << std::endl;
19125 #endif
19126 
19127  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
19128  {
19129  // Create a new element from the communicated values
19130  // and coords from the process that located zeta
19131  GeneralisedElement* new_el_pt = new ELEMENT;
19132 
19133  // Add the element, it is a new element in the mesh
19134  this->add_element_pt(new_el_pt);
19135 
19136  // Add halo element to this mesh
19137  this->add_root_halo_element_pt(iproc, new_el_pt);
19138 
19139  // Cast to the FE pointer
19140  FiniteElement* f_el_pt = dynamic_cast<FiniteElement*>(new_el_pt);
19141 
19142  // Check if new element is associated to any boundary
19143  this->add_halo_element_helper(iproc, f_el_pt);
19144 
19145  // Now we add nodes to the new element
19146  unsigned n_node = f_el_pt->nnode();
19147 
19148  for (unsigned j = 0; j < n_node; j++)
19149  {
19150  Node* new_nod_pt = 0;
19151 
19152  // Call the add halo node helper function
19153  add_halo_node_helper(new_nod_pt,
19154  new_nodes_on_domain,
19155  other_proc_shd_bnd_node_pt,
19156  iproc,
19157  j,
19158  f_el_pt,
19159  global_node_names,
19160  node_name_to_global_index,
19161  global_shared_node_pt);
19162 
19163  } // for (j<n_nod)
19164  }
19165  else // the element already exists as halo
19166  {
19167 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19168  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19169  << " Index of existing halo element "
19170  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19171  << std::endl;
19172 #endif
19173  // The index itself is in Flat_packed_unsigneds[...]
19174  unsigned halo_ele_index =
19175  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19176 
19177  // Use this index to get the element
19178  FiniteElement* f_el_pt = dynamic_cast<FiniteElement*>(
19179  this->root_halo_element_pt(iproc, halo_ele_index));
19180 
19181  // If it's not a finite element die
19182  if (f_el_pt == 0)
19183  {
19184  throw OomphLibError("Halo element is not a FiniteElement\n",
19185  OOMPH_CURRENT_FUNCTION,
19186  OOMPH_EXCEPTION_LOCATION);
19187  }
19188 
19189  } // else the element already exists as halo
19190  }
19191 
19192  //========start of add_halo_element_helper==============================
19193  /// Helper function to create (halo) elements on the loop
19194  /// process based on the info received in send_and_received_located_info
19195  /// This function is in charge of verify if the element is associated to
19196  /// a boundary
19197  //======================================================================
19198  template<class ELEMENT>
19200  unsigned& iproc, FiniteElement* ele_pt)
19201  {
19202 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19203  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19204  << " Bool: Element is associated to an original boundary "
19205  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19206  << std::endl;
19207 #endif
19208 
19209  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
19210  {
19211 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19212  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19213  << " How many boundaries are associated with the element "
19214  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19215  << std::endl;
19216 #endif
19217  const unsigned nassociated_boundaries =
19218  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19219 
19220  for (unsigned b = 0; b < nassociated_boundaries; b++)
19221  {
19222 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19223  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19224  << " Boundary associated to the element "
19225  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19226  << std::endl;
19227 #endif
19228  const unsigned bnd =
19229  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19230 
19231 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19232  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19233  << " Face index of the element "
19234  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19235  << std::endl;
19236 #endif
19237  const unsigned face_index =
19238  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19239 
19240  // Associate the element with the boundary and establish as many
19241  // face indexes it has
19242  this->Boundary_element_pt[bnd].push_back(ele_pt);
19243  this->Face_index_at_boundary[bnd].push_back(face_index);
19244 
19245  } // (b < nassociated_boundaries)
19246 
19247  // Here read the info. regarding the boundary-region of the element
19248 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19249  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19250  << " Bool: Element is associated to a boundary-region "
19251  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19252  << std::endl;
19253 #endif
19254 
19255  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
19256  {
19257 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19258  oomph_info
19259  << "Rec:" << Counter_for_flat_packed_unsigneds
19260  << " How many boundaries-regions are associated with the element "
19261  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19262  << std::endl;
19263 #endif
19264  const unsigned nassociated_boundaries_and_regions =
19265  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19266 
19267  for (unsigned br = 0; br < nassociated_boundaries_and_regions; br++)
19268  {
19269 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19270  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19271  << " Boundary associated to the element "
19272  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19273  << std::endl;
19274 #endif
19275  const unsigned bnd =
19276  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19277 
19278 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19279  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19280  << " Region associated to the element "
19281  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19282  << std::endl;
19283 #endif
19284  const unsigned region =
19285  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19286 
19287 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19288  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19289  << " Face index of the element in boundary-region "
19290  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19291  << std::endl;
19292 #endif
19293  const unsigned face_index =
19294  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19295 
19296  // Associate the element with the boundary-regions and establish
19297  // as many face indexes it has
19298  this->Boundary_region_element_pt[bnd][region].push_back(ele_pt);
19299  this->Face_index_region_at_boundary[bnd][region].push_back(
19300  face_index);
19301 
19302  } // for (br < nassociated_boundaries_and_regions)
19303 
19304  } // Is the element associated with a boundary-region?
19305  }
19306 
19307  // Now check if the element is associated to a shared boundary
19308 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19309  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19310  << " Bool: Element is associated to a shared boundary "
19311  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19312  << std::endl;
19313 #endif
19314  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 3)
19315  {
19316 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19317  oomph_info
19318  << "Rec:" << Counter_for_flat_packed_unsigneds
19319  << " How many shared boundaries are associated with the element "
19320  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19321  << std::endl;
19322 #endif
19323  const unsigned nassociated_shared_boundaries =
19324  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19325 
19326  for (unsigned b = 0; b < nassociated_shared_boundaries; b++)
19327  {
19328 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19329  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19330  << " Shared boundary associated to the element "
19331  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19332  << std::endl;
19333 #endif
19334  const unsigned bnd =
19335  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19336 
19337 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19338  oomph_info
19339  << "Rec:" << Counter_for_flat_packed_unsigneds
19340  << " Face index of the element associated to the shared boundary "
19341  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19342  << std::endl;
19343 #endif
19344 
19345  const unsigned face_index =
19346  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19347 
19348  this->add_shared_boundary_element(bnd, ele_pt);
19349  this->add_face_index_at_shared_boundary(bnd, face_index);
19350 
19351  } // (b < nassociated_shared_boundaries)
19352 
19353  } // The element is associted with a shared boundary
19354  }
19355 
19356  //========start of add_halo_node_helper==========================
19357  /// Helper function to add halo node
19358  //===============================================================
19359  template<class ELEMENT>
19361  Node*& new_nod_pt,
19362  Vector<Node*>& new_nodes_on_domain,
19363  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
19364  other_proc_shd_bnd_node_pt,
19365  unsigned& iproc,
19366  unsigned& node_index,
19367  FiniteElement* const& new_el_pt,
19368  Vector<Vector<Vector<unsigned>>>& global_node_names,
19369  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
19370  Vector<Node*>& global_shared_node_pt)
19371  {
19372  // Given the node, received information about them from process
19373  // iproc, construct them on the current process
19374 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19375  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19376  << " Bool: New node needs to be constructed "
19377  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19378  << std::endl;
19379 #endif
19380  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
19381  {
19382  // Construct a new node based upon sent information, or copy a node
19383  // from one of the shared boundaries
19384  construct_new_halo_node_helper(new_nod_pt,
19385  new_nodes_on_domain,
19386  other_proc_shd_bnd_node_pt,
19387  iproc,
19388  node_index,
19389  new_el_pt,
19390  global_node_names,
19391  node_name_to_global_index,
19392  global_shared_node_pt);
19393  }
19394  else
19395  {
19396 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19397  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19398  << " Index of existing halo node "
19399  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19400  << std::endl;
19401 #endif
19402 
19403  // Copy node from received location
19404  new_nod_pt = new_nodes_on_domain
19405  [Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]];
19406 
19407  new_el_pt->node_pt(node_index) = new_nod_pt;
19408  }
19409  }
19410 
19411  //========start of construct_new_halo_node_helper=================
19412  // Helper function which constructs a new external halo node (on new element)
19413  // with the required information sent from the haloed process
19414  //========================================================================
19415  template<class ELEMENT>
19417  Node*& new_nod_pt,
19418  Vector<Node*>& new_nodes_on_domain,
19419  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
19420  other_proc_shd_bnd_node_pt,
19421  unsigned& iproc,
19422  unsigned& node_index,
19423  FiniteElement* const& new_el_pt,
19424  Vector<Vector<Vector<unsigned>>>& global_node_names,
19425  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
19426  Vector<Node*>& global_shared_node_pt)
19427  {
19428  // The first entry indicates the number of values at this new Node
19429  //(which may be different across the same element e.g. Lagrange multipliers)
19430 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19431  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19432  << " Number of values of external halo node "
19433  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19434  << std::endl;
19435 #endif
19436  unsigned n_val = Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19437 
19438  // Null TimeStepper for now
19439  TimeStepper* time_stepper_pt = this->Time_stepper_pt;
19440  // Default number of previous values to 1
19441  unsigned n_prev = time_stepper_pt->ntstorage();
19442 
19443  // ------------------------------------------------------
19444  // Check if the node is on an original boundary
19445 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19446  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19447  << " Is the node on an original boundary "
19448  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19449  << std::endl;
19450 #endif
19451 
19452  // Flag to indicate if the node is on original boundaries
19453  const unsigned node_on_original_boundaries =
19454  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19455 
19456  // Store the original boundaries where the node is on
19457  Vector<unsigned> original_boundaries_node_is_on;
19458  // Store the zeta coordinates of the node on the original boundaries
19459  Vector<double> zeta_coordinates;
19460  // Store the number of original boundaries the node is on
19461  unsigned n_original_boundaries_node_is_on = 0;
19462 
19463  if (node_on_original_boundaries == 2)
19464  {
19465  // How many original boundaries does the node live on?
19466 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19467  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19468  << " Number of boundaries the node is on: "
19469  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19470  << std::endl;
19471 #endif
19472  n_original_boundaries_node_is_on =
19473  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19474 
19475  // Resize the containers
19476  original_boundaries_node_is_on.resize(n_original_boundaries_node_is_on);
19477  zeta_coordinates.resize(n_original_boundaries_node_is_on);
19478 
19479  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
19480  {
19481  // Boundary number
19482 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19483  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19484  << " Node is on boundary "
19485  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19486  << std::endl;
19487 #endif
19488  original_boundaries_node_is_on[i] =
19489  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19490  zeta_coordinates[i] =
19491  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
19492  }
19493 
19494  } // if (node_on_original_boundaries==2)
19495 #ifdef PARANOID
19496  else
19497  {
19498  if (node_on_original_boundaries != 0)
19499  {
19500  std::ostringstream error_message;
19501  error_message
19502  << "The current node is not on an original boundary, this should\n"
19503  << "be indicated by a zero flag. However, the read value for\n"
19504  << "that flag is (" << node_on_original_boundaries << ").\n\n";
19505  throw OomphLibError(
19506  error_message.str(),
19507  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19508  OOMPH_EXCEPTION_LOCATION);
19509  } // if (node_on_original_boundaries != 0)
19510  }
19511 #endif
19512 
19513  // --------------------------------------------------------------
19514  // Check if the node was on a shared boundary with the iproc
19515  // processor
19516 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19517  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19518  << " Is node on shared boundary? "
19519  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19520  << std::endl;
19521 #endif
19522  const unsigned is_node_on_shared_boundary =
19523  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19524  if (is_node_on_shared_boundary == 1)
19525  {
19526  // How many shared boundaries does the node live on?
19527 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19528  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19529  << " Number of boundaries the node is on: "
19530  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19531  << std::endl;
19532 #endif
19533  const unsigned n_shd_bnd_node_is_on =
19534  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19535  Vector<unsigned> shd_bnds_node_is_on(n_shd_bnd_node_is_on);
19536  for (unsigned i = 0; i < n_shd_bnd_node_is_on; i++)
19537  {
19538  // Shared boundary number
19539 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19540  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19541  << " Node is on boundary "
19542  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19543  << std::endl;
19544 #endif
19545  shd_bnds_node_is_on[i] =
19546  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19547  }
19548 
19549  // Get the index of the node on the shared boundary
19550 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19551  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19552  << " Index of node on boundary "
19553  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19554  << std::endl;
19555 #endif
19556  // Get the node index of the node on the shared boundary
19557  unsigned node_index_on_shared_boundary =
19558  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19559 
19560  // Get the pointer to the node with the received info.
19561  new_nod_pt = this->sorted_shared_boundary_node_pt(
19562  shd_bnds_node_is_on[0], node_index_on_shared_boundary);
19563 
19564  } // if (is_node_on_shared_boundary == 1)
19565 #ifdef PARANOID
19566  else
19567  {
19568  if (is_node_on_shared_boundary != 0)
19569  {
19570  std::ostringstream error_message;
19571  error_message
19572  << "The current node is not on a shared boundary, this should\n"
19573  << "be indicated by a zero flag. However, the read value for\n"
19574  << "that flag is (" << is_node_on_shared_boundary << ").\n\n";
19575  throw OomphLibError(
19576  error_message.str(),
19577  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19578  OOMPH_EXCEPTION_LOCATION);
19579  } // if (node_on_shared_boundary != 0)
19580  }
19581 #endif
19582 
19583  // ------------------------------------------------------------
19584  // Is the node on a shared boundary with other processor?
19585 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19586  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19587  << " Is the node on shared boundaries with other processors "
19588  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19589  << std::endl;
19590 #endif
19591 
19592  // Is the node in shared boundaries no associated with the
19593  // receiver processor
19594  const unsigned is_the_node_in_shared_boundaries_with_other_processors =
19595  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19596 
19597  // The containers where to store the info.
19598  Vector<unsigned> other_processor_1;
19599  Vector<unsigned> other_processor_2;
19600  Vector<unsigned> other_shared_boundaries;
19601  Vector<unsigned> other_indexes;
19602 
19603  // How many shared bounaries with other processors the node lives on
19604  unsigned n_shd_bnd_with_other_procs_have_node = 0;
19605 
19606  // Is the node on shared boundaries with other processors
19607  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19608  {
19609 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19610  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19611  << " In how many shared boundaries with other "
19612  << "processors is the node "
19613  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19614  << std::endl;
19615 #endif
19616 
19617  // How many nodes on other shared boundaries were found
19618  n_shd_bnd_with_other_procs_have_node =
19619  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19620 
19621  // Resize the containers
19622  other_processor_1.resize(n_shd_bnd_with_other_procs_have_node);
19623  other_processor_2.resize(n_shd_bnd_with_other_procs_have_node);
19624  other_shared_boundaries.resize(n_shd_bnd_with_other_procs_have_node);
19625  other_indexes.resize(n_shd_bnd_with_other_procs_have_node);
19626 
19627  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
19628  {
19629 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19630  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19631  << " Processor where the other shared boundary"
19632  << "has the node"
19633  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19634  << std::endl;
19635 #endif
19636  // Read the other processor 1
19637  other_processor_1[i] =
19638  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19639 
19640 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19641  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19642  << " Processor where the other shared boundary"
19643  << "has the node"
19644  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19645  << std::endl;
19646 #endif
19647  // Read the other processor 2
19648  other_processor_2[i] =
19649  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19650 
19651 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19652  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19653  << " Other shared boundary id where the node is on: "
19654  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19655  << std::endl;
19656 #endif
19657 
19658  // Read the other shared boundary id
19659  other_shared_boundaries[i] =
19660  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19661 
19662 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19663  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19664  << " Node index on the other shared boundary "
19665  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19666  << std::endl;
19667 #endif
19668 
19669  // Read the node index on the other shared boundary
19670  other_indexes[i] =
19671  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19672 
19673  } // for (i < n_shd_bnd_with_other_procs_have_node)
19674 
19675  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19676 #ifdef PARANOID
19677  else
19678  {
19679  if (is_the_node_in_shared_boundaries_with_other_processors != 0)
19680  {
19681  std::ostringstream error_message;
19682  error_message
19683  << "The current node is not on a shared boundary with\n"
19684  << "other processors, this should be indicated by a zero flag.\n"
19685  << "However, the read value for that flag is ("
19686  << is_the_node_in_shared_boundaries_with_other_processors << ").\n\n";
19687  throw OomphLibError(
19688  error_message.str(),
19689  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19690  OOMPH_EXCEPTION_LOCATION);
19691  }
19692  }
19693 #endif
19694 
19695  // Now we have all the info. to decide whether the node should be
19696  // created or not
19697 
19698  // First check if the node is a shared boundary node
19699  if (is_node_on_shared_boundary == 1)
19700  {
19701  // We already have the node, we do not need to create it
19702 
19703  // Only check if we need to add boundary info. to the node
19704  if (node_on_original_boundaries == 2)
19705  {
19706  // The node is a boundary node, add the boundary info. before
19707  // adding it to the domain
19708 
19709  // Associate the node to the given boundaries
19710  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
19711  {
19712  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
19713  // Establish the boundary coordinates for the node
19714  Vector<double> zeta(1);
19715  zeta[0] = zeta_coordinates[i];
19716  new_nod_pt->set_coordinates_on_boundary(
19717  original_boundaries_node_is_on[i], zeta);
19718  }
19719 
19720  } // if (node_on_original_boundaries==2)
19721 
19722  // Add the node to the domain
19723  new_nodes_on_domain.push_back(new_nod_pt);
19724 
19725  // Add the node to the element
19726  new_el_pt->node_pt(node_index) = new_nod_pt;
19727 
19728  } // if (is_node_on_shared_boundary == 1)
19729 
19730  // Now check if the node is on a shared boundary with another
19731  // processor, if that is the case try to find the node that may have
19732  // been already sent by the other processors
19733 
19734  // This flags indicates if the node was found, and then decide if it
19735  // is required to create the node
19736  bool found_node_in_other_shared_boundaries = false;
19737  // Flag to indicate whether the node should be created as a boundary
19738  // node or not. If the node lies on a shared boundary with other
19739  // processor the we create it as a boundary node. The processor from
19740  // which we are receiving info. (iproc) may not know that the node
19741  // lies on an original boundary. If the node lies on an original
19742  // boundary then its info. will be sent by another processor, then
19743  // we can set its boundary info. since the node was constructed as a
19744  // boundary node
19745  bool build_node_as_boundary_node = false;
19746 
19747  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19748  {
19749  // Build the node as a boundary node
19750  build_node_as_boundary_node = true;
19751 
19752  // Try to get the node pointer in case that the node has been
19753  // already sent by the other processors
19754 
19755  // Get the number of initial shared boundaries to correct the
19756  // index of the shared boundary
19757  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
19758 
19759  // Add the found nodes in the container
19760  Vector<Node*> found_node_pt;
19761 
19762  // Now try to find the node in any of the other shared boundaries
19763  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
19764  {
19765  // We always check with the lower processor number. The
19766  // info. is only stored in one direction. More importantly,
19767  // this is done with the hope that the info. has been already
19768  // received from the other processor given that its info. was
19769  // processed before the current processor (iproc). NOTE that
19770  // it is not always the case that this info. has been received
19771  // from the other processors since it may have not require to
19772  // send the elements (and nodes) on the shared boundary with
19773  // the current processor (iproc).
19774  unsigned oproc1 = other_processor_1[i];
19775  unsigned oproc2 = other_processor_2[i];
19776  if (other_processor_1[i] > other_processor_2[i])
19777  {
19778  oproc1 = other_processor_2[i];
19779  oproc2 = other_processor_1[i];
19780  } // if (other_processor_1[i] > other_processor_2[i])
19781 
19782  // Re-compute the shared boundary id between the other
19783  // processors
19784  const unsigned shd_bnd_id =
19785  other_shared_boundaries[i] - initial_shd_bnd_id;
19786 
19787  // Read the index
19788  const unsigned index = other_indexes[i];
19789 
19790  // Check if there are nodes received from the other processor
19791  // and with the given shared boundary
19792  const unsigned n_nodes_on_other_processor =
19793  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].size();
19794 
19795  if (n_nodes_on_other_processor > 0)
19796  {
19797  // Check if we can find the index of the node in that
19798  // other processor and shared boundary id
19799  std::map<unsigned, Node*>::iterator it =
19800  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].find(index);
19801 
19802  // If the index exist then get the node pointer
19803  if (it !=
19804  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
19805  {
19806  // Mark the node as found
19807  found_node_in_other_shared_boundaries = true;
19808  // Get the node pointer
19809  Node* tmp_node_pt = (*it).second;
19810 
19811  // Push back the node pointer
19812  found_node_pt.push_back(tmp_node_pt);
19813 
19814  } // if (it!=
19815  // other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
19816 
19817  } // if (n_nodes_on_other_processor > 0)
19818 
19819  } // for (i < n_shd_bnd_with_other_procs_have_node)
19820 
19821  // If the node was found, then all their instances should be the
19822  // same but better check
19823  if (found_node_in_other_shared_boundaries)
19824  {
19825 #ifdef PARANOID
19826  const unsigned n_times_node_found = found_node_pt.size();
19827  for (unsigned j = 1; j < n_times_node_found; j++)
19828  {
19829  if (found_node_pt[j - 1] != found_node_pt[j])
19830  {
19831  std::ostringstream error_message;
19832  error_message
19833  << "The instances of the node that was found on\n"
19834  << "shared boundaries with other processors (but not\n"
19835  << "on shared boundaries with this processor) are not\n"
19836  << "the same.\n"
19837  << "These are the coordinates of the instances of the\n"
19838  << "nodes:\n"
19839  << "(" << found_node_pt[j - 1]->x(0) << ", "
19840  << found_node_pt[j - 1]->x(1) << ")\n"
19841  << "(" << found_node_pt[j]->x(0) << ", " << found_node_pt[j]->x(1)
19842  << ")\n"
19843  << "Dont be surprised if they are the same since the "
19844  << "node is\nrepeated.\n";
19845  throw OomphLibError(error_message.str(),
19846  OOMPH_CURRENT_FUNCTION,
19847  OOMPH_EXCEPTION_LOCATION);
19848 
19849  } // if (found_node_pt[j-1] != found_node_pt[j])
19850 
19851  } // for (j < ntimes_node_found)
19852 #endif // #ifdef PARANOID
19853 
19854  // Check if the node is a shared boundary node from the
19855  // current processor and the iproc processor, if that is the
19856  // case, and the node is also on a shared boundary with other
19857  // processor, then the pointer should be the same!!!
19858  if (is_node_on_shared_boundary == 1)
19859  {
19860  // const unsigned n_times_node_found = found_node_pt.size();
19861  // The pointer to the node is already assigned, it was
19862  // assigned when the node was found to be on a shared
19863  // boundary with the sending processor (iproc). Check that
19864  // any previous instances of the node have been copied
19865  // from the shared boundary, if that is not the case then
19866  // there is a problem
19867  if (found_node_pt[0] != new_nod_pt)
19868  {
19869  std::ostringstream error_message;
19870  error_message
19871  << "The pointer of the node that was found to be on a\n"
19872  << "shared boundary with other processor(s) and the pointer\n"
19873  << "of the node on shared boundary with the receiver\n"
19874  << "processor (iproc) are not the same. This means we have a\n"
19875  << "repeated node)\n"
19876  << "The coordinates for the nodes are:\n"
19877  << "(" << found_node_pt[0]->x(0) << ", " << found_node_pt[0]->x(1)
19878  << ")\n"
19879  << "(" << new_nod_pt->x(0) << ", " << new_nod_pt->x(1) << ")\n"
19880  << "Dont be surprised if they are the same since the "
19881  << "node is\nrepeated.\n";
19882  throw OomphLibError(error_message.str(),
19883  OOMPH_CURRENT_FUNCTION,
19884  OOMPH_EXCEPTION_LOCATION);
19885 
19886  } // if (found_node_pt[i] != new_nod_pt)
19887 
19888  } // if (is_node_on_shared_boundary == 1)
19889  else
19890  {
19891  // Take the first instance of the node in case that it was
19892  // found and is not on a shared boundary with the iproc
19893  // processor (the processor from which we are receiving
19894  // the info.)
19895  new_nod_pt = found_node_pt[0];
19896  }
19897 
19898  } // if (found_node_in_other_shared_boundaries)
19899 
19900  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19901 
19902  // -----------------------------------------------------------------
19903  // Create the node or read the received info if the node is not on a
19904  // shared boundary with the iproc processor
19905  if (is_node_on_shared_boundary != 1)
19906  {
19907  // If the node is on a shared boundary with other processor we
19908  // need to read all the info. since the processor that sent the
19909  // info. did not know that the node is part of another shared
19910  // boundary
19911 
19912  // If the node is not on a shared boundary (with any processor),
19913  // or if this is the first time that the info. of the node is
19914  // received from any of the processors with which it has a shared
19915  // boundary, then we create the node
19916 
19917  // Is the node a boundary node or should it be build as a boundary
19918  // node because it is on a shared boundary with other processors
19919  if (node_on_original_boundaries == 2 || build_node_as_boundary_node)
19920  {
19921  // Check if necessary to create the node, or if it has been
19922  // already found in shared boundaries with other processors
19923  if (!found_node_in_other_shared_boundaries)
19924  {
19925  // Construct a boundary node
19926  if (time_stepper_pt != 0)
19927  {
19928  new_nod_pt =
19929  new_el_pt->construct_boundary_node(node_index, time_stepper_pt);
19930  }
19931  else
19932  {
19933  new_nod_pt = new_el_pt->construct_boundary_node(node_index);
19934  }
19935 
19936  } // if (!found_node_in_other_shared_boundaries)
19937  else
19938  {
19939  // If the node was found then assign the node to the element
19940  new_el_pt->node_pt(node_index) = new_nod_pt;
19941 
19942  } // else if (!found_node_in_other_shared_boundaries)
19943 
19944  // Associate the node to the given boundaries
19945  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
19946  {
19947  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
19948  // Establish the boundary coordinates for the node
19949  Vector<double> zeta(1);
19950  zeta[0] = zeta_coordinates[i];
19951  new_nod_pt->set_coordinates_on_boundary(
19952  original_boundaries_node_is_on[i], zeta);
19953  }
19954 
19955  } // if (node is on an original boundary)
19956  else
19957  {
19958  // Check if necessary to create the node, or if it has been
19959  // already found in shared boundaries with other processors
19960  if (!found_node_in_other_shared_boundaries)
19961  {
19962  // Construct an ordinary (non-boundary) node
19963  if (time_stepper_pt != 0)
19964  {
19965  new_nod_pt = new_el_pt->construct_node(node_index, time_stepper_pt);
19966  }
19967  else
19968  {
19969  new_nod_pt = new_el_pt->construct_node(node_index);
19970  }
19971  } // if (!found_node_in_other_shared_boundaries)
19972  else
19973  {
19974  // If the node was found then assign the node to the element
19975  new_el_pt->node_pt(node_index) = new_nod_pt;
19976  } // else if (!found_node_in_other_shared_boundaries)
19977 
19978  } // else (the node is not a boundary node)
19979 
19980  // ... and gather all its information
19981 
19982  // If the node was found or not in other shared boundaries, this
19983  // is the first time the node is received from this processor
19984  // (iproc), therefore it is added to the vector of nodes received
19985  // from this processor (iproc)
19986  new_nodes_on_domain.push_back(new_nod_pt);
19987 
19988  // Check if necessary to state all the info. to the node if it has
19989  // been already found in shared boundaries with other processors
19990  if (!found_node_in_other_shared_boundaries)
19991  {
19992  // Add the node to the general node storage
19993  this->add_node_pt(new_nod_pt);
19994  } // if (!found_node_in_other_shared_boundaries)
19995 
19996  // Is the new constructed node Algebraic?
19997  AlgebraicNode* new_alg_nod_pt = dynamic_cast<AlgebraicNode*>(new_nod_pt);
19998 
19999  // If it is algebraic, its node update functions will
20000  // not yet have been set up properly
20001  if (new_alg_nod_pt != 0)
20002  {
20003  // The AlgebraicMesh is the external mesh
20004  AlgebraicMesh* alg_mesh_pt = dynamic_cast<AlgebraicMesh*>(this);
20005 
20006  /// The first entry of All_alg_nodal_info contains
20007  /// the default node update id
20008  /// e.g. for the quarter circle there are
20009  /// "Upper_left_box", "Lower right box" etc...
20010 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
20011  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
20012  << " Alg node update id "
20013  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
20014  << std::endl;
20015 #endif
20016 
20017  unsigned update_id =
20018  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
20019 
20020  Vector<double> ref_value;
20021 
20022  // The size of this vector is in the next entry
20023  // of All_alg_nodal_info
20024 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
20025  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
20026  << " Alg node # of ref values "
20027  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
20028  << std::endl;
20029 #endif
20030  unsigned n_ref_val =
20031  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
20032 
20033  // The reference values themselves are in
20034  // All_alg_ref_value
20035  ref_value.resize(n_ref_val);
20036  for (unsigned i_ref = 0; i_ref < n_ref_val; i_ref++)
20037  {
20038  ref_value[i_ref] =
20039  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
20040  }
20041 
20042  Vector<GeomObject*> geom_object_pt;
20043  /// again we need the size of this vector as it varies
20044  /// between meshes; we also need some indication
20045  /// as to which geometric object should be used...
20046 
20047  // The size of this vector is in the next entry
20048  // of All_alg_nodal_info
20049 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
20050  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
20051  << " Alg node # of geom objects "
20052  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
20053  << std::endl;
20054 #endif
20055  unsigned n_geom_obj =
20056  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
20057 
20058  // The remaining indices are in the rest of
20059  // All_alg_nodal_info
20060  geom_object_pt.resize(n_geom_obj);
20061  for (unsigned i_geom = 0; i_geom < n_geom_obj; i_geom++)
20062  {
20063 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
20064  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
20065  << " Alg node: geom object index "
20066  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
20067  << std::endl;
20068 #endif
20069  unsigned geom_index =
20070  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
20071  // This index indicates which of the AlgebraicMesh's
20072  // stored geometric objects should be used
20073  // (0 is a null pointer; everything else should have
20074  // been filled in by the specific Mesh). If it
20075  // hasn't been filled in then the update_node_update
20076  // call should fix it
20077  geom_object_pt[i_geom] = alg_mesh_pt->geom_object_list_pt(geom_index);
20078  }
20079 
20080  // Check if necessary to state all the info. to the node if it has
20081  // been already found in shared boundaries with other processors
20082  if (!found_node_in_other_shared_boundaries)
20083  {
20084  /// For the received update_id, ref_value, geom_object
20085  /// call add_node_update_info
20086  new_alg_nod_pt->add_node_update_info(
20087  update_id, alg_mesh_pt, geom_object_pt, ref_value);
20088 
20089  /// Now call update_node_update
20090  alg_mesh_pt->update_node_update(new_alg_nod_pt);
20091 
20092  } // if (!found_node_in_other_shared_boundaries)
20093 
20094  } // if (new_alg_nod_pt!=0)
20095 
20096  // Check if necessary to state all the info. to the node if it has
20097  // been already found in shared boundaries with other processors
20098  if (!found_node_in_other_shared_boundaries)
20099  {
20100  // Is the node a MacroElementNodeUpdateNode?
20101  MacroElementNodeUpdateNode* macro_nod_pt =
20102  dynamic_cast<MacroElementNodeUpdateNode*>(new_nod_pt);
20103 
20104  if (macro_nod_pt != 0)
20105  {
20106  // Need to call set_node_update_info; this requires
20107  // a Vector<GeomObject*> (taken from the mesh)
20108  Vector<GeomObject*> geom_object_vector_pt;
20109 
20110  // Access the required geom objects from the
20111  // MacroElementNodeUpdateMesh
20112  MacroElementNodeUpdateMesh* macro_mesh_pt =
20113  dynamic_cast<MacroElementNodeUpdateMesh*>(this);
20114  geom_object_vector_pt = macro_mesh_pt->geom_object_vector_pt();
20115 
20116  // Get local coordinate of node in new element
20117  Vector<double> s_in_macro_node_update_element;
20118  new_el_pt->local_coordinate_of_node(node_index,
20119  s_in_macro_node_update_element);
20120 
20121  // Set node update info for this node
20122  macro_nod_pt->set_node_update_info(
20123  new_el_pt, s_in_macro_node_update_element, geom_object_vector_pt);
20124  }
20125 
20126  } // if (!found_node_in_other_shared_boundaries)
20127 
20128  // If there are additional values, resize the node
20129  unsigned n_new_val = new_nod_pt->nvalue();
20130 
20131  // Check if necessary to state all the info. to the node if it has
20132  // been already found in shared boundaries with other processors
20133  if (!found_node_in_other_shared_boundaries)
20134  {
20135  if (n_val > n_new_val)
20136  {
20137  // If it has been necessary to resize then it may be becuse
20138  // the node is on a FSI boundary, if that is the case we need
20139  // to set a map for these external values
20140 
20141  // Cast to a boundary node
20142  BoundaryNodeBase* bnod_pt =
20143  dynamic_cast<BoundaryNodeBase*>(new_nod_pt);
20144 
20145  // Create storage, if it doesn't already exist, for the map
20146  // that will contain the position of the first entry of
20147  // this face element's additional values,
20148  if (bnod_pt->index_of_first_value_assigned_by_face_element_pt() == 0)
20149  {
20150  bnod_pt->index_of_first_value_assigned_by_face_element_pt() =
20151  new std::map<unsigned, unsigned>;
20152  }
20153 
20154  // Get pointer to the map
20155  std::map<unsigned, unsigned>* map_pt =
20156  bnod_pt->index_of_first_value_assigned_by_face_element_pt();
20157 
20158  // The id of the face to which this node belong in the bulk
20159  // element
20160  const unsigned id_face = 0;
20161  // We only resize the node values Vector if we haven't done it yet
20162  std::map<unsigned, unsigned>::const_iterator p =
20163  map_pt->find(id_face);
20164 
20165  // If this node hasn't been resized for current id
20166  if (p == map_pt->end())
20167  {
20168  // assign the face element id and the position of the
20169  // first entry to the boundary node
20170  (*map_pt)[id_face] = n_new_val;
20171 
20172  // resize the node vector of values
20173  new_nod_pt->resize(n_val);
20174  }
20175 
20176  } // if (n_val>n_new_val)
20177 
20178  } // if (!found_node_in_other_shared_boundaries)
20179 
20180  // Is the new node a SolidNode?
20181  SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(new_nod_pt);
20182  if (solid_nod_pt != 0)
20183  {
20184  unsigned n_solid_val = solid_nod_pt->variable_position_pt()->nvalue();
20185  for (unsigned i_val = 0; i_val < n_solid_val; i_val++)
20186  {
20187  for (unsigned t = 0; t < n_prev; t++)
20188  {
20189  double read_data =
20190  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
20191 
20192  // Check if necessary to state all the info. to the node if it has
20193  // been already found in shared boundaries with other processors
20194  if (!found_node_in_other_shared_boundaries)
20195  {
20196  solid_nod_pt->variable_position_pt()->set_value(
20197  t, i_val, read_data);
20198  } // if (!found_node_in_other_shared_boundaries)
20199  }
20200  }
20201 
20202 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
20203  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
20204  << " Number of values solid node: "
20205  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
20206  << std::endl;
20207 #endif
20208  const unsigned nvalues_solid_node =
20209  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
20210  Vector<double> values_solid_node(nvalues_solid_node);
20211  for (unsigned i = 0; i < nvalues_solid_node; i++)
20212  {
20213  values_solid_node[i] =
20214  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
20215  }
20216 
20217  // Check if necessary to state all the info. to the node if it has
20218  // been already found in shared boundaries with other processors
20219  if (!found_node_in_other_shared_boundaries)
20220  {
20221  unsigned index = 0;
20222  solid_nod_pt->read_values_from_vector(values_solid_node, index);
20223  }
20224  }
20225 
20226  // Get copied history values
20227  // unsigned n_val=new_nod_pt->nvalue();
20228  for (unsigned i_val = 0; i_val < n_val; i_val++)
20229  {
20230  for (unsigned t = 0; t < n_prev; t++)
20231  {
20232  double read_data =
20233  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
20234 
20235  // Check if necessary to state all the info. to the node if it
20236  // has been already found in shared boundaries with other
20237  // processors
20238  if (!found_node_in_other_shared_boundaries)
20239  {
20240  new_nod_pt->set_value(t, i_val, read_data);
20241  } // if (!found_node_in_other_shared_boundaries)
20242  }
20243  }
20244 
20245  // Get copied history values for positions
20246  unsigned n_dim = new_nod_pt->ndim();
20247  for (unsigned idim = 0; idim < n_dim; idim++)
20248  {
20249  for (unsigned t = 0; t < n_prev; t++)
20250  {
20251  double read_data =
20252  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
20253 
20254  // Check if necessary to state all the info. to the node if it
20255  // has been already found in shared boundaries with other
20256  // processors
20257  if (!found_node_in_other_shared_boundaries)
20258  {
20259  // Copy to coordinate
20260  new_nod_pt->x(t, idim) = read_data;
20261 
20262  } // if (!found_node_in_other_shared_boundaries)
20263  }
20264  }
20265 
20266  } // if (is_node_on_shared_boundary != 1)
20267 
20268  // If the node was not found in other shared boundaries (possibly
20269  // because it is the first time the node has been sent) then copy
20270  // the node to the shared boundaries where it should be, use the
20271  // special container for this cases
20272  if (n_shd_bnd_with_other_procs_have_node > 0 && // The node is on
20273  // shared
20274  // boundaries with
20275  // other processors
20276  !found_node_in_other_shared_boundaries) // The node has not
20277  // been previously
20278  // set as
20279  // shared with
20280  // other processors
20281  // (first time)
20282  {
20283  // Update the node pointer in all the (references) of the node
20284  this->update_other_proc_shd_bnd_node_helper(new_nod_pt,
20285  other_proc_shd_bnd_node_pt,
20286  other_processor_1,
20287  other_processor_2,
20288  other_shared_boundaries,
20289  other_indexes,
20290  global_node_names,
20291  node_name_to_global_index,
20292  global_shared_node_pt);
20293 
20294  } // if (!found_node_in_other_shared_boundaries)
20295  }
20296 
20297  //========start of update_other_proc_shd_bnd_node_helper=================
20298  // Helper function that assigns/updates the references to the node so
20299  // that it can be found with any other reference
20300  //========================================================================
20301  template<class ELEMENT>
20303  Node*& new_node_pt,
20304  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
20305  other_proc_shd_bnd_node_pt,
20306  Vector<unsigned>& other_processor_1,
20307  Vector<unsigned>& other_processor_2,
20308  Vector<unsigned>& other_shared_boundaries,
20309  Vector<unsigned>& other_indexes,
20310  Vector<Vector<Vector<unsigned>>>& global_node_names,
20311  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
20312  Vector<Node*>& global_shared_node_pt)
20313  {
20314  // Get the number of initial shared boundaries to correct the index
20315  // of the shared boundary
20316  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
20317 
20318 #ifdef PARANOID
20319  // Get the number of instances of the node on other shared
20320  // boundaries with other processors
20321  const unsigned n_data = other_processor_1.size();
20322 #endif // #ifdef PARANOID
20323 
20324  // Create the first node name
20325  Vector<unsigned> node_name(4);
20326  node_name[0] = other_processor_1[0];
20327  node_name[1] = other_processor_2[0];
20328  node_name[2] = other_shared_boundaries[0];
20329  node_name[3] = other_indexes[0];
20330 
20331 #ifdef PARANOID
20332  // Get the global node index, and all the names of the node
20333  std::map<Vector<unsigned>, unsigned>::iterator it =
20334  node_name_to_global_index.find(node_name);
20335  if (it == node_name_to_global_index.end())
20336  {
20337  std::ostringstream error_stream;
20338  error_stream << "The node name does not exist in the global node names\n"
20339  << "This is the name of the node\n"
20340  << "Name: iproc, jproc, ishd_bnd, idx\n"
20341  << "Name: " << node_name[0] << ", " << node_name[1] << ", "
20342  << node_name[2] << ", " << node_name[3] << "\n";
20343  throw OomphLibError(
20344  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
20345  } // if (it!=node_name_to_global_index.end())
20346 #endif // #ifdef PARANOID
20347 
20348  // Get the global node index
20349  const unsigned iglobal_node = node_name_to_global_index[node_name];
20350  // Add the node to the global shared node container
20351  global_shared_node_pt[iglobal_node] = new_node_pt;
20352  // Get the names
20353  Vector<Vector<unsigned>> inode_names = global_node_names[iglobal_node];
20354  // Get the number of names of the node
20355  const unsigned n_names = inode_names.size();
20356 
20357 #ifdef PARANOID
20358  // Check that the received names of the node are part of the global
20359  // node names
20360  unsigned n_found_node_names_on_global_node_name = 0;
20361  // loop over the input node names
20362  for (unsigned j = 0; j < n_data; j++)
20363  {
20364  // loop over the inode_names
20365  for (unsigned k = 0; k < n_names; k++)
20366  {
20367  // Is this input name part of the global node names?
20368  if (inode_names[k][0] == other_processor_1[j] &&
20369  inode_names[k][1] == other_processor_2[j] &&
20370  inode_names[k][2] == other_shared_boundaries[j] &&
20371  inode_names[k][3] == other_indexes[j])
20372  {
20373  // Increase the number of found input node names in the
20374  // global node names
20375  n_found_node_names_on_global_node_name++;
20376  }
20377 
20378  } // for (k < n_names)
20379 
20380  } // for (j < n_data)
20381 
20382  // Were all the input node names found on the global node names?
20383  if (n_found_node_names_on_global_node_name != n_data)
20384  {
20385  std::ostringstream error_stream;
20386  error_stream
20387  << "Not all the node names of the current node were found on the\n"
20388  << "global node names. This happened when adding the node pointer\n"
20389  << "to the data structure that keeps tracks of nodes on shared\n"
20390  << "boundaries with other processors\n\n"
20391  << "These are the names of the current node\n"
20392  << "Name k: iproc, jproc, ishd_bnd, idx\n";
20393  for (unsigned j = 0; j < n_data; j++)
20394  {
20395  error_stream << "Name(" << j << "): " << other_processor_1[j] << ", "
20396  << other_processor_2[j] << ", "
20397  << other_shared_boundaries[j] << ", " << other_indexes[j]
20398  << "\n";
20399  }
20400 
20401  error_stream << "\n\nThese are the names of the global node\n"
20402  << "Name k: iproc, jproc, ishd_bnd, idx\n";
20403  for (unsigned k = 0; k < n_names; k++)
20404  {
20405  error_stream << "Name(" << k << "): " << inode_names[k][0] << ", "
20406  << inode_names[k][1] << ", " << inode_names[k][2] << ", "
20407  << inode_names[k][3] << "\n";
20408  }
20409 
20410  throw OomphLibError(
20411  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
20412  }
20413 #endif // #ifdef PARANOID
20414 
20415  // Set the node pointer in all of its names
20416  for (unsigned j = 0; j < n_names; j++)
20417  {
20418  // Get the j-th node name
20419  const unsigned iproc = inode_names[j][0];
20420  const unsigned jproc = inode_names[j][1];
20421  const unsigned ishd_bnd = inode_names[j][2] - initial_shd_bnd_id;
20422  const unsigned index = inode_names[j][3];
20423 
20424  // The info. is stored only in one direction
20425  // Get the smallest processor number
20426  if (iproc < jproc)
20427  {
20428  other_proc_shd_bnd_node_pt[iproc][jproc][ishd_bnd][index] = new_node_pt;
20429  }
20430  else
20431  {
20432  other_proc_shd_bnd_node_pt[jproc][iproc][ishd_bnd][index] = new_node_pt;
20433  }
20434 
20435  } // for (j < n_names)
20436  }
20437 
20438  // *********************************************************************
20439  // End communication functions
20440  // *********************************************************************
20441 
20442  // *********************************************************************
20443  // BEGIN: Methods to perform load balance
20444  // *********************************************************************
20445 
20446  //======================================================================
20447  /// Performs the load balancing for unstructured meshes, the
20448  /// load balancing strategy is based on mesh migration
20449  //======================================================================
20450  template<class ELEMENT>
20452  const Vector<unsigned>& target_domain_for_local_non_halo_element)
20453  {
20454  oomph_info << "Load balance (unstructured mesh) [BEGIN]" << std::endl;
20455 
20456  // This method can only be called when the mesh has been already
20457  // distributed
20458  if (!this->is_mesh_distributed())
20459  {
20460  std::ostringstream warning_message;
20461  warning_message
20462  << "\n===============================================================\n"
20463  << "The load balancing can only be performed in distributed meshes,\n"
20464  << "your mesh has not been distributed.\n"
20465  << "==============================================================="
20466  "\n\n";
20467  OomphLibWarning(warning_message.str(),
20468  OOMPH_CURRENT_FUNCTION,
20469  OOMPH_EXCEPTION_LOCATION);
20470  // Return
20471  return;
20472  }
20473 
20474  // Get the number of processors
20475  const unsigned nproc = this->communicator_pt()->nproc();
20476  // Get the rank of the current processors
20477  const unsigned my_rank = this->communicator_pt()->my_rank();
20478 
20479  // Check that there are at least two processors
20480  if (nproc == 1)
20481  {
20482  std::ostringstream warning_message;
20483  warning_message
20484  << "\n===============================================================\n"
20485  << "The load balancing can only be performed when there are at least\n"
20486  << "two procesors, the current number of processors is one.\n"
20487  << "==============================================================="
20488  "\n\n";
20489  OomphLibWarning(warning_message.str(),
20490  OOMPH_CURRENT_FUNCTION,
20491  OOMPH_EXCEPTION_LOCATION);
20492  // Return
20493  return;
20494  }
20495 
20496  // Get the time before load balance
20497  double t_start_overall_load_balance = 0.0;
20498  if (Print_timings_level_load_balance > 1)
20499  {
20500  t_start_overall_load_balance = TimingHelpers::timer();
20501  }
20502 
20503  // Get the number of elements in the mesh before load balance
20504  const unsigned nelement_before_load_balance = this->nelement();
20505 
20506 #ifdef PARANOID
20507  // The number of elements in the mesh and the number of target
20508  // domains for the local non halo elements in the mesh should match
20509  if (nnon_halo_element() != target_domain_for_local_non_halo_element.size())
20510  {
20511  std::ostringstream error_message;
20512  error_message << "The number of non halo elements in the current mesh ("
20513  << nnon_halo_element() << ") and the number\n"
20514  << "of target areas for the local non halo elements ("
20515  << target_domain_for_local_non_halo_element.size()
20516  << ") is different\n\n";
20517  throw OomphLibError(
20518  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
20519  }
20520 #endif
20521 
20522  // Backup pointers to elements in this mesh
20523  Vector<FiniteElement*> backed_up_ele_pt(nelement_before_load_balance);
20524  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20525  {
20526  backed_up_ele_pt[e] = this->finite_element_pt(e);
20527  }
20528 
20529  // =====================================================================
20530  // BEGIN: GET THE DOMAINS FOR THE HALO ELEMENTS
20531  // =====================================================================
20532 
20533  // Get the time to get the domains of halo elements
20534  double tt_start_get_domains_halo_elements = 0.0;
20535  if (Print_timings_level_load_balance > 1)
20536  {
20537  tt_start_get_domains_halo_elements = TimingHelpers::timer();
20538  }
20539 
20540  // Get the new domains for the halo elements
20541 
20542  // Send the new domains for the current haloed elements, and receive
20543  // the new domains for the current halo elements
20544  // -- 1) On the current processor get the new domains for the
20545  // haloed elements
20546  // -- 2) Then send this info. to all the processor that have a
20547  // halo copy of the element
20548 
20549  // The storing for the new domains of the haloed elements (sent to
20550  // other processors)
20551  Vector<Vector<unsigned>> new_domains_haloed_elements(nproc);
20552  // The storing for the new domains of the halo elements (received
20553  // from other processors)
20554  Vector<Vector<unsigned>> new_domains_halo_elements(nproc);
20555 
20556  // First resize the containers by getting the current number of
20557  // halo/haloed elements within each processor
20558  for (unsigned iproc = 0; iproc < nproc; iproc++)
20559  {
20560  // There are no halo/haloed elements with myself (my_rank
20561  // processor)
20562  if (iproc != my_rank)
20563  {
20564  // Get the number of halo elements with iproc processor
20565  const unsigned n_halo_iproc = this->nroot_halo_element(iproc);
20566  // Resize the container
20567  new_domains_halo_elements[iproc].resize(n_halo_iproc);
20568 
20569  // Get the number of haloed elements with iproc processor
20570  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20571  // Resize the container
20572  new_domains_haloed_elements[iproc].resize(n_haloed_iproc);
20573  } // if (iproc != my_rank)
20574  } // for (iproc < nproc)
20575 
20576 #ifdef PARANOID
20577  // Count the number of found haloed elements
20578  Vector<unsigned> counter_for_found_haloed_elements(nproc, 0);
20579 #endif
20580 
20581  // Go through all the haloed elements and find their new domain
20582 
20583  // Get the haloed elements with in each processor and check if the
20584  // element is haloed with the processor
20585  for (unsigned iproc = 0; iproc < nproc; iproc++)
20586  {
20587  // There are no halo/haloed elements with myself (my_rank
20588  // processor)
20589  if (iproc != my_rank)
20590  {
20591  // Get the number of haloed elements with iproc processor
20592  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20593 
20594  // Loop over the haloed elements
20595  for (unsigned ihd = 0; ihd < n_haloed_iproc; ihd++)
20596  {
20597  // Get the ihd-th haloed element with "iproc" processor
20598  GeneralisedElement* haloed_ele_pt =
20599  this->root_haloed_element_pt(iproc, ihd);
20600 
20601  // The counter for the nonhalo elements
20602  unsigned nh_count4 = 0;
20603  // Find the element in the general elements container
20604  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20605  {
20606  // Get the e-th element
20607  GeneralisedElement* ele_pt = this->element_pt(e);
20608  // Check if the element is a nonhalo element
20609  if (!ele_pt->is_halo())
20610  {
20611  // Increase the counter for nonhalo elements, in case the
20612  // haloed element is found get the (nh_count4-1) position
20613  // in the target domains vector
20614  nh_count4++;
20615 
20616  if (ele_pt == haloed_ele_pt)
20617  {
20618  // Get the new domain for this element
20619  const unsigned element_domain =
20620  target_domain_for_local_non_halo_element[nh_count4 - 1];
20621  // Here decrease the counter ---------------------^
20622 
20623  // Set the new domain for the haloed element in the
20624  // special container
20625  new_domains_haloed_elements[iproc][ihd] = element_domain;
20626 #ifdef PARANOID
20627  // Increase the counter
20628  counter_for_found_haloed_elements[iproc]++;
20629 #endif
20630  // ... and break the "for" with the general
20631  // elements. Continue with the next haloed element
20632  break;
20633 
20634  } // if (ele_pt == haloed_ele_pt))
20635 
20636  } // if (!ele_pt->is_halo())
20637 
20638  } // for (e < nelement_before_load_balance)
20639 
20640  } // for (ihd < n_haloed_iproc)
20641 
20642  } // if (iproc != my_rank)
20643 
20644  } // for (iproc < nproc)
20645 
20646 #ifdef PARANOID
20647  // Check that all the haloed elements with all processors have been
20648  // found
20649  for (unsigned iproc = 0; iproc < nproc; iproc++)
20650  {
20651  // There are no halo/haloed elements with myself (my_rank
20652  // processor)
20653  if (iproc != my_rank)
20654  {
20655  // Get the number of haloed elements with "iproc" processor
20656  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20657 
20658  // Compare the number of found haloed elements with the current
20659  // number of haloed elements
20660  if (n_haloed_iproc != counter_for_found_haloed_elements[iproc])
20661  {
20662  std::ostringstream error_message;
20663  error_message << "The independent counting of found haloed elements ("
20664  << counter_for_found_haloed_elements[iproc]
20665  << ") with processor (" << iproc
20666  << ") is not equal to the number of haloed elements ("
20667  << n_haloed_iproc << ") with processor (" << iproc
20668  << ")\n";
20669  throw OomphLibError(error_message.str(),
20670  OOMPH_CURRENT_FUNCTION,
20671  OOMPH_EXCEPTION_LOCATION);
20672  } // if (nhaloed_iproc == counter_for_found_haloed_elements[iproc])
20673 
20674  } // if (iproc != my_rank)
20675 
20676  } // for (iproc < nproc)
20677 #endif
20678 
20679  // Now we have the new domains for the haloed elements
20680 
20681  // Send this info. to the processor with a halo copy of the haloed
20682  // elements and set the new domains in the halo copies
20683 
20684  // First put all the info. in a flat package array
20685  Vector<unsigned> new_domains_haloed_flat_unsigned;
20686  // Put in a vector the number of haloed elements within each
20687  // processor
20688  Vector<int> nhaloed_elements_with_iproc(nproc);
20689  for (unsigned iproc = 0; iproc < nproc; iproc++)
20690  {
20691  // There are no halo/haloed elements with myself (my_rank
20692  // processor)
20693  if (iproc != my_rank)
20694  {
20695  // Get the number of haloed elements with "iproc" processor
20696  const unsigned n_haloed_ele_iproc = this->nroot_haloed_element(iproc);
20697  // Copy the number of haloed elements with "iproc" processor
20698  nhaloed_elements_with_iproc[iproc] = n_haloed_ele_iproc;
20699  // Copy the new domains of the haloed elements in the flat
20700  // package
20701  for (unsigned i = 0; i < n_haloed_ele_iproc; i++)
20702  {
20703  new_domains_haloed_flat_unsigned.push_back(
20704  new_domains_haloed_elements[iproc][i]);
20705  } // for (i < n_haloed_ele_iproc)
20706 
20707  } // if (iproc != my_rank)
20708 
20709  } // for (iproc < nproc)
20710 
20711  // The offsets of the flat package within each processor
20712  Vector<int> offset_haloed_elements_with_iproc(nproc);
20713  offset_haloed_elements_with_iproc[0] = 0;
20714  for (unsigned ip = 1; ip < nproc; ip++)
20715  {
20716  // Compute the offset to send the values to each processor
20717  offset_haloed_elements_with_iproc[ip] =
20718  offset_haloed_elements_with_iproc[ip - 1] +
20719  nhaloed_elements_with_iproc[ip - 1];
20720  } // for (ip < nproc)
20721 
20722  // Prepare to receive the data
20723 
20724  // Compute the number of data (halo elements) to receive from each
20725  // processor and the displacements within each processor
20726 
20727  // Counter for the total number of halo elements within all processors
20728  unsigned counter_halo_ele_with_all_procs = 0;
20729 
20730  // Put in a vector the number of halo elements expected to receive
20731  // from each processor
20732  Vector<int> nhalo_elements_with_iproc(nproc);
20733  // Compute the number of total halo elements of (my_rank) this
20734  // processor with all other processors
20735  for (unsigned iproc = 0; iproc < nproc; iproc++)
20736  {
20737  // There are no halo/haloed elements with myself (my_rank
20738  // processor)
20739  if (iproc != my_rank)
20740  {
20741  // Get the number of halo elements with "iproc" processor
20742  const unsigned n_halo_ele_iproc = this->nroot_halo_element(iproc);
20743  // Copy the number of halo elements with "iproc" processor
20744  nhalo_elements_with_iproc[iproc] = n_halo_ele_iproc;
20745  // Add the number of elements with this processor
20746  counter_halo_ele_with_all_procs += n_halo_ele_iproc;
20747  } // if (iproc != my_rank)
20748 
20749  } // for (iproc < nproc)
20750 
20751  // The offsets of the flat package within each processor
20752  Vector<int> offset_halo_elements_with_iproc(nproc);
20753  offset_halo_elements_with_iproc[0] = 0;
20754  for (unsigned ip = 1; ip < nproc; ip++)
20755  {
20756  // Compute the offset to receive the values from each processor
20757  offset_halo_elements_with_iproc[ip] =
20758  offset_halo_elements_with_iproc[ip - 1] +
20759  nhalo_elements_with_iproc[ip - 1];
20760  } // for (ip < nproc)
20761 
20762  // The flat container to receive the new domains of the halo
20763  // elements in the current processor
20764 
20765  // The flat package where all the info. will be gather from the
20766  // other processors (the halo flat package)
20767  Vector<unsigned> new_domains_halo_flat_unsigned(
20768  counter_halo_ele_with_all_procs);
20769 
20770  // Perform the sending and receiving of information to and from all
20771  // processors
20772  MPI_Alltoallv(&new_domains_haloed_flat_unsigned[0], // void *sendbuf
20773  &nhaloed_elements_with_iproc[0], // int *sendcnts
20774  &offset_haloed_elements_with_iproc[0], // int *sdispls
20775  MPI_UNSIGNED, // MPI_Datatype sendtype
20776  &new_domains_halo_flat_unsigned[0], // void *recvbuf
20777  &nhalo_elements_with_iproc[0], // int *recvcnts
20778  &offset_halo_elements_with_iproc[0], // int *rdispls
20779  MPI_UNSIGNED, // MPI_Datatype recvtype
20780  this->communicator_pt()->mpi_comm()); // MPI_Comm comm
20781 
20782  // Once received the new domains for the halo elements, copy the
20783  // domains back to an easier to handle container (from the flat
20784  // package to the one with the different halo elements domains
20785  // within each processor)
20786  unsigned counter_new_domains_halo_ele = 0;
20787  for (unsigned iproc = 0; iproc < nproc; iproc++)
20788  {
20789  // There are no halo/haloed elements with myself (my_rank
20790  // processor)
20791  if (iproc != my_rank)
20792  {
20793  // Get the number of halo elements with "iproc"
20794  const unsigned ntmp_halo_elements_with_iproc =
20795  nhalo_elements_with_iproc[iproc];
20796  // Loop over the number of halo elements within "iproc" and copy
20797  // the elements from the flat package
20798  for (unsigned i = 0; i < ntmp_halo_elements_with_iproc; i++)
20799  {
20800  // Copy the new domain of the halo elements from the flat
20801  // package to an easier to use container
20802  new_domains_halo_elements[iproc][i] =
20803  new_domains_halo_flat_unsigned[counter_new_domains_halo_ele++];
20804  }
20805  } // if (iproc != my_rank)
20806  } // for (iproc < nproc)
20807 
20808  // The time to get domains of halo elements
20809  if (Print_timings_level_load_balance > 1)
20810  {
20811  oomph_info << "CPU for getting domains halo elements (load balance) [1]: "
20812  << TimingHelpers::timer() - tt_start_get_domains_halo_elements
20813  << std::endl;
20814  }
20815 
20816  // =====================================================================
20817  // END: GET THE DOMAINS FOR THE HALO ELEMENTS
20818  // =====================================================================
20819 
20820  // =====================================================================
20821  // BEGIN: CREATE FINITE ELEMENT LOCAL VERSIONS OF THE HALO(ED)
20822  // ELEMENTS
20823  // =====================================================================
20824 
20825  // Get the time to get FiniteElement versions from Generalised
20826  // halo(ed) elements
20827  double tt_start_get_fe_version_from_ge_halo_ed = 0.0;
20828  if (Print_timings_level_load_balance > 1)
20829  {
20830  tt_start_get_fe_version_from_ge_halo_ed = TimingHelpers::timer();
20831  }
20832 
20833  // The finite element storage for the halo elements
20834  Vector<Vector<FiniteElement*>> f_halo_element_pt(nproc);
20835  // The finite element storage for the haloed elements
20836  Vector<Vector<FiniteElement*>> f_haloed_element_pt(nproc);
20837  // Loop over the processors
20838  for (unsigned iproc = 0; iproc < nproc; iproc++)
20839  {
20840  // There are no halo(ed) elements with myself
20841  if (iproc != my_rank)
20842  {
20843  // Get the number of halo elements with the "iproc" processor
20844  const unsigned nhalo_ele_iproc = this->nroot_halo_element(iproc);
20845  // Get the halo elements with the "iproc" processor
20846  Vector<GeneralisedElement*> halo_element_pt_iproc =
20847  this->root_halo_element_pt(iproc);
20848  // Resize the finite element container
20849  f_halo_element_pt[iproc].resize(nhalo_ele_iproc);
20850  // Loop over the halo elements
20851  for (unsigned ih = 0; ih < nhalo_ele_iproc; ih++)
20852  {
20853  // Get the finite element
20854  FiniteElement* ele_pt =
20855  dynamic_cast<FiniteElement*>(halo_element_pt_iproc[ih]);
20856  // Store the finite element version of the element
20857  f_halo_element_pt[iproc][ih] = ele_pt;
20858  } // for (ih < nhalo_ele_iproc)
20859 
20860  // Get the number of haloed elements with the "iproc" processor
20861  const unsigned nhaloed_ele_iproc = this->nroot_haloed_element(iproc);
20862  // Get the haloed elements with the "iproc" processor
20863  Vector<GeneralisedElement*> haloed_element_pt_iproc =
20864  this->root_haloed_element_pt(iproc);
20865  // Resize the finite element container
20866  f_haloed_element_pt[iproc].resize(nhaloed_ele_iproc);
20867  // Loop over the haloed elements
20868  for (unsigned ihd = 0; ihd < nhaloed_ele_iproc; ihd++)
20869  {
20870  // Get the finite element
20871  FiniteElement* ele_pt =
20872  dynamic_cast<FiniteElement*>(haloed_element_pt_iproc[ihd]);
20873  // Store the finite element version of the element
20874  f_haloed_element_pt[iproc][ihd] = ele_pt;
20875  } // for (ih < nhaloed_ele_iproc)
20876 
20877  } // if (iproc != my_rank)
20878 
20879  } // for (iproc < nproc)
20880 
20881  // The time to get FiniteElement versions from Generalised halo(ed)
20882  // elements
20883  if (Print_timings_level_load_balance > 1)
20884  {
20885  oomph_info << "CPU for getting finite element versions from generalised "
20886  "halo(ed) elements (load balance) [2]: "
20887  << TimingHelpers::timer() -
20888  tt_start_get_fe_version_from_ge_halo_ed
20889  << std::endl;
20890  }
20891 
20892  // =====================================================================
20893  // END: CREATE FINITE ELEMENT LOCAL VERSIONS OF THE HALO(ED)
20894  // ELEMENTS
20895  // =====================================================================
20896 
20897  // =====================================================================
20898  // BEGIN: 1) PREPARE THE ELEMENTS THAT WILL BE SENT TO OTHER PROCESSORS
20899  // ---- HALO ELEMENTS ARE NOT CONSIDERED FOR SENDING
20900  // 2) ASSOCIATE THE NODES WITH THE NEW DOMAIN OF THE ELEMENTS
20901  // ---- THE SAME IS PERFORMED FOR NODES IN HALO ELEMENTS
20902  // =====================================================================
20903 
20904  // Get the time to prepare elements to send to other processors
20905  double tt_start_prepare_element_to_send = 0.0;
20906  if (Print_timings_level_load_balance > 1)
20907  {
20908  tt_start_prepare_element_to_send = TimingHelpers::timer();
20909  }
20910 
20911  // Store the elements that will be sent to other processors
20912  Vector<Vector<FiniteElement*>> elements_to_send_pt(nproc);
20913 
20914  // Associate the nodes of each element with the processor the
20915  // element will live on
20916  std::map<Data*, std::set<unsigned>>
20917  processors_associated_with_data_before_load_balance;
20918 
20919  // Compute the elements that will be sent to other processor and
20920  // associate the nodes with the processor the element will live on
20921  unsigned nh_count3 = 0;
20922  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20923  {
20924  // Get the element
20925  FiniteElement* ele_pt = this->finite_element_pt(e);
20926  // Only work with nonhalo elements
20927  if (!(ele_pt->is_halo()))
20928  {
20929  // Get the new domain for the elment
20930  const unsigned element_domain =
20931  target_domain_for_local_non_halo_element[nh_count3++];
20932 
20933  // Include the element in the corresponding vector
20934  elements_to_send_pt[element_domain].push_back(ele_pt);
20935 
20936  // Get the number of nodes on the element
20937  const unsigned n_nodes = ele_pt->nnode();
20938  // Loop over the nodes
20939  for (unsigned j = 0; j < n_nodes; j++)
20940  {
20941  // Get each node of the element
20942  Node* node_pt = ele_pt->node_pt(j);
20943  // ... and associate it with element domains
20944  processors_associated_with_data_before_load_balance[node_pt].insert(
20945  element_domain);
20946 
20947  } // for (j < n_nodes)
20948 
20949  } // if (!(ele_pt->is_halo()))
20950 
20951  } // for (e < nelement_before_load_balance)
20952 
20953  // ... do the same for the halo elements (but do not add them to the
20954  // sending container since only the processor with the haloed
20955  // counterparts is in charge of that). Associate the nodes of the
20956  // halo elements with the processor they will live on
20957  for (unsigned iproc = 0; iproc < nproc; iproc++)
20958  {
20959  // There is no halo elements with myself
20960  if (iproc != my_rank)
20961  {
20962  // Get the number of halo elements with the "iproc" processor
20963  const unsigned n_halo_ele_iproc = this->nroot_halo_element(iproc);
20964  // Get the halo elements with the "iproc" processor
20965  Vector<GeneralisedElement*> halo_element_pt_iproc =
20966  this->root_halo_element_pt(iproc);
20967  // Loop over the halo elements with iproc
20968  for (unsigned ih = 0; ih < n_halo_ele_iproc; ih++)
20969  {
20970  // Get the new domain for the halo element
20971  const unsigned element_domain = new_domains_halo_elements[iproc][ih];
20972 
20973  // Get the finite element
20974  FiniteElement* ele_pt =
20975  dynamic_cast<FiniteElement*>(halo_element_pt_iproc[ih]);
20976 
20977  // Get the number of nodes on the halo element
20978  const unsigned n_nodes = ele_pt->nnode();
20979  // Loop over the nodes
20980  for (unsigned j = 0; j < n_nodes; j++)
20981  {
20982  // Get each node of the halo element
20983  Node* node_pt = ele_pt->node_pt(j);
20984 
20985  // ... and associate it with element domains
20986  processors_associated_with_data_before_load_balance[node_pt].insert(
20987  element_domain);
20988 
20989  } // for (j < n_nodes)
20990 
20991  } // for (ih < nhalo_ele_iproc)
20992 
20993  } // if (iproc != my_rank)
20994 
20995  } // for (iproc < nproc)
20996 
20997  // The time to prepare elements to send to other processors
20998  if (Print_timings_level_load_balance > 1)
20999  {
21000  oomph_info << "CPU for preparing elements to send to other processors "
21001  "(load balance) [3]: "
21002  << TimingHelpers::timer() - tt_start_prepare_element_to_send
21003  << std::endl;
21004  }
21005 
21006  // Now all the nodes are associated with the processor where the
21007  // element will live on. This is performed for the nonhalo and halo
21008  // elements
21009 
21010  // =====================================================================
21011  // END: 1) PREPARE THE ELEMENTS THAT WILL BE SENT TO OTHER PROCESSORS
21012  // ---- HALO ELEMENTS ARE NOT CONSIDERED FOR SENDING
21013  // 2) ASSOCIATE THE NODES WITH THE NEW DOMAIN OF THE ELEMENTS
21014  // ---- THE SAME IS PERFORMED FOR NODES IN HALO ELEMENTS
21015  // =====================================================================
21016 
21017  // =====================================================================
21018  // BEGIN: COMPUTE THE NEW LOCAL HALO ELEMENTS OF ALL PROCESSORS IN THE
21019  // CURRENT PROCESSOR
21020  // ----- FOR NONHALO ELEMENTS AND FOR HALO ELEMENTS
21021  // =====================================================================
21022 
21023  // Get the time to compute new local halo elements within all
21024  // processors
21025  double tt_start_compute_new_local_halo_elements = 0.0;
21026  if (Print_timings_level_load_balance > 1)
21027  {
21028  tt_start_compute_new_local_halo_elements = TimingHelpers::timer();
21029  }
21030 
21031  // Before sending the elements across compute the new local
21032  // halo/haloed elements of each processor. Each processor could have
21033  // elements that will be part of the new halo/haloed elements of
21034  // another processors, then these processors need to compute the
21035  // relations that may happen among these other processors
21036 
21037  // Example:
21038  // Processor 1 may have elements that will be sent to processor 3
21039  // and 4. These processors need to know about the new halo elements
21040  // betweeen them but at this moment only processor 1 can compute that
21041  // info., since it is the only one that currently has that info.
21042 
21043  // Store the new local-halo elements of each processor, the HALOED
21044  // elements are also stored in the container, only needs to INVERT
21045  // the indexes. For example, the HALO elements of processor 2 with
21046  // processor 3 are stored in new_local_halo_element_pt[2][3], and
21047  // the HALOED elements of processor 2 with processor 3 are stored in
21048  // new_local_halo_element_pt[3][2]. Notice that these are also the
21049  // halo elements of processor 3 with 2
21050 
21051  // How to identify the new local halo/haloed element: 1) Loop over
21052  // the element; 2) Only work with nonhalo elements; 3) If the
21053  // element is not assigned to the current processor (iproc) then
21054  // check; 4) Is one of its nodes assiociated to the iproc processor?
21055  // 5) If yes the element is a halo in the iproc processor whose
21056  // nonhalo counter part (haloed) lives in the domain assigned to the
21057  // element
21058  Vector<Vector<Vector<FiniteElement*>>> new_local_halo_element_pt(nproc);
21059 
21060  // Loop over the processors
21061  for (unsigned iproc = 0; iproc < nproc; iproc++)
21062  {
21063  // Resize the container
21064  new_local_halo_element_pt[iproc].resize(nproc);
21065 
21066  // Boolean to know which elements have been already added to the
21067  // new local halo scheme in "iproc"
21068  Vector<std::map<FiniteElement*, bool>> new_local_halo_already_added(
21069  nproc);
21070 
21071  // Go through all the elements and identify the new local halo
21072  // elements of "iproc"
21073  unsigned nh_count5 = 0;
21074  for (unsigned e = 0; e < nelement_before_load_balance; e++)
21075  {
21076  // Get the element
21077  FiniteElement* ele_pt = this->finite_element_pt(e);
21078  // Only work with nonhalo elements
21079  if (!(ele_pt->is_halo()))
21080  {
21081  // Get the domain to which the current element is associated
21082  const unsigned ele_domain =
21083  target_domain_for_local_non_halo_element[nh_count5++];
21084  // If the current element is not associated to the "iproc"
21085  // processor then it could be a halo element
21086  if (ele_domain != iproc)
21087  {
21088  // Get the number of nodes
21089  const unsigned nnodes = ele_pt->nnode();
21090  // Loop over the nodes
21091  for (unsigned j = 0; j < nnodes; j++)
21092  {
21093  Node* node_pt = ele_pt->node_pt(j);
21094  // Check if the node is associated with the current
21095  // "iproc" processor
21096  std::set<unsigned>::iterator it =
21097  processors_associated_with_data_before_load_balance[node_pt]
21098  .find(iproc);
21099  // If it is found then the element is a halo-element
21100  if (it !=
21101  processors_associated_with_data_before_load_balance[node_pt]
21102  .end())
21103  {
21104  // Add the element as new local-halo element with the
21105  // "ele_domain" processor. The non-halo counterpart will
21106  // be located on "ele_domain" processor after sending
21107  // elements across
21108  if (!new_local_halo_already_added[ele_domain][ele_pt])
21109  {
21110  // The element is a halo element on "iproc" with
21111  // "ele_domain"
21112  new_local_halo_element_pt[iproc][ele_domain].push_back(
21113  ele_pt);
21114  // Mark as done
21115  new_local_halo_already_added[ele_domain][ele_pt] = true;
21116  } // if (!new_local_halo_already_added[ele_domain][ele_pt])
21117  } // One of the nodes lies on an element on the current
21118  // "iproc" processor
21119  } // for (j < nnodes)
21120  } // if (ele_domain != iproc)
21121  } // if (!(ele_pt->is_halo()))
21122  } // for (e < nelement_before_load_balance)
21123 
21124  // Now do the same with the halo elements, we need to find those
21125  // halo elements that continue being halo elements but possibly
21126  // with/on another processor. The pair of processors where a
21127  // possible shared boundary is created needs to be notified.
21128 
21129  // Example
21130  //
21131  // ---------------* *---------------
21132  // | |* *| |
21133  // | |* *| |
21134  // | New domain |* *| New domain | * Mark the position
21135  // | proc 1 |* *| proc 3 | of halo elements
21136  // | |* *| |
21137  // | |* *| |
21138  // ---------------* *---------------
21139  // Proc 1 Proc 2
21140 
21141  // Processor 1: The halo elements on processor 1 continue being halo ON
21142  // PROCESSOR 1, but now WITH PROCESSOR 3
21143 
21144  // Processor 2: The halo elements on processor 2 continue being
21145  // halo BUT now ON PROCESSOR 3 WITH PROCESSOR 1
21146 
21147  // The current processor (my_rank) also needs to consider the halo
21148  // elements that will be halo elements of other processor with
21149  // another processor. The case of processor 2
21150 
21151  // Loop over all the halo elements in the current processor and
21152  // check if they will be halo with the "iproc" processor
21153  for (unsigned jproc = 0; jproc < nproc; jproc++)
21154  {
21155  // There are no halo elements with myself (the old halo elements
21156  // were halo in the "my_rank" processor)
21157  if (jproc != my_rank)
21158  {
21159  // Get the number of halo elements with the "jproc" processor
21160  const unsigned n_halo_ele_jproc = this->nroot_halo_element(jproc);
21161  // Get the halo elements with the "jproc" processor
21162  Vector<GeneralisedElement*> halo_element_pt_jproc =
21163  this->root_halo_element_pt(jproc);
21164  // ... and check if any of those elements is a new halo
21165  // element with the "iproc" processor
21166  for (unsigned jh = 0; jh < n_halo_ele_jproc; jh++)
21167  {
21168  // Get the new domain for the halo element
21169  const unsigned ele_domain = new_domains_halo_elements[jproc][jh];
21170 
21171  // If the current element is not associated to the "iproc"
21172  // processor then it could be a halo element on "iproc" with
21173  // "ele_domain".
21174 
21175  // NOTE OUTDATE: Check if the halo element is going to be
21176  // sent to this processor (my_rank), if that is the case
21177  // then we don't need to add it to the set of new halo
21178  // elements with any other processor since any possible
21179  // shared boundary will be created when checking for the
21180  // intersection of the sent and received elements
21181 
21182  // if (ele_domain != iproc && ele_domain != my_rank)
21183 
21184  // NOTE UPDATE: Only check if the halo element is not going
21185  // to be part of the iproc processor, not required to avoid
21186  // those halo elements whose domain is the current rank
21187  // (my_rank). When the shared boundaries are computed, these
21188  // last elements can not create a shared boundary since no
21189  // haloed elements (that shared an edge) are found for
21190  // them. By considering also those halo elements whose new
21191  // domain is the current one (commenting "ele_domain !=
21192  // my_rank") the current processor can compute shared
21193  // boundaries with the iproc processor with help of its old
21194  // halo elements but that will become nonhalo elements, in
21195  // fact they will become haloed elements The halo element is
21196  // not sent to the "element_domain" processor and is not
21197  // passed to the array used to create the new shared
21198  // boundaries "new_shared_boundary_element_pt" because of
21199  // its halo condition
21200  if (ele_domain != iproc)
21201  {
21202  // Get the finite element
21203  FiniteElement* ele_pt =
21204  dynamic_cast<FiniteElement*>(halo_element_pt_jproc[jh]);
21205  // Get the number of nodes on the halo element
21206  const unsigned nnodes = ele_pt->nnode();
21207  // Loop over the nodes
21208  for (unsigned j = 0; j < nnodes; j++)
21209  {
21210  // Get each node of the halo element
21211  Node* node_pt = ele_pt->node_pt(j);
21212 
21213  // Check if the node is associated with the "iproc"
21214  // processor
21215  std::set<unsigned>::iterator it =
21216  processors_associated_with_data_before_load_balance[node_pt]
21217  .find(iproc);
21218  // If it is found then the element is a halo-element
21219  if (it !=
21220  processors_associated_with_data_before_load_balance[node_pt]
21221  .end())
21222  {
21223  // Add the element as new local-halo element with
21224  // the "ele_domain" processor. The non-halo
21225  // counterpart will be located on "ele_domain"
21226  // processor. Because this is a old-halo element it
21227  // will not be sent to the "element_domain" processor
21228  if (!new_local_halo_already_added[ele_domain][ele_pt])
21229  {
21230  // The element is a halo element on "iproc" with
21231  // "ele_domain"
21232  new_local_halo_element_pt[iproc][ele_domain].push_back(
21233  ele_pt);
21234  new_local_halo_already_added[ele_domain][ele_pt] = true;
21235 
21236  // Break the for of the nodes, the element has been
21237  // already added to the new_local_halo_element_pt
21238  // structure
21239  break;
21240 
21241  } // if (!new_local_halo_already_added[ele_domain][ele_pt])
21242 
21243  } // One of the nodes lies on an element belonging to
21244  // "iproc" processor
21245 
21246  } // for (j < nnodes)
21247 
21248  } // if (ele_domain != iproc)
21249 
21250  } // for (jh < n_halo_ele_jproc)
21251 
21252  } // if (jproc != my_rank) // The old halo elements are halo
21253  // with other processors except with "my_rank"
21254 
21255  } // for (jproc < nproc): This is the one that goes for the halo
21256  // elements in the current processor to find the new halo
21257  // elements
21258 
21259  } // for (iproc < nproc)
21260 
21261  // Get the time to compute new local halo elements within all
21262  // processors
21263  if (Print_timings_level_load_balance > 1)
21264  {
21265  oomph_info
21266  << "CPU for computing new local halo elements (load balance) [4]: "
21267  << TimingHelpers::timer() - tt_start_compute_new_local_halo_elements
21268  << std::endl;
21269  }
21270 
21271  // =====================================================================
21272  // END: COMPUTE THE NEW LOCAL HALO ELEMENTS OF ALL PROCESSORS IN THE
21273  // CURRENT PROCESSOR
21274  // ----- FOR NONHALO ELEMENTS AND FOR HALO ELEMENTS
21275  // =====================================================================
21276 
21277  // =====================================================================
21278  // BEGIN: COMPUTE THE NEW LOCAL SHARED BOUNDARY ELEMENTS AND THE
21279  // FACE ELEMENTS. THE SUBSET OF THE ELEMENTS TO SENT THAT ARE PART
21280  // OF THE NEW LOCAL SHARED BOUNDARY ELEMENTS ARE IDENTIFIED TO BE
21281  // MARKED AS HALOED ELEMENTS AND BELONGING TO THE SHARED BOUNDARY
21282  // ELEMENTS IN THE RECEIVED PROCESSOR
21283  // =====================================================================
21284 
21285  // Get the time to compute new local shared boundary elements
21286  double tt_start_compute_new_local_shd_bnd_ele = 0.0;
21287  if (Print_timings_level_load_balance > 1)
21288  {
21289  tt_start_compute_new_local_shd_bnd_ele = TimingHelpers::timer();
21290  }
21291 
21292  // Store the new local-shared boundary elements and the face indexes
21293  // The halo elements and halo face indexes
21294  Vector<Vector<Vector<FiniteElement*>>>
21295  new_local_halo_shared_boundary_element_pt(nproc);
21296  Vector<Vector<Vector<unsigned>>>
21297  new_local_halo_shared_boundary_element_face_index(nproc);
21298 
21299  // Allocate enough memory for the containers
21300  for (unsigned iproc = 0; iproc < nproc; iproc++)
21301  {
21302  new_local_halo_shared_boundary_element_pt[iproc].resize(nproc);
21303  new_local_halo_shared_boundary_element_face_index[iproc].resize(nproc);
21304  } // for (iproc < nproc)
21305 
21306  // Get the elements that create the new local-halo-shared
21307  // boundaries, mark them and identify the face that lies on the
21308  // shared boundary. The new local-halo-shared boundary elements are
21309  // actually a sub-set of the halo elements of each processor with in
21310  // each processor
21311  for (unsigned iproc = 0; iproc < nproc; iproc++)
21312  {
21313  // Star from jproc = iproc + 1 to avoid double creation of shared
21314  // boundary elements, any shared boundary element identified
21315  // between processor "iproc" and "jproc" is also established as
21316  // shared boundary element between processor "jproc" and "iproc"
21317  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
21318  {
21319  this->get_shared_boundary_elements_and_face_indexes(
21320  new_local_halo_element_pt[iproc][jproc],
21321  new_local_halo_element_pt[jproc][iproc],
21322  new_local_halo_shared_boundary_element_pt[iproc][jproc],
21323  new_local_halo_shared_boundary_element_face_index[iproc][jproc],
21324  new_local_halo_shared_boundary_element_pt[jproc][iproc],
21325  new_local_halo_shared_boundary_element_face_index[jproc][iproc]);
21326  } // for (jproc < nproc)
21327  } // for (iproc < nproc)
21328 
21329  // The time to compute new local shared boundary elements
21330  if (Print_timings_level_load_balance > 1)
21331  {
21332  oomph_info << "CPU for computing new local shared boundary elements "
21333  "(load balance) [5]: "
21334  << TimingHelpers::timer() -
21335  tt_start_compute_new_local_shd_bnd_ele
21336  << std::endl;
21337  }
21338 
21339  // =====================================================================
21340  // END: COMPUTE THE NEW LOCAL SHARED BOUNDARY ELEMENTS AND THE FACE
21341  // ELEMENTS. THE SUBSET OF THE ELEMENTS TO SENT THAT ARE PART OF THE
21342  // NEW LOCAL SHARED BOUNDARY ELEMENTS ARE IDENTIFIED TO BE MARKED AS
21343  // HALOED ELEMENTS AND BELONGING TO THE SHARED BOUNDARY ELEMENTS IN
21344  // THE RECEIVED PROCESSOR
21345  // =====================================================================
21346 
21347  // =====================================================================
21348  // BEGIN: SEND THE ELEMENTS AND IDENTIFY THOSE THAT ARE PART OF THE
21349  // SHARED BOUNDARIES AND HALOED WITH OTHER PROCESSORS
21350  // =====================================================================
21351 
21352  // Get the time to send the elements to their new processor in
21353  // charge
21354  double tt_start_send_elements_to_other_processors = 0.0;
21355  if (Print_timings_level_load_balance > 1)
21356  {
21357  tt_start_send_elements_to_other_processors = TimingHelpers::timer();
21358  }
21359 
21360  // Sort the nodes on shared boundaries so that they have the same
21361  // order on all the shared boundaries, this is required to know the
21362  // possible shared nodes among processors
21363  this->sort_nodes_on_shared_boundaries();
21364 
21365  // Store the received elements from each processor
21366  Vector<Vector<FiniteElement*>> received_elements_pt(nproc);
21367 
21368  // The haloed elements and haloed face indexes, these store the
21369  // haloed elements received from "iproc" but that are haloed with
21370  // "jproc". The elements are received from "iproc" which was the
21371  // processor that computed the haloed relation of the "my_rank"
21372  // processor with "jproc"
21373  Vector<Vector<Vector<FiniteElement*>>>
21374  new_received_haloed_shared_boundary_element_pt(nproc);
21375  Vector<Vector<Vector<unsigned>>>
21376  new_received_haloed_shared_boundary_element_face_index(nproc);
21377 
21378  // Container where to store the nodes on shared boundaries not
21379  // associated with the processor that receives the elements/nodes
21380  // other_proc_shd_bnd_node_pt[iproc][jproc][shd_bnd_id][index]
21381  Vector<Vector<Vector<std::map<unsigned, Node*>>>>
21382  other_proc_shd_bnd_node_pt(nproc);
21383  // Resize the container
21384  for (unsigned iproc = 0; iproc < nproc; iproc++)
21385  {
21386  // Resize the container
21387  other_proc_shd_bnd_node_pt[iproc].resize(nproc);
21388  for (unsigned jproc = 0; jproc < nproc; jproc++)
21389  {
21390  // Get the number of shared boundaries (OLD shared boundaries)
21391  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
21392  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
21393  const unsigned n_shared_bound = final_shd_bnd_id - initial_shd_bnd_id;
21394  other_proc_shd_bnd_node_pt[iproc][jproc].resize(n_shared_bound);
21395  } // for (jproc < nproc)
21396 
21397  } // for (iproc < nproc)
21398 
21399  // Store the global node names
21400  // global_node_name[x][ ][ ] Global node number
21401  // global_node_name[ ][x][ ] Global node names
21402  // global_node_name[ ][ ][x] Global node info.
21403  Vector<Vector<Vector<unsigned>>> global_node_names;
21404 
21405  // Creates a map between the node name and the index of the global
21406  // node so we can access all its node names
21407  std::map<Vector<unsigned>, unsigned> node_name_to_global_index;
21408 
21409  // Store the global shared nodes pointers
21410  Vector<Node*> global_shared_node_pt;
21411 
21412  // Compute all the names of the nodes and fill in the
21413  // "other_proc_shd_bnd_node_pt" structure with the nodes that live
21414  // on this processor (my_rank) by looking over all their names
21415  compute_global_node_names_and_shared_nodes(other_proc_shd_bnd_node_pt,
21416  global_node_names,
21417  node_name_to_global_index,
21418  global_shared_node_pt);
21419 
21420  // From the elements received from each processor, store the haloed
21421  // information of the element, it means, the processor with which it
21422  // is haloed and the haloed index with that processor
21423  Vector<Vector<std::map<unsigned, FiniteElement*>>>
21424  received_old_haloed_element_pt(nproc);
21425  // [x][][] : The receiver processor (the original processor)
21426  // [][x][] : The processor with which the receiver processor has
21427  // haloed elements
21428  // [][][x]: The haloed element number
21429 
21430  // Resize the container
21431  for (unsigned iproc = 0; iproc < nproc; iproc++)
21432  {
21433  received_old_haloed_element_pt[iproc].resize(nproc);
21434  } // for (iproc < nproc)
21435 
21436  // Go through all processors and send the corresponding elements to
21437  // each one
21438  for (unsigned iproc = 0; iproc < nproc; iproc++)
21439  {
21440  if (iproc != my_rank)
21441  {
21442  // -----------------------------------------------------------
21443  // Send (package) information of the elements
21444  // -----------------------------------------------------------
21445 
21446  // Keep track of the currently sent elements
21447  Vector<FiniteElement*> currently_sent_elements;
21448  // Keep track of the currently sent nodes to the iproc processor
21449  Vector<Node*> currently_sent_nodes;
21450 
21451  // Clear send and receive buffers
21452  Flat_packed_unsigneds.clear();
21453  Flat_packed_doubles.clear();
21454 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21455  Flat_packed_unsigneds_string.clear();
21456 #endif
21457 
21458  // Get the number of elements to send to iproc processor
21459  const unsigned nelements_to_send = elements_to_send_pt[iproc].size();
21460 
21461  // The very first data of the flat package sent to processor
21462  // iproc is the number of elements that will be sent, this data
21463  // is used by the receiver processor to loop over the number of
21464  // expected elements to receive
21465  Flat_packed_unsigneds.push_back(nelements_to_send);
21466 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21467  std::stringstream junk;
21468  junk << "Number of elements to send from processor " << my_rank
21469  << " to processor " << iproc << ": (" << nelements_to_send << ")";
21470  Flat_packed_unsigneds_string.push_back(junk.str());
21471 #endif
21472 
21473  // Loop over the elements to sent
21474  for (unsigned e = 0; e < nelements_to_send; e++)
21475  {
21476  // Get the element to send
21477  FiniteElement* send_ele_pt = elements_to_send_pt[iproc][e];
21478 
21479  // Get the current number of sent elements
21480  const unsigned ncurrently_sent_elements =
21481  currently_sent_elements.size();
21482 
21483  // Try to add the element
21484  const unsigned index_ele = try_to_add_element_pt_load_balance(
21485  currently_sent_elements, send_ele_pt);
21486 
21487  // Element needs to be added
21488  if (index_ele == ncurrently_sent_elements)
21489  {
21490  Flat_packed_unsigneds.push_back(1);
21491 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21492  Flat_packed_unsigneds_string.push_back(
21493  "Element needs to be constructed");
21494 #endif
21495 
21496  // Get required info. related with the element
21497  get_required_elemental_information_load_balance_helper(
21498  iproc, f_haloed_element_pt, send_ele_pt);
21499 
21500  // Get the number of nodes in the element
21501  const unsigned nnodes = send_ele_pt->nnode();
21502 
21503  // Loop over the nodes in the element
21504  for (unsigned j = 0; j < nnodes; j++)
21505  {
21506  Node* node_pt = send_ele_pt->node_pt(j);
21507 
21508  // Package the info. of the nodes
21509  add_node_load_balance_helper(iproc, // The destination process
21510  f_halo_element_pt,
21511  currently_sent_nodes,
21512  node_pt);
21513 
21514  } // for (j < nnodes)
21515 
21516  } // if (index_ele == ncurrently_sent_elements)
21517  else
21518  {
21519  Flat_packed_unsigneds.push_back(0);
21520 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21521  Flat_packed_unsigneds_string.push_back("Element already exists");
21522 #endif
21523  Flat_packed_unsigneds.push_back(index_ele);
21524 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21525  Flat_packed_unsigneds_string.push_back("Index of existing element");
21526 #endif
21527  } // else if (index_ele == ncurrently_sent_elements)
21528 
21529  } // for (e < nelements_to_send)
21530 
21531  // After storing the info. of the elements identify the indexes
21532  // of the "new_local_halo_shared_boundary_elements" in the
21533  // "currently_send_elements" vector, these elements will be
21534  // identified as "new_received_haloed_shared_boundary_elements"
21535  // on the "receiver" processor
21536 
21537  // Each processor has information of every other processor so we
21538  // need to send all the corresponding info. to the other
21539  // processors. Processor 1 may have information of the relation
21540  // (halo elements) between processor 3 and 4 say, so processor 1
21541  // needs to let know processor 3 and 4 what this relation is
21542  // (which are the shared-elements among these processors)
21543 
21544  for (unsigned jproc = 0; jproc < nproc; jproc++)
21545  {
21546  // Get the number of new local-halo shared boundary elements
21547  // between processor "jproc" and "iproc" (we invert the index
21548  // since we really want the haloed elements, those elements
21549  // that we have just sent)
21550  const unsigned njproc_iproc_new_local_halo_shared_boundary_ele =
21551  new_local_halo_shared_boundary_element_pt[jproc][iproc].size();
21552 
21553  // The vector with the info. of the indexes
21554  Vector<unsigned> new_local_halo_shared_boundary_ele_index;
21555 
21556  // The number of found shared boundary elements in the sent
21557  // container (only consider the nonhalo elements)
21558  unsigned nfound_new_local_halo_shared_bound_ele_index = 0;
21559  // The number of nonhalo elements in the new local halo shared
21560  // boundary elements
21561  unsigned nnon_halo_new_local_halo_shared_bound_ele = 0;
21562 
21563  // Loop over the local halo shared boundary elements between
21564  // processor jproc and iproc
21565  for (unsigned e = 0;
21566  e < njproc_iproc_new_local_halo_shared_boundary_ele;
21567  e++)
21568  {
21569  // Get the shared boundary element
21570  FiniteElement* shared_ele_pt =
21571  new_local_halo_shared_boundary_element_pt[jproc][iproc][e];
21572 
21573  // Only consider the nonhalo elements since the halo
21574  // elements were no considered for sending
21575  if (!shared_ele_pt->is_halo())
21576  {
21577  nnon_halo_new_local_halo_shared_bound_ele++;
21578 
21579  // Now find the index on the currently sent elements
21580 
21581  // Get the current number of sent elements
21582  const unsigned ncurrently_sent_elements =
21583  currently_sent_elements.size();
21584  // Loop over the sent elements
21585  for (unsigned ics = 0; ics < ncurrently_sent_elements; ics++)
21586  {
21587  FiniteElement* currently_sent_ele_pt =
21588  currently_sent_elements[ics];
21589 
21590  // Is this the element?
21591  if (currently_sent_ele_pt == shared_ele_pt)
21592  {
21593  // Store the index on the sent elements of the local
21594  // halo shared boundary element
21595  new_local_halo_shared_boundary_ele_index.push_back(ics);
21596  // Increase the number of found new local halo shared
21597  // bound element index
21598  nfound_new_local_halo_shared_bound_ele_index++;
21599  // We have found it, no need to further search
21600  break;
21601  } // if (currently_sent_ele_pt == shared_ele_pt)
21602 
21603  } // for (ics < ncurrently_sent_elements)
21604 
21605  } // if (!shared_ele_pt->is_halo())
21606 
21607  } // for (e < niproc_new_local_halo_shared_boundary_ele)
21608 
21609 #ifdef PARANOID
21610  if (nfound_new_local_halo_shared_bound_ele_index !=
21611  nnon_halo_new_local_halo_shared_bound_ele)
21612  {
21613  std::ostringstream error_message;
21614  error_message << "Was only possible to identify ("
21615  << nfound_new_local_halo_shared_bound_ele_index
21616  << ") of ("
21617  << nnon_halo_new_local_halo_shared_bound_ele
21618  << ") shared "
21619  << "elements between\nprocessor (" << iproc
21620  << ") and (" << jproc << ") "
21621  << "when sending elements to processor (" << iproc
21622  << ")\n\n";
21623  throw OomphLibError(error_message.str(),
21624  OOMPH_CURRENT_FUNCTION,
21625  OOMPH_EXCEPTION_LOCATION);
21626  }
21627 #endif
21628 
21629  // Send a flag for synchronisation issues
21630  Flat_packed_unsigneds.push_back(9999);
21631 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21632  std::stringstream junk;
21633  junk << "Flag for synchronisation 9999";
21634  Flat_packed_unsigneds_string.push_back(junk.str());
21635 #endif
21636 
21637  // Send the number of nonhalo new local-shared boundary
21638  // elements of processor "iproc" with processor "jproc"
21639  Flat_packed_unsigneds.push_back(
21640  nnon_halo_new_local_halo_shared_bound_ele);
21641 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21642  std::stringstream junk2;
21643  junk2 << "Number of new local halo shared boundary elements "
21644  << nnon_halo_new_local_halo_shared_bound_ele;
21645  Flat_packed_unsigneds_string.push_back(junk2.str());
21646 #endif
21647 
21648  // Send the indexes and the face indexes of the shared
21649  // boundary elements
21650  unsigned counter_nonhalo_sent = 0;
21651  // Loop over the local halo shared boundary elements between
21652  // processor jproc and iproc
21653  for (unsigned e = 0;
21654  e < njproc_iproc_new_local_halo_shared_boundary_ele;
21655  e++)
21656  {
21657  // Get the shared boundary element
21658  FiniteElement* shared_ele_pt =
21659  new_local_halo_shared_boundary_element_pt[jproc][iproc][e];
21660 
21661  // Only consider the nonhalo elements since the halo
21662  // elements were no considered for sending
21663  if (!shared_ele_pt->is_halo())
21664  {
21665  // Get the index on the sent elements of the current
21666  // nonhalo shared boundary element
21667  const unsigned ele_index =
21668  new_local_halo_shared_boundary_ele_index
21669  [counter_nonhalo_sent++];
21670  // ... and get the face index
21671  const unsigned face_index =
21672  new_local_halo_shared_boundary_element_face_index[jproc][iproc]
21673  [e];
21674 
21675  // Send the index on the sent elements of the new local
21676  // halo shared boundary element
21677  Flat_packed_unsigneds.push_back(ele_index);
21678 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21679  std::stringstream junk;
21680  junk << "The index of the halo shared boundary element "
21681  << ele_index;
21682  Flat_packed_unsigneds_string.push_back(junk.str());
21683 #endif
21684 
21685  // Send the face index of the new local halo shared boundary
21686  // element
21687  Flat_packed_unsigneds.push_back(face_index);
21688 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21689  std::stringstream junk2;
21690  junk2 << "The face index of the halo shared boundary element "
21691  << face_index;
21692  Flat_packed_unsigneds_string.push_back(junk2.str());
21693 #endif
21694 
21695  } // if (!shared_ele_pt->is_halo())
21696 
21697  } // for (e < niproc_new_local_halo_shared_boundary_ele)
21698 
21699  } // for (jproc < nproc)
21700 
21701  // ----------------------------------------------------------
21702  // Send the info. perform the communications
21703  // ----------------------------------------------------------
21704  // Processor to which send the info.
21705  int send_proc = static_cast<int>(iproc);
21706  // Processor from which receive the info.
21707  int recv_proc = static_cast<int>(iproc);
21708  send_and_receive_elements_nodes_info(send_proc, recv_proc);
21709 
21710  // ----------------------------------------------------------
21711  // Receive (unpackage) the info of the elements
21712  // ----------------------------------------------------------
21713 
21714  // Keep track of the currently created elements
21715  Vector<FiniteElement*> currently_created_elements;
21716  // Keep track of the currently created nodes
21717  Vector<Node*> currently_created_nodes;
21718 
21719  // Reset the counters
21720  Counter_for_flat_packed_doubles = 0;
21721  Counter_for_flat_packed_unsigneds = 0;
21722 
21723 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21724  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
21725  << " Number of elements need to be constructed "
21726  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
21727  << std::endl;
21728 #endif
21729 
21730  // Read the number of elements that need to be created
21731  const unsigned nelements_to_create =
21732  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21733 
21734  for (unsigned e = 0; e < nelements_to_create; e++)
21735  {
21736  // Create the element from received info. of "iproc"
21737  // processor on the current processor
21738  create_element_load_balance_helper(iproc,
21739  f_haloed_element_pt,
21740  received_old_haloed_element_pt,
21741  currently_created_elements,
21742  currently_created_nodes,
21743  other_proc_shd_bnd_node_pt,
21744  global_node_names,
21745  node_name_to_global_index,
21746  global_shared_node_pt);
21747  }
21748 
21749  // Copy the received elements from "iproc" processor
21750 
21751  // Number of received elements
21752  const unsigned nreceived_elements = currently_created_elements.size();
21753  received_elements_pt[iproc].resize(nreceived_elements);
21754  for (unsigned e = 0; e < nreceived_elements; e++)
21755  {
21756  received_elements_pt[iproc][e] = currently_created_elements[e];
21757  }
21758 
21759  // Go for the haloed elements received from processor "iproc"
21760  // but haloed with "jproc"
21761 
21762  // Allocate memory for the containers
21763  new_received_haloed_shared_boundary_element_pt[iproc].resize(nproc);
21764  new_received_haloed_shared_boundary_element_face_index[iproc].resize(
21765  nproc);
21766 
21767  // Loop over the processors
21768  for (unsigned jproc = 0; jproc < nproc; jproc++)
21769  {
21770  // Read the synchronisation flag
21771  const unsigned synchronisation_flag =
21772  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21773 
21774  if (synchronisation_flag != 9999)
21775  {
21776  std::ostringstream error_message;
21777  error_message << "The synchronisation flag was not read, the\n"
21778  << "information sent between processor (" << my_rank
21779  << ") "
21780  << "and (" << iproc
21781  << ")\nis no longer synchronised\n\n";
21782  throw OomphLibError(error_message.str(),
21783  OOMPH_CURRENT_FUNCTION,
21784  OOMPH_EXCEPTION_LOCATION);
21785  }
21786 
21787  // Read the number of elements that will be part of the new
21788  // received haloed shared boundary elements received from "iproc"
21789  // and haloed with "jproc"
21790  const unsigned niproc_jproc_new_received_haloed_shared_boundary_ele =
21791  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21792 
21793  // Loop over the new received haloed shared boundary elements
21794  for (unsigned e = 0;
21795  e < niproc_jproc_new_received_haloed_shared_boundary_ele;
21796  e++)
21797  {
21798  // Read the index of the new received haloed shared boundary
21799  // ele with "jproc"
21800  const unsigned ele_index =
21801  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21802  // Read the face index for the new received haloed shared
21803  // boundary element
21804  const unsigned face_index =
21805  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21806 
21807  // Get the element
21808  FiniteElement* shared_ele_pt =
21809  currently_created_elements[ele_index];
21810 
21811  // Add the element to the new received-haloed shared
21812  // boundary elements. Received from "iproc" but haloed with
21813  // "jproc" processor
21814  new_received_haloed_shared_boundary_element_pt[iproc][jproc]
21815  .push_back(shared_ele_pt);
21816  // Store the face index
21817  new_received_haloed_shared_boundary_element_face_index[iproc][jproc]
21818  .push_back(face_index);
21819 
21820  } // for (e < niproc_jproc_read_new_local_shared_boundary_ele)
21821 
21822  } // for (jproc < nproc)
21823 
21824  } // if (iproc != my_rank)
21825 
21826  } // for (iproc < nproc)
21827 
21828  // The time to send the elements to their new processor in charge
21829  if (Print_timings_level_load_balance > 1)
21830  {
21831  oomph_info << "CPU for sending elements to their new processors (load "
21832  "balance) [6]: "
21833  << TimingHelpers::timer() -
21834  tt_start_send_elements_to_other_processors
21835  << std::endl;
21836  }
21837 
21838  // =====================================================================
21839  // END: SEND THE ELEMENTS AND IDENTIFY THOSE THAT ARE PART OF THE
21840  // SHARED BOUNDARIES AND HALOED WITH OTHER PROCESSORS
21841  // =====================================================================
21842 
21843  // =====================================================================
21844  // BEGIN: GET ANY ADDITIONAL SHARED BOUNDARY BY THE INTERSECTION OF
21845  // THE ELEMENTS SENT TO PROCESSOR "IPROC" AND THE ELEMENTS RECEIVED
21846  // FROM PROCESSOR "IPROC". IF ANY NEW SHARED BOUNDARY IS FOUND, IT
21847  // IS CREATED BY THE OLD HALO ELEMENTS (RECEIVED ELEMENTS) THAT HAVE
21848  // NOW BECOME PART OF THE DOMAIN AND THE OLD HALOED ELEMENTS (SENT
21849  // ELEMENTS)
21850  // =====================================================================
21851 
21852  // Get the time to compute any additional shared boundary
21853  double tt_start_compute_additional_shared_boundaries = 0.0;
21854  if (Print_timings_level_load_balance > 1)
21855  {
21856  tt_start_compute_additional_shared_boundaries = TimingHelpers::timer();
21857  }
21858 
21859  // Store any additional elements that may create a shared boundary,
21860  // after sending elements from one to other processor check for any
21861  // new possible shared boundaries
21862  Vector<Vector<FiniteElement*>> tmp_group1_shared_boundary_element_pt(nproc);
21863  Vector<Vector<unsigned>> tmp_group1_shared_boundary_element_face_index(
21864  nproc);
21865  Vector<Vector<FiniteElement*>> tmp_group2_shared_boundary_element_pt(nproc);
21866  Vector<Vector<unsigned>> tmp_group2_shared_boundary_element_face_index(
21867  nproc);
21868 
21869  // Compute any additional shared boundaries by checking the
21870  // intersection between the received elements from each processor
21871  // and the elements just sent to that processor, the lowest
21872  // processors number loops over its received elements and the
21873  // highest loops over its sent elements (halo elements that have
21874  // become part of the domain now can create shared boundaries with
21875  // other processor)
21876 
21877  // Note: These additional shared boundaries may be created by the
21878  // elements that previously were halo but now have become part of
21879  // the processor (the received elements), and the elements that were
21880  // previously part of the processor but now have become halo (a
21881  // subset of the sent-elements)
21882 
21883  // Then these new shared boundaries come from the intersection of
21884  // the new-haloed elements (received elements) and the new-halo
21885  // elements (sent elements). These could be computed previously (in
21886  // the computing of the local new-halo and local new-haloed elements
21887  // usign the info. of the new domains for the old halo elements),
21888  // however, it was decided to perform the computation here in order to
21889  // avoid the identification of the old halo element that was part of a
21890  // shared boundary in the set of just received elements
21891  for (unsigned iproc = 0; iproc < nproc; iproc++)
21892  {
21893  if (my_rank < iproc)
21894  {
21895  // Lowest processor loops over the received elements
21896  this->get_shared_boundary_elements_and_face_indexes(
21897  received_elements_pt[iproc],
21898  elements_to_send_pt[iproc],
21899  tmp_group1_shared_boundary_element_pt[iproc],
21900  tmp_group1_shared_boundary_element_face_index[iproc],
21901  tmp_group2_shared_boundary_element_pt[iproc],
21902  tmp_group2_shared_boundary_element_face_index[iproc]);
21903 
21904  } // if (my_rank < iproc)
21905  else if (my_rank > iproc)
21906  {
21907  // Highest processor loops over the sent elements
21908  this->get_shared_boundary_elements_and_face_indexes(
21909  elements_to_send_pt[iproc],
21910  received_elements_pt[iproc],
21911  tmp_group1_shared_boundary_element_pt[iproc],
21912  tmp_group1_shared_boundary_element_face_index[iproc],
21913  tmp_group2_shared_boundary_element_pt[iproc],
21914  tmp_group2_shared_boundary_element_face_index[iproc]);
21915 
21916  } // else if (my_rank > iproc)
21917 
21918  } // for (iproc < nproc)
21919 
21920  // The time to compute any additional shared boundary
21921  if (Print_timings_level_load_balance > 1)
21922  {
21923  oomph_info
21924  << "CPU for computing additional shared boundaries (load balance) [7]: "
21925  << TimingHelpers::timer() -
21926  tt_start_compute_additional_shared_boundaries
21927  << std::endl;
21928  }
21929 
21930  // =====================================================================
21931  // END: GET ANY ADDITIONAL SHARED BOUNDARY BY THE INTERSECTION OF
21932  // THE ELEMENTS SENT TO PROCESSOR "IPROC" AND THE ELEMENTS RECEIVED
21933  // FROM PROCESSOR "IPROC". IF ANY NEW SHARED BOUNDARY IS FOUND, IT
21934  // IS CREATED BY THE OLD HALO ELEMENTS (RECEIVED ELEMENTS) THAT HAVE
21935  // NOW BECOME PART OF THE DOMAIN AND THE OLD HALOED ELEMENTS (SENT
21936  // ELEMENTS)
21937  // =====================================================================
21938 
21939  // =====================================================================
21940  // BEGIN: SORT THE SHARED BOUNDARIES SO THAT THEY ARE CREATED IN THE
21941  // SAME ORDER IN THE INVOLVED PROCESSORS (A PAIR OF PROCESSORS)
21942  // =====================================================================
21943 
21944  // Get the time to sort shared boundaries
21945  double tt_start_sort_shared_boundaries = 0.0;
21946  if (Print_timings_level_load_balance > 1)
21947  {
21948  tt_start_sort_shared_boundaries = TimingHelpers::timer();
21949  }
21950 
21951  // Once computed the elements that create the shared boundaries,
21952  // sort them so that the shared boundaries are created at the same
21953  // order in both processors that define the shared boundary
21954 
21955  // The order is like this
21956 
21957  // Lowest processors
21958  // 1) Shared boundary elements received from processors (local in
21959  // other processors)
21960  // 2) Local shared boundary elements (do not include halo elements)
21961  // 3) Shared boundary elements by intersection (already sorted)
21962 
21963  // Highest processors
21964  // 1) Local shared boundary elements (do not include halo elements)
21965  // 2) Shared boundary elements received from processors (local in
21966  // other processors)
21967  // 3) Shared boundary elements by intersection (already sorted)
21968 
21969  Vector<Vector<FiniteElement*>> new_shared_boundary_element_pt(nproc);
21970  Vector<Vector<unsigned>> new_shared_boundary_element_face_index(nproc);
21971  for (unsigned iproc = 0; iproc < nproc; iproc++)
21972  {
21973  // Lower processor
21974  if (my_rank < iproc)
21975  {
21976  // Copy the elements received from processor "jproc" but that
21977  // are haloed with "iproc" processor
21978  for (unsigned jproc = 0; jproc < nproc; jproc++)
21979  {
21980  // Can not receive elements from itself
21981  if (jproc != my_rank)
21982  {
21983  // Get the number of elements to copy from received processors
21984  const unsigned nrecvd_haloed_shared_bound_ele_jproc_iproc =
21985  new_received_haloed_shared_boundary_element_pt[jproc][iproc]
21986  .size();
21987  for (unsigned e = 0; e < nrecvd_haloed_shared_bound_ele_jproc_iproc;
21988  e++)
21989  {
21990  // Get the element
21991  FiniteElement* ele_pt =
21992  new_received_haloed_shared_boundary_element_pt[jproc][iproc][e];
21993  // Get the face index
21994  const unsigned face_index =
21995  new_received_haloed_shared_boundary_element_face_index[jproc]
21996  [iproc]
21997  [e];
21998 
21999  // Add the elements to the containers
22000  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
22001  new_shared_boundary_element_face_index[iproc].push_back(
22002  face_index);
22003 
22004  } // for (e < nrecvd_haloed_shared_bound_ele_iproc_jproc)
22005 
22006  } // if (jproc != my_rank)
22007 
22008  } // for (jproc < nproc)
22009 
22010  // Then the local shared haloed (invert the indexes to get the
22011  // haloed elements)
22012  const unsigned nlocal_haloed_shared_bound_ele_iproc_my_rank =
22013  new_local_halo_shared_boundary_element_pt[iproc][my_rank].size();
22014  for (unsigned e = 0; e < nlocal_haloed_shared_bound_ele_iproc_my_rank;
22015  e++)
22016  {
22017  // Get the element
22018  FiniteElement* ele_pt =
22019  new_local_halo_shared_boundary_element_pt[iproc][my_rank][e];
22020  // Get the face index
22021  const unsigned face_index =
22022  new_local_halo_shared_boundary_element_face_index[iproc][my_rank]
22023  [e];
22024 
22025  // Only include the element if it is nonhalo (this may be an
22026  // old halo element that helped to indentify a shared boundary
22027  // with iproc)
22028  if (!ele_pt->is_halo())
22029  {
22030  // Add the elements to the containers
22031  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
22032  new_shared_boundary_element_face_index[iproc].push_back(face_index);
22033  } // if (!ele_pt->is_halo())
22034 
22035  } // for (e < nlocal_haloed_shared_bound_ele_iproc_my_rank)
22036 
22037  // ... and finally any additional shared boundary elements from
22038  // tmp_group1
22039  const unsigned ntmp_group1_shared_bound_ele_iproc =
22040  tmp_group1_shared_boundary_element_pt[iproc].size();
22041  for (unsigned e = 0; e < ntmp_group1_shared_bound_ele_iproc; e++)
22042  {
22043  // Get the element
22044  FiniteElement* ele_pt =
22045  tmp_group1_shared_boundary_element_pt[iproc][e];
22046  // Get the face index
22047  const unsigned face_index =
22048  tmp_group1_shared_boundary_element_face_index[iproc][e];
22049 
22050  // Add the elements to the containers
22051  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
22052  new_shared_boundary_element_face_index[iproc].push_back(face_index);
22053 
22054  } // for (e < ntmp_group1_shared_bound_ele_iproc)
22055 
22056  } // if (my_rank < iproc)
22057  // Highest processor
22058  else if (my_rank > iproc)
22059  {
22060  // Get the haloed elements first and then the elements received
22061  // from processor "jproc" but that are haloed with "iproc"
22062  // processor
22063 
22064  // Get the number of elements to copy from local elements
22065  // (invert the indexes to get the haloed elements)
22066  const unsigned nlocal_haloed_shared_bound_ele_iproc_my_rank =
22067  new_local_halo_shared_boundary_element_pt[iproc][my_rank].size();
22068  for (unsigned e = 0; e < nlocal_haloed_shared_bound_ele_iproc_my_rank;
22069  e++)
22070  {
22071  // Get the element
22072  FiniteElement* ele_pt =
22073  new_local_halo_shared_boundary_element_pt[iproc][my_rank][e];
22074  // Get the face index
22075  const unsigned face_index =
22076  new_local_halo_shared_boundary_element_face_index[iproc][my_rank]
22077  [e];
22078 
22079  // Only include the element if it is nonhalo (this may be an
22080  // old halo element that helped to indentify a shared boundary
22081  // with iproc)
22082  if (!ele_pt->is_halo())
22083  {
22084  // Add the elements to the containers
22085  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
22086  new_shared_boundary_element_face_index[iproc].push_back(face_index);
22087  } // if (!ele_pt->is_halo())
22088 
22089  } // for (e < nlocal_haloed_shared_bound_ele_iproc_my_rank)
22090 
22091  for (unsigned jproc = 0; jproc < nproc; jproc++)
22092  {
22093  // Can not receive elements from itself
22094  if (jproc != my_rank)
22095  {
22096  // Then the received shared elements from "jproc" but haloed
22097  // with "iproc"
22098  const unsigned nrecvd_haloed_shared_bound_ele_jproc_iproc =
22099  new_received_haloed_shared_boundary_element_pt[jproc][iproc]
22100  .size();
22101  for (unsigned e = 0; e < nrecvd_haloed_shared_bound_ele_jproc_iproc;
22102  e++)
22103  {
22104  // Get the element
22105  FiniteElement* ele_pt =
22106  new_received_haloed_shared_boundary_element_pt[jproc][iproc][e];
22107  // Get the face index
22108  const unsigned face_index =
22109  new_received_haloed_shared_boundary_element_face_index[jproc]
22110  [iproc]
22111  [e];
22112 
22113  // Add the elements to the containers
22114  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
22115  new_shared_boundary_element_face_index[iproc].push_back(
22116  face_index);
22117 
22118  } // for (e < nrecvd_haloed_shared_bound_ele_iproc)
22119 
22120  } // if (jproc != my_rank)
22121 
22122  } // for (jproc < nproc)
22123 
22124  // ... and finally any additional shared boundary elements from
22125  // tmp_group2
22126  const unsigned ntmp_group2_shared_bound_ele_iproc =
22127  tmp_group2_shared_boundary_element_pt[iproc].size();
22128  for (unsigned e = 0; e < ntmp_group2_shared_bound_ele_iproc; e++)
22129  {
22130  // Get the element
22131  FiniteElement* ele_pt =
22132  tmp_group2_shared_boundary_element_pt[iproc][e];
22133  // Get the face index
22134  const unsigned face_index =
22135  tmp_group2_shared_boundary_element_face_index[iproc][e];
22136 
22137  // Add the elements to the containers
22138  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
22139  new_shared_boundary_element_face_index[iproc].push_back(face_index);
22140 
22141  } // for (e < ntmp_group2_shared_bound_ele_iproc)
22142 
22143  } // else if (my_rank > iproc)
22144 
22145  } // for (iproc < nproc)
22146 
22147  // The time to sort shared boundaries
22148  if (Print_timings_level_load_balance > 1)
22149  {
22150  oomph_info << "CPU for sorting shared boundaries (load balance) [8]: "
22151  << TimingHelpers::timer() - tt_start_sort_shared_boundaries
22152  << std::endl;
22153  }
22154 
22155  // =====================================================================
22156  // END: SORT THE SHARED BOUNDARIES SO THAT THEY ARE CREATED IN THE
22157  // SAME ORDER IN THE INVOLVED PROCESSORS (A PAIR OF PROCESSORS)
22158  // =====================================================================
22159 
22160  // =====================================================================
22161  // BEGIN: CREATE THE NEW SHARED BOUNDARIES. BEFORE THE GENERATION OF
22162  // THE SHARED BOUNDARIES PUT IN A CONTAINER THOSE NONHALO ELEMENTS
22163  // THAT WILL REMAIN IN THE CURRENT PROCESSOR (BECAUSE THEIR RANK IS
22164  // THE SAME AS THE CURRENT PROCESSOR), AND THOSE ELEMENTS RECEIVED
22165  // FROM OTHER PROCESSORS. THESE SET OF ELEMENTS WILL BE USED TO
22166  // CHECK FOR POSSIBLE CONNECTIONS OF THE NEW SHARED BOUNDARIES WITH
22167  // THE ORIGINAL BOUNDARIES
22168  // =====================================================================
22169  // Finally, create the new shared boundaries
22170 
22171  // Get the time to create the new shared boundaries
22172  double tt_start_create_new_shared_boundaries = 0.0;
22173  if (Print_timings_level_load_balance > 1)
22174  {
22175  tt_start_create_new_shared_boundaries = TimingHelpers::timer();
22176  }
22177 
22178  // Compute the elements that will remain after deletion in the
22179  // curent processor. This is required to check if the new shared
22180  // boundaries crete a connection with any node of the elements in
22181  // the boundaries
22182 
22183  // Try to use as much information as possible
22184 
22185  // Storage for the elements in the processor
22186  std::set<FiniteElement*> element_in_processor_pt;
22187 
22188  // Loop over the old elements, those before sending/received
22189  // elements to/from other processors
22190  unsigned nh_count6 = 0;
22191  for (unsigned e = 0; e < nelement_before_load_balance; e++)
22192  {
22193  // Get the element
22194  FiniteElement* ele_pt = backed_up_ele_pt[e];
22195  // Only work with nonhalo elements
22196  if (!(ele_pt->is_halo()))
22197  {
22198  // Is the element part of the new domain
22199  if (target_domain_for_local_non_halo_element[nh_count6++] == my_rank)
22200  {
22201  // Add the element to the set of elements in the processor
22202  element_in_processor_pt.insert(ele_pt);
22203  }
22204 
22205  } // if (!(ele_pt->is_halo()))
22206 
22207  } // for (e < nelement_before_load_balance)
22208 
22209  // Now include the received elements from the other processors
22210  // Loop over the processors
22211  for (unsigned iproc = 0; iproc < nproc; iproc++)
22212  {
22213  // No elements received from myself
22214  if (iproc != my_rank)
22215  {
22216  // Get the number of received elements with the "iproc"
22217  // processor
22218  const unsigned n_received_ele = received_elements_pt[iproc].size();
22219  for (unsigned ie = 0; ie < n_received_ele; ie++)
22220  {
22221  // Get the ie-th received element from processor iproc
22222  FiniteElement* ele_pt = received_elements_pt[iproc][ie];
22223 
22224  // Include it in the set of elements in the processor
22225  element_in_processor_pt.insert(ele_pt);
22226 
22227  } // for (ie < nreceived_ele)
22228 
22229  } // if (iproc != my_rank)
22230 
22231  } // for (iproc < nproc)
22232 
22233  // Now create the shared boundaries
22234  create_new_shared_boundaries(element_in_processor_pt,
22235  new_shared_boundary_element_pt,
22236  new_shared_boundary_element_face_index);
22237 
22238  // The time to create the new shared boundaries
22239  if (Print_timings_level_load_balance > 1)
22240  {
22241  oomph_info
22242  << "CPU for creating new shared boundaries (load balance) [9]: "
22243  << TimingHelpers::timer() - tt_start_create_new_shared_boundaries
22244  << std::endl;
22245  }
22246 
22247  // =====================================================================
22248  // END: CREATE THE NEW SHARED BOUNDARIES. BEFORE THE GENERATION OF
22249  // THE SHARED BOUNDARIES PUT IN A CONTAINER THOSE NONHALO ELEMENTS
22250  // THAT WILL REMAIN IN THE CURRENT PROCESSOR (BECAUSE THEIR RANK IS
22251  // THE SAME AS THE CURRENT PROCESSOR), AND THOSE ELEMENTS RECEIVED
22252  // FROM OTHER PROCESSORS. THESE SET OF ELEMENTS WILL BE USED TO
22253  // CHECK FOR POSSIBLE CONNECTIONS OF THE NEW SHARED BOUNDARIES WITH
22254  // THE ORIGINAL BOUNDARIES
22255  // =====================================================================
22256 
22257  // =====================================================================
22258  // BEGIN: DELETE THE ELEMENTS NO LONGER BELONGING TO THE DOMAIN,
22259  // INCLUDING HALO ELEMENTS. ADD THE KEPT ELEMENTS TO THE MESH AND
22260  // THE RECEIVED ELEMENTS FROM OTHER PROCESSORS
22261  // =====================================================================
22262 
22263  // Get the time to delete elements no longer belonging to the
22264  // processor
22265  double tt_start_delete_elements = 0.0;
22266  if (Print_timings_level_load_balance > 1)
22267  {
22268  tt_start_delete_elements = TimingHelpers::timer();
22269  }
22270 
22271  // Once computed the new shared boundaries delete the elements that
22272  // no longer belong to the processor (including the old halo
22273  // elements)
22274 
22275  // The procedure is similar to the one performed at the distribution
22276  // stage (src/generic/mesh.cc -- distribute() method)
22277 
22278  // Clean the storage for halo(ed) elements/nodes
22279  this->Halo_node_pt.clear();
22280  this->Root_halo_element_pt.clear();
22281 
22282  this->Haloed_node_pt.clear();
22283  this->Root_haloed_element_pt.clear();
22284 
22285  // Mark all the nodes as obsolete
22286  const unsigned nnodes = this->nnode();
22287  for (unsigned j = 0; j < nnodes; j++)
22288  {
22289  this->node_pt(j)->set_obsolete();
22290  }
22291 
22292  // Flush the mesh storage
22293  this->flush_element_storage();
22294 
22295  // Delete any storage of external elements and nodes
22296  this->delete_all_external_storage();
22297 
22298  // Clear external storage
22299  this->External_halo_node_pt.clear();
22300  this->External_halo_element_pt.clear();
22301 
22302  this->External_haloed_node_pt.clear();
22303  this->External_haloed_element_pt.clear();
22304 
22305  // Keep track of the deleted elements
22306  Vector<FiniteElement*> deleted_elements;
22307 
22308  // Delete the elements that no longer belong to the processor
22309  unsigned nh_count7 = 0;
22310  for (unsigned e = 0; e < nelement_before_load_balance; e++)
22311  {
22312  FiniteElement* ele_pt = backed_up_ele_pt[e];
22313  // Only work with nonhalo elements
22314  if (!(ele_pt->is_halo()))
22315  {
22316  if (target_domain_for_local_non_halo_element[nh_count7++] == my_rank)
22317  {
22318  // Add the element to the mesh
22319  this->add_element_pt(ele_pt);
22320  // Get the number of nodes on the element
22321  const unsigned nele_nodes = ele_pt->nnode();
22322  // Loop over the nodes of the element
22323  for (unsigned j = 0; j < nele_nodes; j++)
22324  {
22325  // Mark the node as non-obsolete
22326  ele_pt->node_pt(j)->set_non_obsolete();
22327  } // for (j < nele_nodes)
22328 
22329  } // The element belongs to the domain
22330  else
22331  {
22332  // Delete the element, but keep track of it
22333  deleted_elements.push_back(ele_pt);
22334  // Delete and point to null
22335  delete ele_pt;
22336  ele_pt = 0;
22337  }
22338 
22339  } // if (!(ele_pt->is_halo()))
22340  else
22341  {
22342  // If the element is halo, delete if but keep track of it
22343  deleted_elements.push_back(ele_pt);
22344  // Delete and point to null
22345  delete ele_pt;
22346  ele_pt = 0;
22347  }
22348 
22349  } // for (e < nelement_before_load_balance)
22350 
22351  // Now add the received elements from each processor
22352  for (unsigned iproc = 0; iproc < nproc; iproc++)
22353  {
22354  if (iproc != my_rank)
22355  {
22356  // Get the number of received elements with the "iproc"
22357  // processor
22358  const unsigned nreceived_ele = received_elements_pt[iproc].size();
22359  for (unsigned ie = 0; ie < nreceived_ele; ie++)
22360  {
22361  // Get the element and add it to the mesh
22362  FiniteElement* ele_pt = received_elements_pt[iproc][ie];
22363  // Add the element to the mesh
22364  this->add_element_pt(ele_pt);
22365  // Get the number of nodes on the element
22366  const unsigned nele_nodes = ele_pt->nnode();
22367  // Loop over the nodes of the element
22368  for (unsigned j = 0; j < nele_nodes; j++)
22369  {
22370  // Mark the node as non-obsolete
22371  ele_pt->node_pt(j)->set_non_obsolete();
22372  } // for (j < nele_nodes)
22373 
22374  } // for (ie < nreceived_ele)
22375 
22376  } // if (iproc != my_rank)
22377 
22378  } // for (iproc < nproc)
22379 
22380  // Now remove the obsolete nodes
22381  this->prune_dead_nodes();
22382 
22383  // The time to delete elements no longer belonging to the processor
22384  if (Print_timings_level_load_balance > 1)
22385  {
22386  oomph_info << "CPU for deleting elements no longer belonging to this "
22387  "processor (load balance) [10]: "
22388  << TimingHelpers::timer() - tt_start_delete_elements
22389  << std::endl;
22390  }
22391 
22392  // =====================================================================
22393  // END: DELETE THE ELEMENTS NO LONGER BELONGING TO THE DOMAIN,
22394  // INCLUDING HALO ELEMENTS. ADD THE KEPT ELEMENTS TO THE MESH AND
22395  // THE RECEIVED ELEMENTS FROM OTHER PROCESSORS
22396  // =====================================================================
22397 
22398  // =====================================================================
22399  // BEGIN: REESTABLISH THE HALO(ED) SCHEME, ATTACH HALO ELEMENTS
22400  // (HALO NODES INCLUDED) TO THE NEW MESH (AFTER LOAD BALANCING)
22401  // RESTORE THE BOUNDARY ELEMENTS SCHEME AND THE NUMBER OF SEGMENTS
22402  // ON EACH BOUNDARY
22403  // =====================================================================
22404 
22405  // Get the time to re-establish the halo(ed) information
22406  double tt_start_re_etablish_halo_ed_info = 0.0;
22407  if (Print_timings_level_load_balance > 1)
22408  {
22409  tt_start_re_etablish_halo_ed_info = TimingHelpers::timer();
22410  }
22411 
22412  // Prepare the data to re-establish the halo(ed) scheme
22413 
22414  // Sort the nodes on the new shared boundaries so that they have the
22415  // same order on all processors
22416  this->sort_nodes_on_shared_boundaries();
22417 
22418  // Before re-establish the halo and haloed elements save the number
22419  // of current elements in the boundaries, this will be useful to
22420  // re-establish the boundary elements. Notice that there may be
22421  // boundary elements with null pointers, since the element may no
22422  // longer belong to the current processor
22423  const unsigned tmp_nboundary = this->nboundary();
22424  Vector<unsigned> ntmp_boundary_elements(tmp_nboundary);
22425 
22426  // If there are regions, save the number of boundary-region elements
22427  Vector<Vector<unsigned>> ntmp_boundary_elements_in_region(tmp_nboundary);
22428  // Are there regions?
22429  const unsigned n_regions = this->nregion();
22430 
22431  // Loop over the boundaries
22432  for (unsigned ib = 0; ib < tmp_nboundary; ib++)
22433  {
22434  // Get the number of boundary elements
22435  ntmp_boundary_elements[ib] = this->nboundary_element(ib);
22436 
22437  // Resize the container
22438  ntmp_boundary_elements_in_region[ib].resize(n_regions);
22439 
22440  // Loop over the regions
22441  for (unsigned rr = 0; rr < n_regions; rr++)
22442  {
22443  // Get the region id
22444  const unsigned region_id =
22445  static_cast<unsigned>(this->region_attribute(rr));
22446 
22447  // Store the number of element in the region (notice we are
22448  // using the region index not the region id to refer to the
22449  // region)
22450  ntmp_boundary_elements_in_region[ib][rr] =
22451  this->nboundary_element_in_region(ib, region_id);
22452 
22453  } // for (rr < n_regions)
22454 
22455  } // for (ib < tmp_nboundary)
22456 
22457  // Re-establish the halo(ed) scheme
22458  this->reset_halo_haloed_scheme();
22459 
22460  // Get the number of elements in the mesh after load balance
22461  const unsigned nelement_after_load_balance = this->nelement();
22462 
22463  // We need to reset boundary elements because we need to get rid of
22464  // the old boundary elements and stay only with the new ones
22465  this->reset_boundary_element_info(ntmp_boundary_elements,
22466  ntmp_boundary_elements_in_region,
22467  deleted_elements);
22468 
22469  // There is no need to re-set boundary coordinates since the
22470  // load-balanced mesh already has the correct information (the
22471  // boundary coordinate for each node was sent with the node
22472  // information)
22473 
22474  // We need to re-compute the number of segments on each boundary
22475  // after load balance. It may be possible that the boundary is now
22476  // split in more segments, or that previous gaps between the
22477  // segments have now dissapeared because the received elements
22478  // filled those gaps
22479 
22480  // In order to re-set the number of segments it is required to get
22481  // the face elements, attach them to create a contiguous
22482  // representation of the boundary (in segments possibly) and then
22483  // counter the number of segments. This can only be done after
22484  // restoring the boundary elements scheme (which has been done
22485  // above)
22486 
22487  // Set the number of segments for the boundaries with geom objects
22488  // associated. The correct value is not on the original mesh since
22489  // it is computed only when calling then
22490  // setup_boundary_coordinates() method (called only for those
22491  // boundaries with no geom object associated)
22492  for (unsigned b = 0; b < tmp_nboundary; b++)
22493  {
22494  if (this->boundary_geom_object_pt(b) != 0)
22495  {
22496  // Clear the boundary segment nodes storage
22497  this->flush_boundary_segment_node(b);
22498 
22499  // Dummy vector of nodes on segments
22500  Vector<Vector<Node*>> dummy_segment_node_pt;
22501 
22502  // Compute the new number of segments in the boundary
22503  get_boundary_segment_nodes_helper(b, dummy_segment_node_pt);
22504 
22505  // Get the number of segments from the vector of nodes
22506  const unsigned nsegments = dummy_segment_node_pt.size();
22507 
22508  // Set the number of segments for the storing of the nodes
22509  // associated to the segments
22510  this->set_nboundary_segment_node(b, nsegments);
22511  } // if (this->boundary_geom_object_pt(b)!=0)
22512 
22513  } // for (b < n_boundary)
22514 
22515  // The time to re-establish the halo(ed) information
22516  if (Print_timings_level_load_balance > 1)
22517  {
22518  oomph_info
22519  << "CPU for re-establishing halo(ed) information (load balance) [11]: "
22520  << TimingHelpers::timer() - tt_start_re_etablish_halo_ed_info
22521  << std::endl;
22522  }
22523 
22524  // =====================================================================
22525  // END: REESTABLISH THE HALO(ED) SCHEME, ATTACH HALO ELEMENTS (HALO
22526  // NODES INCLUDED) TO THE NEW MESH (AFTER LOAD BALANCING) RESTORE
22527  // THE BOUNDARY ELEMENTS SCHEME AND THE NUMBER OF SEGMENTS ON EACH
22528  // BOUNDARY
22529  // =====================================================================
22530 
22531  if (Print_timings_level_load_balance > 1)
22532  {
22533  oomph_info << "CPU for load balance [n_ele_before="
22534  << nelement_before_load_balance
22535  << ", n_ele_after=" << nelement_after_load_balance << "]: "
22536  << TimingHelpers::timer() - t_start_overall_load_balance
22537  << std::endl;
22538  }
22539 
22540  oomph_info << "Load balance (unstructured mesh) [END]" << std::endl;
22541  }
22542 
22543  //======================================================================
22544  /// Use the first and second group of elements to find the
22545  /// intersection between them to get the shared boundary
22546  /// elements from the first and second group
22547  //======================================================================
22548  template<class ELEMENT>
22551  const Vector<FiniteElement*>& first_element_pt,
22552  const Vector<FiniteElement*>& second_element_pt,
22553  Vector<FiniteElement*>& first_shared_boundary_element_pt,
22554  Vector<unsigned>& first_shared_boundary_element_face_index,
22555  Vector<FiniteElement*>& second_shared_boundary_element_pt,
22556  Vector<unsigned>& second_shared_boundary_element_face_index)
22557  {
22558  // 1) Compare their faces (nodes) and if they match then they are
22559  // part of a shared boundary
22560  // 2) Save the first and second group of elements that give rise to
22561  // the shared boundary, also include the face index
22562 
22563  // Get the number of elements on the first group
22564  const unsigned nfirst_element = first_element_pt.size();
22565  // Loop over the elements in the first group
22566  for (unsigned ef = 0; ef < nfirst_element; ef++)
22567  {
22568  // Get the element
22569  FiniteElement* fele_pt = first_element_pt[ef];
22570  // Check if the element is halo
22571  bool first_ele_is_halo = false;
22572  if (fele_pt->is_halo())
22573  {
22574  first_ele_is_halo = true;
22575  }
22576  // Get each of the faces
22577  for (unsigned ifface = 0; ifface < 3; ifface++)
22578  {
22579  Vector<Node*> first_face(2);
22580  if (ifface == 0)
22581  {
22582  first_face[0] = fele_pt->node_pt(1);
22583  first_face[1] = fele_pt->node_pt(2);
22584  }
22585  else if (ifface == 1)
22586  {
22587  first_face[0] = fele_pt->node_pt(2);
22588  first_face[1] = fele_pt->node_pt(0);
22589  }
22590  else if (ifface == 2)
22591  {
22592  first_face[0] = fele_pt->node_pt(0);
22593  first_face[1] = fele_pt->node_pt(1);
22594  }
22595 
22596  // Now check each of the faces with the faces on the second
22597  // elements
22598 
22599  // Get the number of elements on the second group
22600  const unsigned nsecond_element = second_element_pt.size();
22601  // Loop over the elements in the second group
22602  for (unsigned es = 0; es < nsecond_element; es++)
22603  {
22604  // Get the element
22605  FiniteElement* sele_pt = second_element_pt[es];
22606  // Check if the element is halo
22607  bool second_ele_is_halo = false;
22608  if (sele_pt->is_halo())
22609  {
22610  second_ele_is_halo = true;
22611  }
22612  // Now check whether both elements are halo, if that is the
22613  // case then we go for the next elements. We can not look for
22614  // shared boundaries between halo elements since other
22615  // processors, those with the nonhalo counterpart of the
22616  // elements, are in charge of creating those shared boundaries
22617  if (!(first_ele_is_halo && second_ele_is_halo))
22618  {
22619  // Get each of the faces
22620  for (unsigned isface = 0; isface < 3; isface++)
22621  {
22622  Vector<Node*> second_face(2);
22623  if (isface == 0)
22624  {
22625  second_face[0] = sele_pt->node_pt(1);
22626  second_face[1] = sele_pt->node_pt(2);
22627  }
22628  else if (isface == 1)
22629  {
22630  second_face[0] = sele_pt->node_pt(2);
22631  second_face[1] = sele_pt->node_pt(0);
22632  }
22633  else if (isface == 2)
22634  {
22635  second_face[0] = sele_pt->node_pt(0);
22636  second_face[1] = sele_pt->node_pt(1);
22637  }
22638 
22639  // Now check for any intersection among first and second
22640  // faces
22641  if (first_face[0] == second_face[0] &&
22642  first_face[1] == second_face[1])
22643  {
22644  // Save the elements on the corresponding containers
22645  first_shared_boundary_element_pt.push_back(fele_pt);
22646  // .. and the face index
22647  first_shared_boundary_element_face_index.push_back(ifface);
22648 
22649  // Save the elements on the corresponding containers
22650  second_shared_boundary_element_pt.push_back(sele_pt);
22651  // .. and the face index
22652  second_shared_boundary_element_face_index.push_back(isface);
22653 
22654  // Break the loop over the faces of the first elements
22655  // and the first elements, we need to continue looking
22656  // on the next face of the first elements
22657 
22658  // Increase the indexes to force breaking the loop
22659  isface = 3;
22660  es = nsecond_element;
22661  }
22662  // Check for intersection with the reversed case too
22663  else if (first_face[0] == second_face[1] &&
22664  first_face[1] == second_face[0])
22665  {
22666  // Save the elements on the corresponding containers
22667  first_shared_boundary_element_pt.push_back(fele_pt);
22668  // .. and the face index
22669  first_shared_boundary_element_face_index.push_back(ifface);
22670 
22671  // Save the elements on the corresponding containers
22672  second_shared_boundary_element_pt.push_back(sele_pt);
22673  // .. and the face index
22674  second_shared_boundary_element_face_index.push_back(isface);
22675 
22676  // Break the loop over the faces of the first elements
22677  // and the first elements, we need to continue looking
22678  // on the next face of the first elements
22679 
22680  // Increase the indexes to force breaking the loop
22681  isface = 3;
22682  es = nsecond_element;
22683  }
22684 
22685  } // for (isface < 3)
22686 
22687  } // if (!(first_ele_is_halo && second_ele_is_halo))
22688 
22689  } // for (es < nsecond_element)
22690 
22691  } // for (ifface < 3)
22692 
22693  } // for (ef < nfirst_element)
22694  }
22695 
22696  //======================================================================
22697  /// Creates the new shared boundaries, this method is also in
22698  /// charge of computing the shared boundaries ids of each processor
22699  /// and send that info. to all the processors
22700  //======================================================================
22701  template<class ELEMENT>
22703  std::set<FiniteElement*>& element_in_processor_pt,
22704  Vector<Vector<FiniteElement*>>& new_shared_boundary_element_pt,
22705  Vector<Vector<unsigned>>& new_shared_boundary_element_face_index)
22706  {
22707  // Get the number of processors
22708  const unsigned nproc = this->communicator_pt()->nproc();
22709  // Get the rank of the current processor
22710  const unsigned my_rank = this->communicator_pt()->my_rank();
22711 
22712  // ================================================================
22713  // BEGIN: GET THE SHARED BOUNDARY FACE ELEMENTS FROM THE SHARED
22714  // BOUNDARY ELEMENTS, AND ASSIGN A ROOT EDGE TO EACH FACE
22715  // ELEMENT. AVOID THE CREATION OF FACE ELEMENTS THAT REPRESENT THE
22716  // SAME EDGE (INTERNAL BOUNDARIES)
22717  // ================================================================
22718 
22719  // Get the time to get edges from shared boundary face elements
22720  double tt_start_get_edges_from_shd_bnd_face_ele = 0.0;
22721  if (Print_timings_level_load_balance > 2)
22722  {
22723  tt_start_get_edges_from_shd_bnd_face_ele = TimingHelpers::timer();
22724  }
22725 
22726  // Face elements that create the shared boundaries (unsorted)
22727  Vector<Vector<FiniteElement*>> tmp_unsorted_face_ele_pt(nproc);
22728  // The elements from where the face element was created
22729  Vector<Vector<FiniteElement*>> tmp_unsorted_ele_pt(nproc);
22730  // The face index of the bulk element from where was created the
22731  // face element
22732  Vector<Vector<int>> tmp_unsorted_face_index_ele(nproc);
22733 
22734  // Store the current edges lying on boundaries (this will help for
22735  // any edge of a shared boundary lying on an internal boundary)
22736  std::map<std::pair<Node*, Node*>, unsigned> elements_edges_on_boundary;
22737 
22738  // Compute the edges on the other boundaries
22739  this->get_element_edges_on_boundary(elements_edges_on_boundary);
22740 
22741  // Mark those edges (pair of nodes overlapped by a shared boundary)
22742  std::map<std::pair<Node*, Node*>, bool> overlapped_edge;
22743 
22744  // Associate every found edge (face element) on the shared boundary
22745  // with an original boundary only if the edge (face element) lies
22746  // (overlaps) on an original boundary, it may happen only for
22747  // internal boundaries
22748  Vector<Vector<int>> tmp_edge_boundary(nproc);
22749 
22750  // Get the face elements from the shared boundary elements with in
22751  // each processor
22752  for (unsigned iproc = 0; iproc < nproc; iproc++)
22753  {
22754  // There are no shared boundary elements with myself
22755  if (iproc != my_rank)
22756  {
22757  // Get the number of shared boundary elements with in "iproc"
22758  // processor
22759  const unsigned n_shared_bound_ele =
22760  new_shared_boundary_element_pt[iproc].size();
22761 
22762  // Avoid to create repeated face elements, compare the nodes on
22763  // the edges of the face elements
22764  Vector<std::pair<Node*, Node*>> done_faces;
22765 
22766  // Count the number of repeated faces
22767  unsigned nrepeated_faces = 0;
22768 
22769  // Loop over the shared boundary elements with the iproc
22770  // processor
22771  for (unsigned iele = 0; iele < n_shared_bound_ele; iele++)
22772  {
22773  // Get the bulk element
22774  FiniteElement* bulk_ele_pt =
22775  new_shared_boundary_element_pt[iproc][iele];
22776 
22777  // Get the face index
22778  int face_index = static_cast<int>(
22779  new_shared_boundary_element_face_index[iproc][iele]);
22780 
22781  // Create the face element
22782  FiniteElement* tmp_ele_pt =
22783  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
22784 
22785  // Before adding the face element to the vector check that is
22786  // not has been previously created
22787  bool done_face = false;
22788 
22789  // Get the number of nodes on the face element and get the first
22790  // and last node
22791  const unsigned nnode_face_ele = tmp_ele_pt->nnode();
22792  Node* first_face_node_pt = tmp_ele_pt->node_pt(0);
22793  Node* last_face_node_pt = tmp_ele_pt->node_pt(nnode_face_ele - 1);
22794 
22795  // Get the number of already done face elements
22796  const unsigned ndone_faces = done_faces.size();
22797  // Loop over the already visited face elements
22798  for (unsigned n = 0; n < ndone_faces; n++)
22799  {
22800  Node* first_done_face_node_pt = done_faces[n].first;
22801  Node* second_done_face_node_pt = done_faces[n].second;
22802  if (first_face_node_pt == first_done_face_node_pt &&
22803  last_face_node_pt == second_done_face_node_pt)
22804  {
22805  done_face = true;
22806  nrepeated_faces++;
22807  break;
22808  }
22809  // Check for the reversed case
22810  else if (first_face_node_pt == second_done_face_node_pt &&
22811  last_face_node_pt == first_done_face_node_pt)
22812  {
22813  done_face = true;
22814  nrepeated_faces++;
22815  break;
22816  }
22817 
22818  } // for (n < ndone_faces)
22819 
22820  // Only include the faces that are not repeated
22821  if (!done_face)
22822  {
22823  // Add the face element in the vector
22824  tmp_unsorted_face_ele_pt[iproc].push_back(tmp_ele_pt);
22825  // Add the bulk element to the vector
22826  tmp_unsorted_ele_pt[iproc].push_back(bulk_ele_pt);
22827  // Add the face index to the vector
22828  tmp_unsorted_face_index_ele[iproc].push_back(face_index);
22829  // Include the nodes in the done nodes vector
22830  std::pair<Node*, Node*> tmp_edge =
22831  std::make_pair(first_face_node_pt, last_face_node_pt);
22832  // Push the edge
22833  done_faces.push_back(tmp_edge);
22834 
22835  // Associate the face element with a boundary (if that is
22836  // the case)
22837  int edge_boundary_id = -1;
22838  std::map<std::pair<Node*, Node*>, unsigned>::iterator it;
22839  it = elements_edges_on_boundary.find(tmp_edge);
22840  // If the edges lie on a boundary then get the boundary id
22841  // on which the edges lie
22842  if (it != elements_edges_on_boundary.end())
22843  {
22844  // Assign the internal boundary id associated with the
22845  // edge
22846  edge_boundary_id = (*it).second;
22847  // Mark the edge as overlapped
22848  overlapped_edge[tmp_edge] = true;
22849  // Also include the reversed version of the edge
22850  std::pair<Node*, Node*> rev_tmp_edge =
22851  std::make_pair(last_face_node_pt, first_face_node_pt);
22852  // Mark the reversed version of the edge as overlapped
22853  overlapped_edge[rev_tmp_edge] = true;
22854  }
22855  else
22856  {
22857  // Look for the reversed version
22858  std::pair<Node*, Node*> rtmp_edge =
22859  std::make_pair(last_face_node_pt, first_face_node_pt);
22860  it = elements_edges_on_boundary.find(rtmp_edge);
22861  if (it != elements_edges_on_boundary.end())
22862  {
22863  // Assign the internal boundary id associated with the
22864  // edge
22865  edge_boundary_id = (*it).second;
22866  // Mark the edge as overlapped
22867  overlapped_edge[rtmp_edge] = true;
22868  // Mark the reversed version (normal) of the edge as
22869  // overlapped
22870  overlapped_edge[tmp_edge] = true;
22871  }
22872  }
22873  // Associate the edge with a boundary
22874  tmp_edge_boundary[iproc].push_back(edge_boundary_id);
22875  } // if (!done_face)
22876  else
22877  {
22878  // Delete the repeated face elements
22879  delete tmp_ele_pt;
22880  tmp_ele_pt = 0;
22881  }
22882 
22883  } // for (iele < n_shared_bound_ele)
22884 
22885  } // if (iproc != my_rank)
22886 
22887  } // for (iproc < nproc)
22888 
22889  // The time to get edges from shared boundary face elements
22890  if (Print_timings_level_load_balance > 2)
22891  {
22892  oomph_info << "CPU for getting edges from shared boundary face elements "
22893  "(load balance) [9.1]: "
22894  << TimingHelpers::timer() -
22895  tt_start_get_edges_from_shd_bnd_face_ele
22896  << std::endl;
22897  }
22898 
22899  // ================================================================
22900  // END: GET THE SHARED BOUNDARY FACE ELEMENTS FROM THE SHARED
22901  // BOUNDARY ELEMENTS, AND ASSIGN A ROOT EDGE TO EACH FACE
22902  // ELEMENT. AVOID THE CREATION OF FACE ELEMENTS THAT REPRESENT THE
22903  // SAME EDGE (INTERNAL BOUNDARIES)
22904  // ================================================================
22905 
22906  // ================================================================
22907  // BEGIN: BEFORE SORTING THE SHARED FACE ELEMENTS AND ITS ASSOCIATED
22908  // DATA, WE NEED TO ENSURE THAT THEY APPEAR (OR ARE STORED) IN THE
22909  // SAME ORDER IN BOTH OF THE PROCESSORS THAT CREATED THEM. WE USE
22910  // THE BOTTOM-LEFT NODE OF EACH FACE ELEMENT TO STORE THEM IN THE
22911  // SAME ORDER IN BOTH PROCESSORS. ALSO ENSURE THAT THE FACE ELEMENTS
22912  // AGREE WITH THE FIRST AND LAST NODE IN ALL PROCESSORS
22913  // ================================================================
22914 
22915  // Get the time to sort shared face elements
22916  double tt_start_sort_shared_face_elements = 0.0;
22917  if (Print_timings_level_load_balance > 2)
22918  {
22919  tt_start_sort_shared_face_elements = TimingHelpers::timer();
22920  }
22921 
22922  // -----------------------------------------------------------------
22923  // Before continuing we need to ensured that the face elements are
22924  // stored in the same order in all processors. Sort them starting
22925  // from the face element with the bottom-left node coordinate
22926 
22927  // Face elements that create the shared boundaries (unsorted)
22928  Vector<Vector<FiniteElement*>> unsorted_face_ele_pt(nproc);
22929  // The elements from where the face element was created
22930  Vector<Vector<FiniteElement*>> unsorted_ele_pt(nproc);
22931  // The face index of the bulk element from where was created the
22932  // face element
22933  Vector<Vector<int>> unsorted_face_index_ele(nproc);
22934  // Associate every found edge on the shared boundary with an
22935  // original boundary only if the edge lies on an original boundary,
22936  // it may happen only for internal boundaries
22937  Vector<Vector<int>> edge_boundary(nproc);
22938 
22939  // For each face element, mark if the element should be considered
22940  // in its inverted way to fullfill with the bottom-left node to be
22941  // the first (left) node. First get the status of each element and
22942  // when they get sorted copy the values across
22943  std::vector<std::vector<bool>> tmp_treat_as_inverted(nproc);
22944  // Vector to store the status of the sorted face elements based on
22945  // the bottom-left condition
22946  std::vector<std::vector<bool>> treat_as_inverted(nproc);
22947 
22948  // Get the bottom-left node of each face element and sort them
22949  // starting from the face element with the bottom-left node
22950 
22951  // Loop over the processors
22952  for (unsigned iproc = 0; iproc < nproc; iproc++)
22953  {
22954  // There are no shared face elements with myself
22955  if (iproc != my_rank)
22956  {
22957  // Get the number of unsorted face elements
22958  const unsigned n_face_ele = tmp_unsorted_face_ele_pt[iproc].size();
22959  // Store the centroid of the face element. Perform the sorting
22960  // based on the bottom-left centroid of each face element
22961  Vector<Vector<double>> centroid_vertices(n_face_ele);
22962 
22963  // Resize the storage for the treating as inverted face element
22964  // storage
22965  tmp_treat_as_inverted[iproc].resize(n_face_ele);
22966 
22967  // Loop over the face elements associated with the iproc
22968  // processor
22969  for (unsigned e = 0; e < n_face_ele; e++)
22970  {
22971  // Get the face element
22972  FiniteElement* face_ele_pt = tmp_unsorted_face_ele_pt[iproc][e];
22973  // Get the number of nodes of the face element
22974  const unsigned n_node = face_ele_pt->nnode();
22975  Vector<double> bottom_left(2);
22976  // Assign as the bottom-left node the first node
22977  // Get the node
22978  Node* node_pt = face_ele_pt->node_pt(0);
22979  bottom_left[0] = node_pt->x(0);
22980  bottom_left[1] = node_pt->x(1);
22981  // Set as not treat as inverted element
22982  tmp_treat_as_inverted[iproc][e] = false;
22983  // Loop over the nodes to get the bottom-left vertex of all
22984  // the nodes
22985  for (unsigned n = 1; n < n_node; n++)
22986  {
22987  // Get the node
22988  Node* node_pt = face_ele_pt->node_pt(n);
22989  if (node_pt->x(1) < bottom_left[1])
22990  {
22991  bottom_left[0] = node_pt->x(0);
22992  bottom_left[1] = node_pt->x(1);
22993  // The first node is no longer the bottom-left node, we
22994  // need to treat the element as inverted
22995  tmp_treat_as_inverted[iproc][e] = true;
22996  } // if (node_pt->x(1) < bottom_left[1])
22997  else if (node_pt->x(1) == bottom_left[1])
22998  {
22999  if (node_pt->x(0) < bottom_left[0])
23000  {
23001  bottom_left[0] = node_pt->x(0);
23002  bottom_left[1] = node_pt->x(1);
23003  // The first node is no longer the bottom-left node, we
23004  // need to treat the element as inverted
23005  tmp_treat_as_inverted[iproc][e] = true;
23006  } // if (node_pt->x(0) < bottom_left[0])
23007  } // else if (node_pt->x(1) == bottom_left[1])
23008 
23009  } // for (n < n_node
23010 
23011  // Resize the container
23012  centroid_vertices[e].resize(2);
23013  // Add the centroid of the face element
23014  centroid_vertices[e][0] = (face_ele_pt->node_pt(0)->x(0) +
23015  face_ele_pt->node_pt(n_node - 1)->x(0)) *
23016  0.5;
23017  centroid_vertices[e][1] = (face_ele_pt->node_pt(0)->x(1) +
23018  face_ele_pt->node_pt(n_node - 1)->x(1)) *
23019  0.5;
23020 
23021  } // for (e < n_face_ele)
23022 
23023  // Sort the face elements based on their bottom-left node
23024  unsigned n_sorted_bottom_left = 0;
23025  // Keep track of the already sorted face elements
23026  std::vector<bool> done_face(n_face_ele, false);
23027 
23028  // Loop until all face elements have been sorted
23029  while (n_sorted_bottom_left < n_face_ele)
23030  {
23031  // The index of the next bottom-left face element
23032  unsigned index = 0;
23033  Vector<double> current_bottom_left(2);
23034  for (unsigned e = 0; e < n_face_ele; e++)
23035  {
23036  // Get the first not done face element
23037  if (!done_face[e])
23038  {
23039  // Store the first not done
23040  current_bottom_left[0] = centroid_vertices[e][0];
23041  current_bottom_left[1] = centroid_vertices[e][1];
23042  // Set the index
23043  index = e;
23044  // Break
23045  break;
23046  } // if (!done_face[e])
23047 
23048  } // for (e < n_face_ele)
23049 
23050  // Loop over all the other nondone face elements
23051  for (unsigned e = index + 1; e < n_face_ele; e++)
23052  {
23053  // Get the first not done face element
23054  if (!done_face[e])
23055  {
23056  if (centroid_vertices[e][1] < current_bottom_left[1])
23057  {
23058  // Re-set the current bottom left vertex
23059  current_bottom_left[0] = centroid_vertices[e][0];
23060  current_bottom_left[1] = centroid_vertices[e][1];
23061  // Re-assign the index
23062  index = e;
23063  } // if (centroid_vertices[e][1] < current_bottom_left[1])
23064  else if (centroid_vertices[e][1] == current_bottom_left[1])
23065  {
23066  if (centroid_vertices[e][0] < current_bottom_left[0])
23067  {
23068  // Re-set the current bottom left vertex
23069  current_bottom_left[0] = centroid_vertices[e][0];
23070  current_bottom_left[1] = centroid_vertices[e][1];
23071  // Re-assign the index
23072  index = e;
23073  } // if (centroid_vertices[e][0] < current_bottom_left[0])
23074 
23075  } // else if (centroid_vertices[e][1] == current_bottom_left[1])
23076 
23077  } // if (!done_face[e])
23078 
23079  } // for (e < n_face_ele)
23080 
23081  // The face element
23082  unsorted_face_ele_pt[iproc].push_back(
23083  tmp_unsorted_face_ele_pt[iproc][index]);
23084  // The boundary element
23085  unsorted_ele_pt[iproc].push_back(tmp_unsorted_ele_pt[iproc][index]);
23086  // The face index
23087  unsorted_face_index_ele[iproc].push_back(
23088  tmp_unsorted_face_index_ele[iproc][index]);
23089  // The edge boundary associated to the face element
23090  edge_boundary[iproc].push_back(tmp_edge_boundary[iproc][index]);
23091  // The treat as inverted condition
23092  treat_as_inverted[iproc].push_back(
23093  tmp_treat_as_inverted[iproc][index]);
23094 
23095  // Mark the face element as sorted (done or visited)
23096  done_face[index] = true;
23097 
23098  // Increase the number of sorted bottom-left face elements
23099  n_sorted_bottom_left++;
23100 
23101  } // while (n_sorted_bottom_left < n_face_ele)
23102 
23103 #ifdef PARANOID
23104  // Get the number of face elements sorted with the bottom-left
23105  // condition
23106  const unsigned tmp_n_face_ele = unsorted_face_ele_pt[iproc].size();
23107 
23108  if (tmp_n_face_ele != n_face_ele)
23109  {
23110  std::ostringstream error_stream;
23111  error_stream
23112  << "The number of face elements before sorting them starting\n"
23113  << "from their bottom-left vertex is different from the number\n"
23114  << "of face elements after the sorting\n"
23115  << "N. ele before sorting: (" << n_face_ele << ")\n"
23116  << "N. ele after sorting: (" << tmp_n_face_ele << ")\n";
23117  throw OomphLibError(
23118  error_stream.str(),
23119  "RefineableTriangleMesh::create_new_shared_boundaries()",
23120  OOMPH_EXCEPTION_LOCATION);
23121  }
23122 #endif
23123 
23124  } // if (iproc != my_rank)
23125 
23126  } // for (iproc < nproc)
23127 
23128  // The time to sort shared face elements
23129  if (Print_timings_level_load_balance > 2)
23130  {
23131  oomph_info << "CPU for sorting shared boundary face elements (load "
23132  "balance) [9.2]: "
23133  << TimingHelpers::timer() - tt_start_sort_shared_face_elements
23134  << std::endl;
23135  }
23136 
23137  // ================================================================
23138  // END: SORTING THE SHARED FACE ELEMENTS AND ITS ASSOCIATED DATA, WE
23139  // NEED TO ENSURE THAT THEY APPEAR (OR ARE STORED) IN THE SAME ORDER
23140  // IN BOTH OF THE PROCESSORS THAT CREATED THEM. WE USE THE
23141  // BOTTOM-LEFT NODE OF EACH FACE ELEMENT TO STORE THEM IN THE SAME
23142  // ORDER IN BOTH PROCESSORS. ALSO ENSURE THAT THE FACE ELEMENTS
23143  // AGREE WITH THE FIRST AND LAST NODE IN ALL PROCESSORS
23144  // ================================================================
23145 
23146  // ================================================================
23147  // BEGIN: COMPUTE THE GLOBAL DEGREE (VALENCY OF EACH NODE). THE
23148  // DEGREE OF THE NODES IN THE CURRENT SHARED BOUNDARIES IS COMPUTED
23149  // FIRST, THEN THIS INFO. IS SENT TO A ROOT PROCESSOR WHICH IS IN
23150  // CHARGE OF IDENTIFY AND RE-ASSIGN THE DEGREE OF THE NODES (IF THAT
23151  // IS THE CASE)
23152  // ================================================================
23153 
23154  // Get the time to compute the valency of each node
23155  double tt_start_compute_valency_of_nodes = 0.0;
23156  if (Print_timings_level_load_balance > 2)
23157  {
23158  tt_start_compute_valency_of_nodes = TimingHelpers::timer();
23159  }
23160 
23161  // Stores the global-degree of each node
23162  std::map<Node*, unsigned> global_node_degree;
23163 
23164  // Get the global degree (valency) of each node
23165  compute_shared_node_degree_helper(unsorted_face_ele_pt, global_node_degree);
23166 
23167  // The time to compute the valency of each node
23168  if (Print_timings_level_load_balance > 2)
23169  {
23170  oomph_info
23171  << "CPU for computing the valency of nodes (load balance) [9.3]: "
23172  << TimingHelpers::timer() - tt_start_compute_valency_of_nodes
23173  << std::endl;
23174  }
23175 
23176  // ================================================================
23177  // END: COMPUTE THE GLOBAL DEGREE (VALENCY OF EACH NODE). THE
23178  // DEGREE OF THE NODES IN THE CURRENT SHARED BOUNDARIES IS COMPUTED
23179  // FIRST, THEN THIS INFO. IS SENT TO A ROOT PROCESSOR WHICH IS IN
23180  // CHARGE OF IDENTIFY AND RE-ASSIGN THE DEGREE OF THE NODES (IF THAT
23181  // IS THE CASE)
23182  // ================================================================
23183 
23184  // ================================================================
23185  // BEGIN: IDENTIFY THE NODES LYING ON EDGES NOT OVERLAPED BY SHARED
23186  // BOUNDARIES, IDENTIFY THE BOUNDARY TO WHICH THE EDGE CORRESPOND
23187  // ================================================================
23188 
23189  // Get the time to compute nodes on non overlapped shared boundaries
23190  double tt_start_nodes_on_non_overlapped_shd_bnd = 0.0;
23191  if (Print_timings_level_load_balance > 2)
23192  {
23193  tt_start_nodes_on_non_overlapped_shd_bnd = TimingHelpers::timer();
23194  }
23195 
23196  // Mark the nodes on original boundaries not overlapped by shared
23197  // boundaries
23198  std::map<unsigned, std::map<Node*, bool>>
23199  node_on_bnd_not_overlapped_by_shd_bnd;
23200 
23201  // Loop over the edges of the original boundaries
23202  for (std::map<std::pair<Node*, Node*>, unsigned>::iterator it_map =
23203  elements_edges_on_boundary.begin();
23204  it_map != elements_edges_on_boundary.end();
23205  it_map++)
23206  {
23207  // Get the edge
23208  std::pair<Node*, Node*> edge_pair = (*it_map).first;
23209  // Is the edge overlaped by a shared boundary
23210  if (!overlapped_edge[edge_pair])
23211  {
23212  // Mark the nodes of the edge as being on an edge not overlaped
23213  // by a shared boundary on the boundary the edge is
23214  unsigned b = (*it_map).second;
23215 
23216  // Get the left node
23217  Node* left_node_pt = edge_pair.first;
23218  node_on_bnd_not_overlapped_by_shd_bnd[b][left_node_pt] = true;
23219 
23220  // Get the right node
23221  Node* right_node_pt = edge_pair.second;
23222  node_on_bnd_not_overlapped_by_shd_bnd[b][right_node_pt] = true;
23223 
23224  } // if (!overlapped_edge[edge_pair])
23225 
23226  } // Loop over edges to mark those nodes on overlaped edge by
23227  // shared boundaries
23228 
23229  // The time to compute nodes on non overlapped shared boundaries
23230  if (Print_timings_level_load_balance > 2)
23231  {
23232  oomph_info << "CPU for computing nodes on non overlapped shared "
23233  "boundaries (load balance) [9.4]: "
23234  << TimingHelpers::timer() -
23235  tt_start_nodes_on_non_overlapped_shd_bnd
23236  << std::endl;
23237  }
23238 
23239  // ================================================================
23240  // END: IDENTIFY THE NODES LYING ON EDGES NOT OVERLAPED BY SHARED
23241  // BOUNDARIES, IDENTIFY THE BOUNDARY TO WHICH THE EDGE CORRESPOND
23242  // ================================================================
23243 
23244  // ==================================================================
23245  // BEGIN: SORT THE SHARED BOUNDARY FACE ELEMENTS, ADD FACE ELEMENTS
23246  // TO THE LEFT OR RIGHT OF THE ROOT FACE ELEMENT. STOP ADDING WHEN
23247  // THE MOST LEFT OR MOST RIGHT ELEMENT (NODE) IS ALREADY PART OF
23248  // ANOTHER BOUNDARY (THIS MEANS THAT THE SHARED BOUNDARY THAT IS
23249  // BEING CREATED HAS A CONNECTION). ALSO REMEMBER TO CHECK FOR THE
23250  // CASE WHEN THE MOST LEFT OR MOST RIGHT NODE IS A BOUNDARY NODE OF
23251  // A BOUNDARY THAT NO LONGER EXIST IN THE DOMAIN. AT THE END OF THIS
23252  // SECTION WE WILL HAVE THE NUMBER OF SHARED BOUNDARIES OF THIS
23253  // PROCESSOR WITH OTHERS BUT NOT THE GLOBAL SHARED BOUNDARY ID
23254  // ==================================================================
23255 
23256  // Get the time to sort shared boundaries face elements to create a
23257  // continuous representation of the boundary
23258  double tt_start_join_shd_bnd_face_ele = 0.0;
23259  if (Print_timings_level_load_balance > 2)
23260  {
23261  tt_start_join_shd_bnd_face_ele = TimingHelpers::timer();
23262  }
23263 
23264  // Face elements that create the shared boundaries (sorted)
23265  Vector<Vector<Vector<FiniteElement*>>> sorted_face_ele_pt(nproc);
23266 
23267  // Bulk elements that create the shared boundaries (sorted)
23268  Vector<Vector<Vector<FiniteElement*>>> sorted_ele_pt(nproc);
23269 
23270  // Face indexes of the bulk elements that create the shared
23271  // boundaries (sorted)
23272  Vector<Vector<Vector<int>>> sorted_face_index_ele(nproc);
23273 
23274  // Store the edge boundary id associated with a shared boundary (if
23275  // any, this apply for shared boundaries lying on internal
23276  // boundaries, then the shared boundary is marked as overlaping an
23277  // internal boundary)
23278  Vector<Vector<int>> edge_boundary_id(nproc);
23279 
23280  // Store the connection information obtained when joining the face
23281  // elements (used for connection purposes only)
23282  Vector<Vector<Vector<int>>> sorted_connection_info(nproc);
23283 
23284  // Store the local shared boundary id associated to the elements
23285  // that will give rise to the shared boundaries (used to compute the
23286  // global shared boundary id from the local shared boundary id)
23287  Vector<Vector<unsigned>> proc_local_shared_boundary_id(nproc);
23288 
23289  // Map that associates the local shared boundary id with the list of
23290  // nodes that create it
23291  std::map<unsigned, std::list<Node*>>
23292  local_shd_bnd_id_to_sorted_list_node_pt;
23293 
23294  // Local shared bouonday id (used to locally identify the lists of
23295  // nodes that create shared boundaries, it is also useful to
23296  // identify connections with shared boundaries)
23297  unsigned local_shd_bnd_id = this->Initial_shared_boundary_id;
23298 
23299  // Sort the face elements, using the nodes at its ends
23300 
23301  // Mark the done elements
23302  std::map<FiniteElement*, bool> done_ele;
23303 
23304  // Mark the inverted elements
23305  std::map<FiniteElement*, bool> is_inverted;
23306 
23307  // Sort the face elements to get the number of shared boundaries
23308  // with in each processor
23309  for (unsigned iproc = 0; iproc < nproc; iproc++)
23310  {
23311  // No face elements with myself
23312  if (iproc != my_rank)
23313  {
23314  // Get the number of unsorted face elements with the iproc
23315  // processor
23316  const unsigned nunsorted_face_ele = unsorted_face_ele_pt[iproc].size();
23317  // Count the number of sorted face elements
23318  unsigned nsorted_face_ele = 0;
23319 
23320  // Iterate until all the face elements have been sorted
23321  while (nsorted_face_ele < nunsorted_face_ele)
23322  {
23323  // Take the first nonsorted element an use it as root element,
23324  // add elements to the left and right until no more elements
23325  // left or until a stop condition is reached (connection,
23326  // boundary node)
23327 
23328 #ifdef PARANOID
23329  // Flag to indicate if a root element was found
23330  bool found_root_element = false;
23331 #endif
23332 
23333  // Index of the found root element
23334  unsigned root_index = 0;
23335 
23336  // List that contains the sorted face elements
23337  std::list<FiniteElement*> tmp_sorted_face_ele_pt;
23338 
23339  // List that contains the sorted elements
23340  std::list<FiniteElement*> tmp_sorted_ele_pt;
23341 
23342  // List that contains the sorted face indexes of the bulk
23343  // elements
23344  std::list<int> tmp_sorted_face_index_ele;
23345 
23346  // Storing for the sorting nodes extracted from the face
23347  // elements. The sorted nodes are used to identify connections
23348  // among new shared boundaries or original boundaries
23349  std::list<Node*> tmp_sorted_nodes_pt;
23350  // Clear the storage (just in case)
23351  tmp_sorted_nodes_pt.clear();
23352 
23353  // The initial and final nodes
23354  Node* initial_node_pt = 0;
23355  Node* final_node_pt = 0;
23356 
23357  // Store the original boundary id related with the root face
23358  // element (if there is one)
23359  int root_edge_bound_id = -1;
23360 
23361  // Loop over the unsorted face elements until a root element
23362  // is found
23363  for (unsigned e = 0; e < nunsorted_face_ele; e++)
23364  {
23365  // Get a root element
23366  FiniteElement* root_ele_pt = unsorted_face_ele_pt[iproc][e];
23367  // Is the element already done?
23368  if (!done_ele[root_ele_pt])
23369  {
23370  // Get the edge boundary id associated with the edge (if
23371  // there is one)
23372  root_edge_bound_id = edge_boundary[iproc][e];
23373  // Add the face element to the list of sorted face
23374  // elements
23375  tmp_sorted_face_ele_pt.push_back(root_ele_pt);
23376  // Add the bulk element to the list of sorted elements
23377  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23378  // Add the face index to the list of sorted face index
23379  // elements
23380  tmp_sorted_face_index_ele.push_back(
23381  unsorted_face_index_ele[iproc][e]);
23382 
23383  // Get the nodes and state them as initial and final
23384  const unsigned nnodes = root_ele_pt->nnode();
23385  // Check if the face element should be treated as inverted
23386  if (!treat_as_inverted[iproc][e])
23387  {
23388  initial_node_pt = root_ele_pt->node_pt(0);
23389  final_node_pt = root_ele_pt->node_pt(nnodes - 1);
23390  }
23391  else
23392  {
23393  initial_node_pt = root_ele_pt->node_pt(nnodes - 1);
23394  final_node_pt = root_ele_pt->node_pt(0);
23395  }
23396  // Add both nodes to the list of sorted nodes
23397  tmp_sorted_nodes_pt.push_back(initial_node_pt);
23398  tmp_sorted_nodes_pt.push_back(final_node_pt);
23399 
23400  // Mark the element as done
23401  done_ele[root_ele_pt] = true;
23402  // Check if the face element should be treated as inverted
23403  if (!treat_as_inverted[iproc][e])
23404  {
23405  // Mark the element as not inverted
23406  is_inverted[root_ele_pt] = false;
23407  }
23408  else
23409  {
23410  // Mark the element as inverted
23411  is_inverted[root_ele_pt] = true;
23412  }
23413  // Increase the counter for sorted face elements
23414  nsorted_face_ele++;
23415  // Set the root index
23416  root_index = e;
23417 #ifdef PARANOID
23418  // Set the flag of found root element
23419  found_root_element = true;
23420 #endif
23421  // Break the loop
23422  break;
23423 
23424  } // if (!done_ele[root_ele_pt])
23425 
23426  } // for (e < nunsorted_face_ele)
23427 
23428 #ifdef PARANOID
23429  if (!found_root_element)
23430  {
23431  std::ostringstream error_stream;
23432  error_stream
23433  << "It was not possible the found the root element\n\n";
23434  throw OomphLibError(error_stream.str(),
23435  OOMPH_CURRENT_FUNCTION,
23436  OOMPH_EXCEPTION_LOCATION);
23437  }
23438 #endif
23439 
23440  // New element added. Continue adding elements -- or nodes --
23441  // to the list of shared boundary elements while a new element
23442  // has been added to the list (we have just added the root
23443  // element)
23444  bool new_element_added = true;
23445 
23446  // Similarly that in the
23447  // "create_polylines_from_halo_elements_helper() method, we
23448  // extract the nodes (in order) that will create the shared
23449  // polyline, and also check for connections with the just
23450  // added face elements (nodes)
23451 
23452  // Flags to indicate at which end (of the sorted list of
23453  // boundary elements) the element was added (left or right)
23454  bool element_added_to_the_left = false;
23455  bool element_added_to_the_right = false;
23456 
23457  // Flag to indicate that the "left" node of the element added
23458  // to the left was found to be shared with another boundary
23459  bool connection_to_the_left = false;
23460 
23461  // Flag to indicate that the "right" node of the element added
23462  // to the right was found to be shared with another boundary
23463  bool connection_to_the_right = false;
23464 
23465  // Flag to stop the adding of elements (and nodes) to the
23466  // current shared boundary (because there are connections at
23467  // both ends)
23468  bool current_polyline_has_connections_at_both_ends = false;
23469 
23470  // Store the boundary ids of the polylines to connect (only
23471  // used when the polyline was found to have a connection)
23472  // -1: Indicates no connection
23473  // -2: Indicates connection with itself
23474  // -3: Indicates no connection BUT STOP adding elements
23475  // -because the node is a boundary node whose boundary is no
23476  // -currently part of the domain. Think in one of the corner
23477  // -nodes of a triangle touchin a boundary that does no longer
23478  // -exist
23479  // Any other value: Boundary id to connect
23480  int bound_id_connection_to_the_left = -1;
23481  int bound_id_connection_to_the_right = -1;
23482 
23483  // Get the global degree of the node (notice the local degree
23484  // has been updated to global degree)
23485  const unsigned initial_node_degree =
23486  global_node_degree[initial_node_pt];
23487 
23488  // Flag to indicate we are calling the method from a load
23489  // balance sub-rutine
23490  const bool called_for_load_balance = true;
23491 
23492  // Check if the nodes of the root element have connections
23493  // ... to the left
23494  bound_id_connection_to_the_left =
23495  this->check_connections_of_polyline_nodes(
23496  element_in_processor_pt,
23497  root_edge_bound_id,
23498  overlapped_edge,
23499  node_on_bnd_not_overlapped_by_shd_bnd,
23500  tmp_sorted_nodes_pt,
23501  local_shd_bnd_id_to_sorted_list_node_pt,
23502  initial_node_degree,
23503  initial_node_pt,
23504  called_for_load_balance);
23505 
23506  // If there is a stop condition then set the corresponding
23507  // flag
23508  if (bound_id_connection_to_the_left != -1)
23509  {
23510  connection_to_the_left = true;
23511  } // if (bound_id_connection_to_the_left != -1)
23512 
23513  // Get the global degree of the node (notice the local degree
23514  // has been updated to global degree)
23515  const unsigned final_node_degree = global_node_degree[final_node_pt];
23516 
23517  // ... and to the right
23518  bound_id_connection_to_the_right =
23519  this->check_connections_of_polyline_nodes(
23520  element_in_processor_pt,
23521  root_edge_bound_id,
23522  overlapped_edge,
23523  node_on_bnd_not_overlapped_by_shd_bnd,
23524  tmp_sorted_nodes_pt,
23525  local_shd_bnd_id_to_sorted_list_node_pt,
23526  final_node_degree,
23527  final_node_pt,
23528  called_for_load_balance);
23529 
23530  // If there is a stop condition then set the corresponding
23531  // flag
23532  if (bound_id_connection_to_the_right != -1)
23533  {
23534  connection_to_the_right = true;
23535  } // if (bound_id_connection_to_the_right != -1)
23536 
23537  // If the current shared boundary has connections at both ends
23538  // then stop the adding of elements (and nodes)
23539  if (connection_to_the_left && connection_to_the_right)
23540  {
23541  current_polyline_has_connections_at_both_ends = true;
23542  }
23543 
23544  // Continue searching for more elements to add if
23545  // 1) A new element was added at the left or right of the list
23546  // 2) There are more possible elements to add
23547  // 3) The nodes at the edges of the added element (left or
23548  // right) are not part of any other previous shared
23549  // boundary
23550  while (new_element_added && (nsorted_face_ele < nunsorted_face_ele) &&
23551  !current_polyline_has_connections_at_both_ends)
23552  {
23553  // Loop over the remaining elements and try to create a
23554  // contiguous set of face elements, start looking from the
23555  // root index. Any previous element should have been already
23556  // visited
23557  for (unsigned e = root_index; e < nunsorted_face_ele; e++)
23558  {
23559  // Reset the flags for added elements, to the left and right
23560  new_element_added = false;
23561  element_added_to_the_left = false;
23562  element_added_to_the_right = false;
23563 
23564  // Get the "e"-th element on the vector
23565  FiniteElement* tmp_ele_pt = unsorted_face_ele_pt[iproc][e];
23566  // Get the boundary id associated with the edge (if any)
23567  const int edge_bound_id = edge_boundary[iproc][e];
23568  // Check if the element has been already sorted and the
23569  // related edge bound id is the same as the root edge (if
23570  // any)
23571  if (!done_ele[tmp_ele_pt] &&
23572  (edge_bound_id == root_edge_bound_id))
23573  {
23574  // Get the number of nodes on the current element
23575  const unsigned nnodes = tmp_ele_pt->nnode();
23576  // Get the first and last node of the element
23577  // Check if the face element should be treated as inverted
23578  Node* first_node_pt = 0;
23579  Node* last_node_pt = 0;
23580  if (!treat_as_inverted[iproc][e])
23581  {
23582  first_node_pt = tmp_ele_pt->node_pt(0);
23583  last_node_pt = tmp_ele_pt->node_pt(nnodes - 1);
23584  }
23585  else
23586  {
23587  first_node_pt = tmp_ele_pt->node_pt(nnodes - 1);
23588  last_node_pt = tmp_ele_pt->node_pt(0);
23589  }
23590 
23591  // A pointer to the node at the left or right of the
23592  // just added element, the most left or the most right
23593  // node
23594  Node* new_added_node_pt = 0;
23595 
23596  // Check if the element goes to the left
23597  if (initial_node_pt == last_node_pt && !connection_to_the_left)
23598  {
23599  // Update the initial node and the just added node
23600  new_added_node_pt = initial_node_pt = first_node_pt;
23601  // Add the most left node
23602  tmp_sorted_nodes_pt.push_front(first_node_pt);
23603  // Add the face element to the list of sorted face
23604  // elements
23605  tmp_sorted_face_ele_pt.push_front(tmp_ele_pt);
23606  // Add the bulk element to the list of sorted elements
23607  tmp_sorted_ele_pt.push_front(unsorted_ele_pt[iproc][e]);
23608  // Add the face index to the list of sorted face index
23609  // elements
23610  tmp_sorted_face_index_ele.push_front(
23611  unsorted_face_index_ele[iproc][e]);
23612  if (!treat_as_inverted[iproc][e])
23613  {
23614  // Mark the element as not inverted
23615  is_inverted[tmp_ele_pt] = false;
23616  }
23617  else
23618  {
23619  // Mark the element as inverted
23620  is_inverted[tmp_ele_pt] = true;
23621  }
23622  // Set the flag to indicate a new element was added
23623  new_element_added = true;
23624  // Set the flag to indicate the element was added to
23625  // the left
23626  element_added_to_the_left = true;
23627  }
23628  // Check if the element goes to the left (but inverted)
23629  else if (initial_node_pt == first_node_pt &&
23630  !connection_to_the_left)
23631  {
23632  // Update the initial node and the just added node
23633  new_added_node_pt = initial_node_pt = last_node_pt;
23634  // Add the most left node
23635  tmp_sorted_nodes_pt.push_front(last_node_pt);
23636  // Add the face element to the list of sorted face
23637  // elements
23638  tmp_sorted_face_ele_pt.push_front(tmp_ele_pt);
23639  // Add the bulk element to the list of sorted elements
23640  tmp_sorted_ele_pt.push_front(unsorted_ele_pt[iproc][e]);
23641  // Add the face index to the list of sorted face index
23642  // elements
23643  tmp_sorted_face_index_ele.push_front(
23644  unsorted_face_index_ele[iproc][e]);
23645  if (!treat_as_inverted[iproc][e])
23646  {
23647  // Mark the element as inverted
23648  is_inverted[tmp_ele_pt] = true;
23649  }
23650  else
23651  {
23652  // Mark the element as not inverted
23653  is_inverted[tmp_ele_pt] = false;
23654  }
23655  // Set the flag to indicate a new element was added
23656  new_element_added = true;
23657  // Set the flag to indicate the element was added to
23658  // the left
23659  element_added_to_the_left = true;
23660  }
23661  // Check if the elements goes to the right
23662  else if (final_node_pt == first_node_pt &&
23663  !connection_to_the_right)
23664  {
23665  // Update the final node and the just added node
23666  new_added_node_pt = final_node_pt = last_node_pt;
23667  // Add the most right node
23668  tmp_sorted_nodes_pt.push_back(last_node_pt);
23669  // Add the face element to the list of sorted face
23670  // elements
23671  tmp_sorted_face_ele_pt.push_back(tmp_ele_pt);
23672  // Add the bulk element to the list of sorted elements
23673  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23674  // Add the face index to the list of sorted face index
23675  // elements
23676  tmp_sorted_face_index_ele.push_back(
23677  unsorted_face_index_ele[iproc][e]);
23678  if (!treat_as_inverted[iproc][e])
23679  {
23680  // Mark the element as not inverted
23681  is_inverted[tmp_ele_pt] = false;
23682  }
23683  else
23684  {
23685  // Mark the element as inverted
23686  is_inverted[tmp_ele_pt] = true;
23687  }
23688  // Set the flag to indicate a new element was added
23689  new_element_added = true;
23690  // Set the flag to indicate the element was added to
23691  // the right
23692  element_added_to_the_right = true;
23693  }
23694  // Check if the elements goes to the right (but inverted)
23695  else if (final_node_pt == last_node_pt &&
23696  !connection_to_the_right)
23697  {
23698  // Update the final node and the just added node
23699  new_added_node_pt = final_node_pt = first_node_pt;
23700  // Add the most right node
23701  tmp_sorted_nodes_pt.push_back(first_node_pt);
23702  // Add the face element to the list of sorted face
23703  // elements
23704  tmp_sorted_face_ele_pt.push_back(tmp_ele_pt);
23705  // Add the bulk element to the list of sorted elements
23706  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23707  // Add the face index to the list of sorted face index
23708  // elements
23709  tmp_sorted_face_index_ele.push_back(
23710  unsorted_face_index_ele[iproc][e]);
23711  if (!treat_as_inverted[iproc][e])
23712  {
23713  // Mark the element as inverted
23714  is_inverted[tmp_ele_pt] = true;
23715  }
23716  else
23717  {
23718  // Mark the element as not inverted
23719  is_inverted[tmp_ele_pt] = false;
23720  }
23721  // Set the flag to indicate a new elements was added
23722  new_element_added = true;
23723  // Set the flag to indicate the element was added to
23724  // the right
23725  element_added_to_the_right = true;
23726  }
23727 
23728  // Do additional stuff if the element was added
23729  if (new_element_added)
23730  {
23731  // Mark the element as done
23732  done_ele[tmp_ele_pt] = true;
23733  // Increase the counter for sorted face elements
23734  nsorted_face_ele++;
23735 
23736  // Get the global degree of the node (notice the
23737  // local degree has been updated to global degree)
23738  const unsigned new_added_node_degree =
23739  global_node_degree[new_added_node_pt];
23740 
23741  // Based on which side the element was added, look for
23742  // connections on that side
23743 
23744  // Verify for connections to the left (we need to
23745  // check for the connection variable too, since
23746  // after a connection has been done we no longer
23747  // need to verify for this condition)
23748  if (element_added_to_the_left && !connection_to_the_left)
23749  {
23750  // Check for connection
23751  bound_id_connection_to_the_left =
23752  this->check_connections_of_polyline_nodes(
23753  element_in_processor_pt,
23754  root_edge_bound_id,
23755  overlapped_edge,
23756  node_on_bnd_not_overlapped_by_shd_bnd,
23757  tmp_sorted_nodes_pt,
23758  local_shd_bnd_id_to_sorted_list_node_pt,
23759  new_added_node_degree,
23760  new_added_node_pt,
23761  called_for_load_balance);
23762 
23763  // If there is a stop condition then set the
23764  // corresponding flag
23765  if (bound_id_connection_to_the_left != -1)
23766  {
23767  connection_to_the_left = true;
23768  } // if (bound_id_connection_to_the_left != -1)
23769 
23770  } // if (node_added_to_the_left &&
23771  // !connection_to_the_left)
23772 
23773  // Verify for connections to the right (we need to
23774  // check for the connection variable too, since
23775  // after a connection has been done we no longer
23776  // need to verify for this condition)
23777  if (element_added_to_the_right && !connection_to_the_right)
23778  {
23779  // Check for connection
23780  bound_id_connection_to_the_right =
23781  this->check_connections_of_polyline_nodes(
23782  element_in_processor_pt,
23783  root_edge_bound_id,
23784  overlapped_edge,
23785  node_on_bnd_not_overlapped_by_shd_bnd,
23786  tmp_sorted_nodes_pt,
23787  local_shd_bnd_id_to_sorted_list_node_pt,
23788  new_added_node_degree,
23789  new_added_node_pt,
23790  called_for_load_balance);
23791 
23792  // If there is a stop condition then set the
23793  // corresponding flag
23794  if (bound_id_connection_to_the_right != -1)
23795  {
23796  connection_to_the_right = true;
23797  } // if (bound_id_connection_to_the_right != -1)
23798 
23799  } // if (node_added_to_the_right &&
23800  // !connection_to_the_right)
23801 
23802  // If the current shared boundary has connections at
23803  // both ends then stop the adding of elements (and
23804  // nodes)
23805  if (connection_to_the_left && connection_to_the_right)
23806  {
23807  current_polyline_has_connections_at_both_ends = true;
23808  }
23809 
23810  // Break the for (looping over unsorted face
23811  // elements) and re-start looking for more elements
23812  // that fit to the left or right
23813  break;
23814 
23815  } // if (new_element_added)
23816 
23817  } // if (!done_ele[tmp_ele_pt])
23818 
23819  } // for (e < nunsorted_face_ele)
23820 
23821  } // while(new_element_added &&
23822  // (nsorted_face_ele < nunsorted_face_ele)
23823  // && !current_polyline_has_connections_at_both_ends)
23824 
23825  // ------------------------------------------------------------
23826  // Before assigning a local shared boundary id to the list of
23827  // nodes and boundary elements, check for any loop that the
23828  // shared boundary may be creating
23829 
23830  // The vector of the elements
23831  Vector<FiniteElement*> tmp_vector_sorted_ele_pt;
23832  // Store the list of elements on a vector of elements
23833  for (std::list<FiniteElement*>::iterator it =
23834  tmp_sorted_ele_pt.begin();
23835  it != tmp_sorted_ele_pt.end();
23836  it++)
23837  {
23838  tmp_vector_sorted_ele_pt.push_back((*it));
23839  }
23840 
23841  // The vector of the face elements
23842  Vector<FiniteElement*> tmp_vector_sorted_face_ele_pt;
23843  // Store the list of face elements on a vector of face
23844  // elements
23845  for (std::list<FiniteElement*>::iterator it =
23846  tmp_sorted_face_ele_pt.begin();
23847  it != tmp_sorted_face_ele_pt.end();
23848  it++)
23849  {
23850  tmp_vector_sorted_face_ele_pt.push_back((*it));
23851  }
23852 
23853  // The vector of the face indexes
23854  Vector<int> tmp_vector_sorted_face_index_ele;
23855  // Store the list of elements on a vector of elements
23856  for (std::list<int>::iterator it = tmp_sorted_face_index_ele.begin();
23857  it != tmp_sorted_face_index_ele.end();
23858  it++)
23859  {
23860  tmp_vector_sorted_face_index_ele.push_back((*it));
23861  }
23862 
23863  // Store the nodes for the new shared polylines without loops
23864  Vector<std::list<Node*>> final_sorted_nodes_pt;
23865  // Store the boundary elements of the shared polyline without
23866  // loops
23867  Vector<Vector<FiniteElement*>> final_boundary_element_pt;
23868  // Store the boundary face elements of the shared polyline
23869  // without loops
23870  Vector<Vector<FiniteElement*>> final_boundary_face_element_pt;
23871  // Face indexes of the boundary elements without loops
23872  Vector<Vector<int>> final_face_index_element;
23873  // Connection flags (to the left) of the shared boundaries
23874  // without loops
23875  Vector<int> final_bound_id_connection_to_the_left;
23876  // Connection flags (to the right) of the shared boundaries
23877  // without loops
23878  Vector<int> final_bound_id_connection_to_the_right;
23879 
23880  // Break any possible loop created by the shared polyline
23881  this->break_loops_on_shared_polyline_load_balance_helper(
23882  local_shd_bnd_id,
23883  tmp_sorted_nodes_pt,
23884  tmp_vector_sorted_ele_pt,
23885  tmp_vector_sorted_face_ele_pt,
23886  tmp_vector_sorted_face_index_ele,
23887  bound_id_connection_to_the_left,
23888  bound_id_connection_to_the_right,
23889  final_sorted_nodes_pt,
23890  final_boundary_element_pt,
23891  final_boundary_face_element_pt,
23892  final_face_index_element,
23893  final_bound_id_connection_to_the_left,
23894  final_bound_id_connection_to_the_right);
23895 
23896  // Get the number of final sorted nodes
23897  const unsigned n_final_sorted_nodes = final_sorted_nodes_pt.size();
23898 
23899  // Loop over the list of final sorted nodes
23900  for (unsigned i = 0; i < n_final_sorted_nodes; i++)
23901  {
23902  // Store the list of nodes that gave rise to the shared
23903  // boundary
23904  local_shd_bnd_id_to_sorted_list_node_pt[local_shd_bnd_id] =
23905  final_sorted_nodes_pt[i];
23906 
23907  // Store the local shared boundary id assigned to the
23908  // elements that will create the shared boundary
23909  proc_local_shared_boundary_id[iproc].push_back(local_shd_bnd_id);
23910 
23911  // Increase the shared boundary id (note that this is only
23912  // used to keep track of the list of nodes that create the
23913  // shared boundaries in the current processor)
23914  local_shd_bnd_id++;
23915 
23916  // Include the vector of elements to the sorted vector
23917  sorted_ele_pt[iproc].push_back(final_boundary_element_pt[i]);
23918 
23919  // Include the vector of face elements to the sorted vector
23920  sorted_face_ele_pt[iproc].push_back(
23921  final_boundary_face_element_pt[i]);
23922 
23923  // Include the vector of elements to the sorted vector
23924  sorted_face_index_ele[iproc].push_back(final_face_index_element[i]);
23925 
23926  // Include the possible associated boundary id to the vector
23927  edge_boundary_id[iproc].push_back(root_edge_bound_id);
23928 
23929  // Include the connection information associated with the
23930  // current set of face elements (that will give rise to a
23931  // shared polyline
23932  // The temporal storage for the boundary connections ids
23933  Vector<int> bnd_connections_ids(2);
23934  bnd_connections_ids[0] = final_bound_id_connection_to_the_left[i];
23935  bnd_connections_ids[1] = final_bound_id_connection_to_the_right[i];
23936  sorted_connection_info[iproc].push_back(bnd_connections_ids);
23937 
23938  } // for (i < n_final_sorted_nodes)
23939 
23940  } // while (nsorted_face_ele < nunsorted_face_ele)
23941 
23942  } // if (iproc != my_rank)
23943 
23944  } // for (iproc < nproc)
23945 
23946  // The time to sort shared boundaries face elements to create a
23947  // continuous representation of the boundary
23948  if (Print_timings_level_load_balance > 2)
23949  {
23950  oomph_info << "CPU for joining shared boundary face elements (load "
23951  "balance) [9.5]: "
23952  << TimingHelpers::timer() - tt_start_join_shd_bnd_face_ele
23953  << std::endl;
23954  }
23955 
23956  // ==================================================================
23957  // END: SORT THE SHARED BOUNDARY FACE ELEMENTS, ADD FACE ELEMENTS TO
23958  // THE LEFT OR RIGHT OF THE ROOT FACE ELEMENT. STOP ADDING WHEN THE
23959  // MOST LEFT OR MOST RIGHT ELEMENT (NODE) IS ALREADY PART OF ANOTHER
23960  // BOUNDARY (THIS MEANS THAT THE SHARED BOUNDARY THAT IS BEING
23961  // CREATED HAS A CONNECTION). ALSO REMEMBER TO CHECK FOR THE CASE
23962  // WHEN THE MOST LEFT OR MOST RIGHT NODE IS A BOUNDARY NODE OF A
23963  // BOUNDARY THAT NO LONGER EXIST IN THE DOMAIN. AT THE END OF THIS
23964  // SECTION WE WILL HAVE THE NUMBER OF SHARED BOUNDARIES OF THIS
23965  // PROCESSOR WITH OTHERS BUT NOT THE GLOBAL SHARED BOUNDARY ID
23966  // ==================================================================
23967 
23968  // ==================================================================
23969  // BEGIN: COMPUTE THE GLOBAL SHARED BOUNDARIES IDS. GATHER THE
23970  // NUMBER OF SHARED BOUNDARIES OF EACH PROCESSOR, THEN A ROOT
23971  // PROCESSOR IS IN CHARGE OF VERIFYING THAT THE SAME NUMBER OF
23972  // SHARED BOUNDARIES HAVE BEEN CREATED BY A PAIR OF PROCESSORS. THE
23973  // ROOT PROCESSOR COMPUTES THE INITIAL GLOBAL SHARED BOUNDARY ID
23974  // BETWEEN EACH PAIR OR PROCESSORS AND SENDS THESE INFO. TO ALL
23975  // PROCESSORS. THE GLOBAL INITIAL AND FINAL SHARED BOUNDARY ID ARE
23976  // ALSO COMPUTED
23977  // ==================================================================
23978 
23979  // Get the time to compute new shared boundaries ids
23980  double tt_start_get_new_shared_boundaries_ids = 0.0;
23981  if (Print_timings_level_load_balance > 2)
23982  {
23983  tt_start_get_new_shared_boundaries_ids = TimingHelpers::timer();
23984  }
23985 
23986  // Get the number of shared boundaries with in each processor
23987  Vector<unsigned> nshared_boundaries_with_processor(nproc);
23988  // Loop over the processors
23989  for (unsigned iproc = 0; iproc < nproc; iproc++)
23990  {
23991  // No shared boundaries with myself
23992  if (iproc != my_rank)
23993  {
23994  // Store the number of shared boundaries of the current
23995  // processor (my_rank) with the iproc processor
23996  nshared_boundaries_with_processor[iproc] =
23997  sorted_face_ele_pt[iproc].size();
23998 
23999  } // if (iproc != my_rank)
24000 
24001  } // for (iproc < nproc)
24002 
24003  // Each processor sends the number of shared boundaries that it has
24004  // with in each other processor to the "root_processor" which will
24005  // be in charge of checking and computing the global shared
24006  // boundaries ids
24007  const unsigned root_processor = 0;
24008 
24009  // Get the communicator of the mesh
24010  OomphCommunicator* comm_pt = this->communicator_pt();
24011 
24012  // Container where to store the info. received from other processor
24013  // in root. It receives from all processors the number of shared
24014  // boundaries that each one has with any other processor
24015  Vector<unsigned> flat_unsigned_root_received_data(nproc * nproc);
24016 
24017  // Gather the info. in the "root_processor"
24018  MPI_Gather(&nshared_boundaries_with_processor[0], // Info. sent from
24019  // each processor
24020  nproc, // Total number of data to send from each
24021  // processor
24022  MPI_UNSIGNED,
24023  &flat_unsigned_root_received_data[0], // Container where
24024  // to receive the
24025  // info. from all
24026  // the processors
24027  nproc, // Number of data to receive from each processor
24028  MPI_UNSIGNED,
24029  root_processor, // The processor that receives all the
24030  // info.
24031  comm_pt->mpi_comm());
24032 
24033  // Container where root store the info. that will be sent back to
24034  // all processor, because root performs a Broadcast operation then
24035  // the info. is received in the same container
24036  Vector<unsigned> flat_unsigned_root_send_receive_data;
24037 
24038  // Compute the new initial and final shared boundary id (they are
24039  // based on the global number of shared boundaries)
24040  unsigned new_initial_shared_boundary_id = 0;
24041  unsigned new_final_shared_boundary_id = 0;
24042 
24043  // Compute the boundaries ids for the shared boundaries
24044  if (my_rank == root_processor)
24045  {
24046  // Change the representation of the data received from all
24047  // processors to a matrix representation for ease access
24048  Vector<Vector<unsigned>> root_nshared_bound_proc_with_proc(nproc);
24049  // Loop over the processors and get the number of shared
24050  // boundaries of processor iproc with jproc
24051  for (unsigned iproc = 0; iproc < nproc; iproc++)
24052  {
24053  // Resize the vector to store the data
24054  root_nshared_bound_proc_with_proc[iproc].resize(nproc);
24055  // Loop over the processors and get the number of shared
24056  // boundaries of processor iproc with jproc
24057  for (unsigned jproc = 0; jproc < nproc; jproc++)
24058  {
24059  root_nshared_bound_proc_with_proc[iproc][jproc] =
24060  flat_unsigned_root_received_data[(iproc * nproc) + jproc];
24061 
24062  } // for (jproc < nproc)
24063 
24064  } // for (iproc < nproc)
24065 
24066 #ifdef PARANOID
24067  // Check that the same number of boundaries are shared by two
24068  // specific processors
24069  for (unsigned iproc = 0; iproc < nproc; iproc++)
24070  {
24071  for (unsigned jproc = 0; jproc < iproc; jproc++)
24072  {
24073  if (root_nshared_bound_proc_with_proc[iproc][jproc] !=
24074  root_nshared_bound_proc_with_proc[jproc][iproc])
24075  {
24076  std::ostringstream error_stream;
24077  error_stream
24078  << "ROOT PROCESSOR ERROR\n\n"
24079  << "The number of shared boundaries between processor (" << iproc
24080  << ") and (" << jproc << ") is not the same:\n"
24081  << "Shared boundaries of processor (" << iproc
24082  << ") with processor (" << jproc << "): ("
24083  << root_nshared_bound_proc_with_proc[iproc][jproc] << ")\n"
24084  << "Shared boundaries of processor (" << jproc
24085  << ") with processor (" << iproc << "): ("
24086  << root_nshared_bound_proc_with_proc[jproc][iproc] << ")\n\n";
24087  throw OomphLibError(error_stream.str(),
24088  OOMPH_CURRENT_FUNCTION,
24089  OOMPH_EXCEPTION_LOCATION);
24090 
24091  } // The number of shared boundaries between processors
24092  // "iproc" and "jproc" is not the same
24093 
24094  } // for (jproc < iproc)
24095 
24096  } // for (iproc < nproc)
24097 #endif
24098 
24099  // The enumeration of the shared boundaries starts from the lowest
24100  // processor number to the highest processor number
24101 
24102  // Two processors share the same boundaries ids, the lowest
24103  // processor number is the one in charge of computing the shared
24104  // boundaries ids
24105  Vector<Vector<unsigned>> start_shared_bound_id_proc_with_proc(nproc);
24106  // Resize the vector, we can not do it when storing the
24107  // info. because of the strategy to save the info.
24108  for (unsigned iproc = 0; iproc < nproc; iproc++)
24109  {
24110  start_shared_bound_id_proc_with_proc[iproc].resize(nproc);
24111  }
24112 
24113  // The shared boundaries ids start from the current number of
24114  // original boundaries
24115  unsigned shared_bound_id = this->nboundary();
24116 
24117  // Set the new initial shared boundary id
24118  new_initial_shared_boundary_id = shared_bound_id;
24119 
24120  // Assign the global shared boundary id for the shared boundaries
24121  for (unsigned iproc = 0; iproc < nproc; iproc++)
24122  {
24123  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
24124  {
24125  // Are there shared boundaries between the pair of processors
24126  if (root_nshared_bound_proc_with_proc[iproc][jproc] > 0)
24127  {
24128  // Set the start boundary id of processor "iproc" with
24129  // processor "jproc" and viceversa
24130  start_shared_bound_id_proc_with_proc[iproc][jproc] =
24131  shared_bound_id;
24132  start_shared_bound_id_proc_with_proc[jproc][iproc] =
24133  shared_bound_id;
24134  // Increase the shared boundary id counter with as many
24135  // shared boundaries there are between the iproc and jproc
24136  // processor
24137  shared_bound_id += root_nshared_bound_proc_with_proc[iproc][jproc];
24138  } // if (root_nshared_bound_proc_with_proc[iproc][jproc] > 0)
24139 
24140  } // for (jproc < iproc)
24141 
24142  } // for (iproc < nproc)
24143 
24144  // Set the new final shared boundary id
24145  new_final_shared_boundary_id = shared_bound_id;
24146 
24147  // Prepare the info. to send back to each processor
24148  Vector<unsigned> send_start_shared_bound_id_proc_with_proc(nproc * nproc);
24149 
24150  // Copy the info. to the storage to send the info. back to other
24151  // processors
24152  for (unsigned iproc = 0; iproc < nproc; iproc++)
24153  {
24154  for (unsigned jproc = 0; jproc < nproc; jproc++)
24155  {
24156  // Get the initial shared boundary id between each pair of
24157  // processors (iproc, jproc)
24158  const unsigned initial_shd_bnd_id =
24159  start_shared_bound_id_proc_with_proc[iproc][jproc];
24160  flat_unsigned_root_send_receive_data.push_back(initial_shd_bnd_id);
24161 
24162  // .. then copy the number of shared boundaries that there are
24163  // between processor iproc and jproc
24164  const unsigned nshared_bnd_iproc_jproc =
24165  root_nshared_bound_proc_with_proc[iproc][jproc];
24166  flat_unsigned_root_send_receive_data.push_back(
24167  nshared_bnd_iproc_jproc);
24168 
24169  } // for (jproc < nproc)
24170 
24171  } // for (iproc < nproc)
24172 
24173  // .. at the end of the data to send include the global initial
24174  // shared boundary id
24175  flat_unsigned_root_send_receive_data.push_back(
24176  new_initial_shared_boundary_id);
24177 
24178  // ... and the global final shared boundary id
24179  flat_unsigned_root_send_receive_data.push_back(
24180  new_final_shared_boundary_id);
24181 
24182  } // if (my_rank == root_processor)
24183 
24184  // Send the initial shared boundaries ids and the number of shared
24185  // boundaries between all procesors to all processors. All
24186  // processors need to know this info.
24187 
24188  // The number of data that will be sent by root to other processors
24189  // and the number of data that other processors receive from root,
24190  // it is the same because it is performed via a Broadcast
24191  unsigned root_ndata_sent_to_all_proc =
24192  flat_unsigned_root_send_receive_data.size();
24193 
24194  MPI_Bcast(&root_ndata_sent_to_all_proc, // Data to send
24195  1,
24196  MPI_UNSIGNED,
24197  root_processor,
24198  comm_pt->mpi_comm());
24199 
24200  // Resize the container if this is a processor that receives data
24201  if (my_rank != root_processor)
24202  {
24203  flat_unsigned_root_send_receive_data.resize(root_ndata_sent_to_all_proc);
24204  }
24205 
24206  // Send back the start boundaries ids for the shared boundaries
24207  // Scatter the info. from the "root_processor"
24208  MPI_Bcast(&flat_unsigned_root_send_receive_data[0], // Info. sent to
24209  // each
24210  // processor
24211  root_ndata_sent_to_all_proc, // Total number of data to
24212  // send to each processor
24213  MPI_UNSIGNED,
24214  root_processor, // The processor that sends all the info.
24215  comm_pt->mpi_comm());
24216 
24217  // The container to store the initial shared boundaries ids between
24218  // each pair of processors
24219  Vector<Vector<unsigned>> initial_shared_bound_id_proc_with_proc(nproc);
24220 
24221  // All processors need to know how many shared boundaries there are
24222  // between each pair of processors
24223 
24224  // The number of shared boundaries between each pair of processors
24225  Vector<Vector<unsigned>> nshared_bound_proc_with_proc(nproc);
24226 
24227  unsigned iflat_counter = 0;
24228  // Fill the containers with the received info. from root processor
24229  for (unsigned iproc = 0; iproc < nproc; iproc++)
24230  {
24231  // Resize the containers
24232  initial_shared_bound_id_proc_with_proc[iproc].resize(nproc);
24233  nshared_bound_proc_with_proc[iproc].resize(nproc);
24234 
24235  // Loop over the processors
24236  for (unsigned jproc = 0; jproc < nproc; jproc++)
24237  {
24238  // Get the initial shared boundary id between each pair of
24239  // processors (iproc, jproc)
24240  initial_shared_bound_id_proc_with_proc[iproc][jproc] =
24241  flat_unsigned_root_send_receive_data[iflat_counter++];
24242 
24243  // .. and copy the number of shared boundaries that there are
24244  // between processor iproc and jproc
24245  nshared_bound_proc_with_proc[iproc][jproc] =
24246  flat_unsigned_root_send_receive_data[iflat_counter++];
24247 
24248  } // for (jproc < nproc)
24249 
24250  } // for (iproc < nproc)
24251 
24252  // Read the new initial shared boundary id
24253  new_initial_shared_boundary_id =
24254  flat_unsigned_root_send_receive_data[root_ndata_sent_to_all_proc - 2];
24255 
24256  // Read the new final shared boundary id
24257  new_final_shared_boundary_id =
24258  flat_unsigned_root_send_receive_data[root_ndata_sent_to_all_proc - 1];
24259 
24260  // The time to compute new shared boundaries ids
24261  if (Print_timings_level_load_balance > 2)
24262  {
24263  oomph_info
24264  << "CPU for computing new shared boundaries ids (load balance) [9.6]: "
24265  << TimingHelpers::timer() - tt_start_get_new_shared_boundaries_ids
24266  << std::endl;
24267  }
24268 
24269  // ==================================================================
24270  // END: COMPUTE THE GLOBAL SHARED BOUNDARIES IDS. GATHER THE NUMBER
24271  // OF SHARED BOUNDARIES OF EACH PROCESSOR, THEN A ROOT PROCESSOR IS
24272  // IN CHARGE OF VERIFYING THAT THE SAME NUMBER OF SHARED BOUNDARIES
24273  // HAVE BEEN CREATED BY A PAIR OF PROCESSORS. THE ROOT PROCESSOR
24274  // COMPUTES THE INITIAL GLOBAL SHARED BOUNDARY ID BETWEEN EACH PAIR
24275  // OR PROCESSORS AND SENDS THESE INFO. TO ALL PROCESSORS. THE GLOBAL
24276  // INITIAL AND FINAL SHARED BOUNDARY ID ARE ALSO COMPUTED
24277  // ==================================================================
24278 
24279  // ==================================================================
24280  // BEGIN: CREATE THE NEW SHARED BOUNDARIES. DELETE THE OLD SHARED
24281  // BOUNDARIES INFORMATION. FILL THE DATA STRUCTURES WITH THE NEW
24282  // SHARED BOUNDARIES INFO.
24283  // ==================================================================
24284 
24285  // Get the time to create new shared boundaries representations
24286  double tt_start_create_new_shared_boundaries_polylines = 0.0;
24287  if (Print_timings_level_load_balance > 2)
24288  {
24289  tt_start_create_new_shared_boundaries_polylines = TimingHelpers::timer();
24290  }
24291 
24292  // Create the shared boundaries and establish all the related info.
24293  // - Create Polylines
24294  // - Store shared boundary elements
24295  // - Fill data structures to know which shared boundaries belong to
24296  // which processor
24297 
24298  // Resize the shared polylines container
24299  this->flush_shared_boundary_polyline_pt();
24300  this->Shared_boundary_polyline_pt.resize(nproc);
24301 
24302  // Resize for the boundaries ids shared with all processors
24303  this->Shared_boundaries_ids.clear();
24304  this->Shared_boundaries_ids.resize(nproc);
24305  for (unsigned iproc = 0; iproc < nproc; iproc++)
24306  {
24307  this->Shared_boundaries_ids[iproc].clear();
24308  this->Shared_boundaries_ids[iproc].resize(nproc);
24309  } // for (iproc < nproc)
24310 
24311  // Clear data
24312  this->Shared_boundary_from_processors.clear();
24313  this->Shared_boundary_overlaps_internal_boundary.clear();
24314  this->Boundary_was_splitted.clear();
24315  this->Boundary_subpolylines.clear();
24316  this->Boundary_marked_as_shared_boundary.clear();
24317 
24318  // Flush data
24319  this->flush_shared_boundary_element();
24320  this->flush_face_index_at_shared_boundary();
24321  this->flush_shared_boundary_node();
24322  this->flush_sorted_shared_boundary_node();
24323 
24324  // Store the old local inital shared boundary id (used to map from
24325  // local shared boundary id to global shared boundary id)
24326  const unsigned old_local_shd_bnd_id = this->Initial_shared_boundary_id;
24327 
24328  // Update the initial and final shared boundary id
24329  this->Initial_shared_boundary_id = new_initial_shared_boundary_id;
24330  this->Final_shared_boundary_id = new_final_shared_boundary_id;
24331 
24332  // Storage for the new created polylines between the current
24333  // processor (my_rank) and the other processors, unsorted polylines
24334  Vector<TriangleMeshPolyLine*> unsorted_polylines_pt;
24335 
24336  // Map to get the global shared boundary id from the local shared
24337  // boundary id. Note that this is only used to get the global shared
24338  // boundary id when the shared boundary that is being created has
24339  // connections
24340  std::map<unsigned, unsigned> local_to_global_shd_bnd_id;
24341 
24342  // Each processor knows the boundaries ids for each of the shared
24343  // boundaries it has, establish that info. in the proper containers
24344  // Additionally, store the shared boundaries of ALL processors with
24345  // ALL processors, but only create the shared boundaries (and their
24346  // respective polylines) of the current processor (my_rank)
24347  for (unsigned iproc = 0; iproc < nproc; iproc++)
24348  {
24349  // Avoid creating double shared boundaries, the shared boundaries
24350  // created between processor "iproc" and processor "jproc" are the
24351  // same than those created between processor "jproc" and processor
24352  // "iproc"
24353  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
24354  {
24355  // If we are working with the current processor (my_rank) then
24356  // create the shared boundaries, if that is not the case then
24357  // only fill the info. on the proper containers
24358  if (iproc == my_rank || jproc == my_rank)
24359  {
24360  // Check the condition that made it get here
24361  unsigned ref_proc = 0;
24362  if (iproc == my_rank)
24363  {
24364  ref_proc = jproc;
24365  }
24366  else if (jproc == my_rank)
24367  {
24368  ref_proc = iproc;
24369  }
24370 
24371  // Get the number of shared boundaries between processor iproc
24372  // and processor jproc
24373  const unsigned nshared_bound_iproc_jproc =
24374  nshared_bound_proc_with_proc[iproc][jproc];
24375 
24376  // Loop over the number of shared boundaries
24377  for (unsigned counter = 0; counter < nshared_bound_iproc_jproc;
24378  counter++)
24379  {
24380  // Compute the shared boundary id for the shared boundary
24381  const unsigned shd_bnd_id =
24382  initial_shared_bound_id_proc_with_proc[iproc][jproc] + counter;
24383  // Set up the shared boundaries between "iproc" (my_rank)
24384  // and "jproc"
24385  this->Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
24386  this->Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
24387 
24388  // Specify the processors involved for the creation of the
24389  // shared boundary
24390  Vector<unsigned> processors(2);
24391  processors[0] = iproc;
24392  processors[1] = jproc;
24393  this->Shared_boundary_from_processors[shd_bnd_id] = processors;
24394 
24395  // Get the possible root edge id associated to the shared
24396  // boundary (useful when the shared boundary overlaps an
24397  // original boundary)
24398  int root_edge_bound_id = edge_boundary_id[ref_proc][counter];
24399  // Check if the shared boundary is overlapping (or is part)
24400  // of an internal boundary
24401  if (root_edge_bound_id != -1)
24402  {
24403  // If the shared boundary is part of an internal boundary then
24404  // mark the shared boundary
24405  this->Shared_boundary_overlaps_internal_boundary[shd_bnd_id] =
24406  static_cast<unsigned>(root_edge_bound_id);
24407  } // if (root_edge_bound_id != -1)
24408 
24409  // Storing for the nodes of the polyline (these are different
24410  // from the nodes on the face elements -- it is actually a
24411  // sub-set -- since the polyline is created from the first and
24412  // last nodes on the face elements)
24413  Vector<Node*> node_pt_to_create_shared_polyline;
24414 
24415  // Add the first node for the very first face element. In
24416  // the loop we will only add the last node of the face
24417  // element
24418  FiniteElement* first_face_ele_pt =
24419  sorted_face_ele_pt[ref_proc][counter][0];
24420 
24421  // Get the number of nodes on the first face element
24422  const unsigned first_face_ele_nnodes = first_face_ele_pt->nnode();
24423  if (!is_inverted[first_face_ele_pt])
24424  {
24425  // Get the first node
24426  Node* first_node_pt = first_face_ele_pt->node_pt(0);
24427  // Add the node to create the polyline
24428  node_pt_to_create_shared_polyline.push_back(first_node_pt);
24429  // Add the first node to the shared boundary
24430  this->add_shared_boundary_node(shd_bnd_id, first_node_pt);
24431  }
24432  else
24433  {
24434  // Get the first node in the inverted face element
24435  Node* first_node_pt =
24436  first_face_ele_pt->node_pt(first_face_ele_nnodes - 1);
24437  // Add the node to create the polyline
24438  node_pt_to_create_shared_polyline.push_back(first_node_pt);
24439  // Add the first node to the shared boundary
24440  this->add_shared_boundary_node(shd_bnd_id, first_node_pt);
24441  }
24442 
24443  // ... and extract only the last nodes of the face elements
24444  // in the next loop and add them in the vector of nodes to
24445  // create polylines (node_pt_to_create_shared_polyline)
24446 
24447  // Get the number of elements
24448  const unsigned nshared_boundary_elements =
24449  sorted_face_ele_pt[ref_proc][counter].size();
24450 
24451  // Store the shared boundary elements, nodes and get the
24452  // sorted nodes to create the polyline
24453  for (unsigned ie = 0; ie < nshared_boundary_elements; ie++)
24454  {
24455  // Get the bulk element version of the face element
24456  FiniteElement* bulk_ele_pt = sorted_ele_pt[ref_proc][counter][ie];
24457 
24458  // Add the shared boundary element and associate it to the
24459  // "shd_bnd_id"
24460  this->add_shared_boundary_element(shd_bnd_id, bulk_ele_pt);
24461 
24462  // Get the face index from which the face element was
24463  // created from the bulk element
24464  const int face_index =
24465  sorted_face_index_ele[ref_proc][counter][ie];
24466 
24467  // Add the face index to the face indexes of the shared
24468  // boundary
24469  this->add_face_index_at_shared_boundary(shd_bnd_id, face_index);
24470 
24471  // Get the face element to obtain the last node
24472  FiniteElement* face_ele_pt =
24473  sorted_face_ele_pt[ref_proc][counter][ie];
24474 
24475  // Get the number of nodes
24476  const unsigned nnodes = face_ele_pt->nnode();
24477  if (!is_inverted[face_ele_pt])
24478  {
24479  // We have already added the first node, then start from
24480  // the second one
24481  for (unsigned n = 1; n < nnodes; n++)
24482  {
24483  // Get the node to be added
24484  Node* node_pt = face_ele_pt->node_pt(n);
24485  // Add the node and associate it to the shared boundary
24486  this->add_shared_boundary_node(shd_bnd_id, node_pt);
24487  } // for (n < nnodes)
24488 
24489  // Add the last node of the face element to the vector of
24490  // nodes to create the polyline
24491  // Get the last node
24492  Node* last_node_pt = face_ele_pt->node_pt(nnodes - 1);
24493  node_pt_to_create_shared_polyline.push_back(last_node_pt);
24494  } // if (!is_inverted[face_ele_pt])
24495  else
24496  {
24497  // We have already added the first node, then start from
24498  // the second one (in reverse order)
24499  for (int n = nnodes - 2; n >= 0; n--)
24500  {
24501  // Get the node to be added
24502  Node* node_pt = face_ele_pt->node_pt(n);
24503  // Add the node and associate it to the shared boundary
24504  this->add_shared_boundary_node(shd_bnd_id, node_pt);
24505  } // for (n < nnodes)
24506 
24507  // Add the last node of the face element to the vector of
24508  // nodes to create the polyline
24509  // Get the last node
24510  Node* last_node_pt = face_ele_pt->node_pt(0);
24511  node_pt_to_create_shared_polyline.push_back(last_node_pt);
24512 
24513  } // else if (!is_inverted[face_ele_pt])
24514 
24515  } // for (ie < nshared_boundary_elements)
24516 
24517  // The number of nodes for the shared boundary polyline
24518  const unsigned nnodes_to_create_shared_boundary =
24519  node_pt_to_create_shared_polyline.size();
24520 
24521  // Get the vertices that create the shared boundary polyline
24522  Vector<Vector<double>> vertices(nnodes_to_create_shared_boundary);
24523  for (unsigned n = 0; n < nnodes_to_create_shared_boundary; n++)
24524  {
24525  vertices[n].resize(2);
24526  // Get the node
24527  Node* tmp_node_pt = node_pt_to_create_shared_polyline[n];
24528  // Get the vertices
24529  vertices[n][0] = tmp_node_pt->x(0);
24530  vertices[n][1] = tmp_node_pt->x(1);
24531  } // for (n < nnodes_to_create_shared_boundary)
24532 
24533  // Create the polyline
24534  TriangleMeshPolyLine* polyline_pt =
24535  new TriangleMeshPolyLine(vertices, shd_bnd_id);
24536 
24537  // Updates bnd_id<--->curve section map
24538  this->Boundary_curve_section_pt[shd_bnd_id] = polyline_pt;
24539 
24540  // Add the new created polyline to the list of unsorted
24541  // polylines
24542  unsorted_polylines_pt.push_back(polyline_pt);
24543 
24544  // Mark the polyline for deletion (when calling destructor)
24545  this->Free_curve_section_pt.insert(polyline_pt);
24546 
24547  // Now assign the connection information
24548  // ---------------------------------------------------------
24549  // Get the local shared boundary id associated to the
24550  // elements that gave rise to this shared boundary
24551  const unsigned local_shd_bnd_id =
24552  proc_local_shared_boundary_id[ref_proc][counter];
24553 
24554  // Associate the local shared boundary to the global shared
24555  // boundary
24556  local_to_global_shd_bnd_id[local_shd_bnd_id] = shd_bnd_id;
24557 
24558  // Get the correct shared boundaries ids, from the local
24559  // shared boundaries ids established at the identification
24560  // of the conections
24561 
24562  // Get the local bnd id for the connection to the left
24563  int tmp_bnd_id_connection_to_the_left =
24564  sorted_connection_info[ref_proc][counter][0];
24565  // Get the local bnd id for the connection to the right
24566  int tmp_bnd_id_connection_to_the_right =
24567  sorted_connection_info[ref_proc][counter][1];
24568 
24569  // The global shared boundaries ids for connections to the
24570  // left or right
24571  int bnd_id_connection_to_the_left = -1;
24572  int bnd_id_connection_to_the_right = -1;
24573 
24574  // To the left
24575  // --------------
24576 
24577  // If the connection is with the same shared boundary then
24578  // set the current boundary id
24579  if (tmp_bnd_id_connection_to_the_left == -2)
24580  {
24581  // Set the current shared boundary id
24582  bnd_id_connection_to_the_left = shd_bnd_id;
24583  } // if (tmp_bnd_id_connection_to_the_left == -2)
24584 
24585  // Check if the connection was a stop adding nodes condition
24586  if (tmp_bnd_id_connection_to_the_left == -3)
24587  {
24588  // Set as no connected
24589  bnd_id_connection_to_the_left = -1;
24590  } // if (tmp_bnd_id_connection_to_the_left == -3)
24591 
24592  // There is a connection with another boundary, check if it
24593  // is a shared boundary or an original boundary
24594  if (tmp_bnd_id_connection_to_the_left >=
24595  static_cast<int>(old_local_shd_bnd_id))
24596  {
24597  // The connection is with a shared boundary, get the
24598  // global shared boundary id and set the connection
24599 #ifdef PARANOID
24600  std::map<unsigned, unsigned>::iterator it =
24601  local_to_global_shd_bnd_id.find(
24602  static_cast<unsigned>(tmp_bnd_id_connection_to_the_left));
24603  // If the global shared boundary id was not found we
24604  // are in trouble
24605  if (it == local_to_global_shd_bnd_id.end())
24606  {
24607  std::stringstream error_message;
24608  error_message
24609  << "The global shared boundary id was not found for\n"
24610  << "the local shared boundary shared with processor ("
24611  << ref_proc << ").\n"
24612  << "This processor: (" << my_rank << ")\n"
24613  << "Boundary shared with processor: (" << ref_proc << ")\n"
24614  << "Local shared boundary: ("
24615  << tmp_bnd_id_connection_to_the_left << ")\n";
24616  throw OomphLibError(error_message.str(),
24617  OOMPH_CURRENT_FUNCTION,
24618  OOMPH_EXCEPTION_LOCATION);
24619  } // if (it==local_to_global_shd_bnd_id.end())
24620 #endif
24621 
24622  // Get the global shared boundary id
24623  bnd_id_connection_to_the_left =
24624  local_to_global_shd_bnd_id[static_cast<unsigned>(
24625  tmp_bnd_id_connection_to_the_left)];
24626  }
24627  else
24628  {
24629  // The connection is with an original boundary, copy
24630  // the boundary id
24631  bnd_id_connection_to_the_left = tmp_bnd_id_connection_to_the_left;
24632 
24633  } // else (connection with a shared boundary)
24634 
24635  // To the right
24636  // --------------
24637 
24638  // If the connection is with the same shared boundary then
24639  // set the current boundary id
24640  if (tmp_bnd_id_connection_to_the_right == -2)
24641  {
24642  // Set the current shared boundary id
24643  bnd_id_connection_to_the_right = shd_bnd_id;
24644  } // if (tmp_bnd_id_connection_to_the_right == -2)
24645 
24646  // Check if the connection was a stop adding nodes condition
24647  if (tmp_bnd_id_connection_to_the_right == -3)
24648  {
24649  // Set as no connected
24650  bnd_id_connection_to_the_right = -1;
24651  } // if (tmp_bnd_id_connection_to_the_right == -3)
24652 
24653  // There is a connection with another boundary, check if it
24654  // is a shared boundary or an original boundary
24655  if (tmp_bnd_id_connection_to_the_right >=
24656  static_cast<int>(old_local_shd_bnd_id))
24657  {
24658  // The connection is with a shared boundary, get the
24659  // global shared boundary id and set the connection
24660 #ifdef PARANOID
24661  std::map<unsigned, unsigned>::iterator it =
24662  local_to_global_shd_bnd_id.find(
24663  static_cast<unsigned>(tmp_bnd_id_connection_to_the_right));
24664  // If the global shared boundary id was not found we
24665  // are in trouble
24666  if (it == local_to_global_shd_bnd_id.end())
24667  {
24668  std::stringstream error_message;
24669  error_message
24670  << "The global shared boundary id was not found for\n"
24671  << "the local shared boundary shared with processor ("
24672  << ref_proc << ").\n"
24673  << "This processor: (" << my_rank << ")\n"
24674  << "Boundary shared with processor: (" << ref_proc << ")\n"
24675  << "Local shared boundary: ("
24676  << tmp_bnd_id_connection_to_the_right << ")\n";
24677  throw OomphLibError(error_message.str(),
24678  OOMPH_CURRENT_FUNCTION,
24679  OOMPH_EXCEPTION_LOCATION);
24680  } // if (it==local_to_global_shd_bnd_id.end())
24681 #endif
24682  // Get the global shared boundary id
24683  bnd_id_connection_to_the_right =
24684  local_to_global_shd_bnd_id[static_cast<unsigned>(
24685  tmp_bnd_id_connection_to_the_right)];
24686  }
24687  else
24688  {
24689  // The connection is with an original boundary, copy the
24690  // boundary id
24691  bnd_id_connection_to_the_right =
24692  tmp_bnd_id_connection_to_the_right;
24693 
24694  } // else (connection with a shared boundary)
24695 
24696  // --------------------------------
24697  // Set the connection to the left
24698  if (bnd_id_connection_to_the_left != -1)
24699  {
24700  // Get the unsigned version of the boundary id to the left
24701  const unsigned ubnd_id_connection_to_the_left =
24702  static_cast<unsigned>(bnd_id_connection_to_the_left);
24703  // Set the initial vertex as connected
24704  polyline_pt->set_initial_vertex_connected();
24705  // Set the initial vertex connected boundary id
24706  polyline_pt->initial_vertex_connected_bnd_id() =
24707  ubnd_id_connection_to_the_left;
24708  // Set the chunk number to zero
24709  polyline_pt->initial_vertex_connected_n_chunk() = 0;
24710 
24711  } // if (bnd_id_connection_to_the_left != -1)
24712 
24713  // ---------------------------------
24714  // Set the connection to the right
24715  if (bnd_id_connection_to_the_right != -1)
24716  {
24717  // Get the unsigned version of the boundary id to the
24718  // right
24719  const unsigned ubnd_id_connection_to_the_right =
24720  static_cast<unsigned>(bnd_id_connection_to_the_right);
24721  // Set the final vertex as connected
24722  polyline_pt->set_final_vertex_connected();
24723  // Set the final vertex connected boundary id
24724  polyline_pt->final_vertex_connected_bnd_id() =
24725  ubnd_id_connection_to_the_right;
24726  // Set the chunk number to zero
24727  polyline_pt->final_vertex_connected_n_chunk() = 0;
24728 
24729  } // if (bnd_id_connection_to_the_right != -1)
24730 
24731  } // for (counter < nshared_bound_iproc_jproc)
24732 
24733  } // if (iproc == my_rank || jproc == my_rank)
24734  else
24735  {
24736  // We are not working with the current processor, then we only
24737  // need to fill the containers
24738 
24739  // Get the number of shared boundaries between processor iproc
24740  // and processor jproc
24741  const unsigned nshared_bound_iproc_jproc =
24742  nshared_bound_proc_with_proc[iproc][jproc];
24743  // Loop over the number of shared boundaries
24744  for (unsigned counter = 0; counter < nshared_bound_iproc_jproc;
24745  counter++)
24746  {
24747  // Compute the shared boundary id for the shared boundary
24748  const unsigned shd_bnd_id =
24749  initial_shared_bound_id_proc_with_proc[iproc][jproc] + counter;
24750 
24751  // Set up the shared boundaries between "iproc" and "jproc"
24752  this->Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
24753  this->Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
24754 
24755  // Specify the processors involved for the creation of the
24756  // shared boundary
24757  Vector<unsigned> processors(2);
24758  processors[0] = iproc;
24759  processors[1] = jproc;
24760  this->Shared_boundary_from_processors[shd_bnd_id] = processors;
24761 
24762  } // for (counter < nshared_bound_iproc_jproc)
24763 
24764  } // else if (iproc == my_rank || jproc == my_rank)
24765 
24766  } // for (jproc < nproc)
24767 
24768  } // for (iproc < nproc)
24769 
24770  // Get the time to create new shared boundaries representations
24771  if (Print_timings_level_load_balance > 2)
24772  {
24773  oomph_info << "CPU for creating new shared boundaries representations "
24774  "(load balance) [9.7]: "
24775  << TimingHelpers::timer() -
24776  tt_start_create_new_shared_boundaries_polylines
24777  << std::endl;
24778  }
24779 
24780  // ==================================================================
24781  // END: CREATE THE NEW SHARED BOUNDARIES. DELETE THE OLD SHARED
24782  // BOUNDARIES INFORMATION. FILL THE DATA STRUCTURES WITH THE NEW
24783  // SHARED BOUNDARIES INFO.
24784  // ==================================================================
24785 
24786  // ==================================================================
24787  // BEGIN: SORT THE SHARED BOUNDARIES AND CREATE SHARED CURVES (A SET
24788  // OF CONTIGUOUS SHARED POLYLINES). STORE THEM IN THE GLOBAL
24789  // CONTAINER FOR SHARED BOUNDARIES. FREE MEMORY BY DELETING FACE
24790  // ELEMENTS
24791  // ==================================================================
24792 
24793  // Get the time to create the new shared curves
24794  double tt_start_create_new_shared_curves = 0.0;
24795  if (Print_timings_level_load_balance > 2)
24796  {
24797  tt_start_create_new_shared_curves = TimingHelpers::timer();
24798  }
24799 
24800  // Sort the polylines and find if they create a contiguous open
24801  // curve
24802  if (unsorted_polylines_pt.size() > 0)
24803  {
24804  // Now that we have all the new unsorted polylines on "my_rank"x
24805  // processor it is time to sort them so they be all contiguous
24806  this->sort_polylines_helper(unsorted_polylines_pt,
24807  this->Shared_boundary_polyline_pt[my_rank]);
24808  }
24809 
24810  // Free the memory allocated for the face elements
24811  for (unsigned iproc = 0; iproc < nproc; iproc++)
24812  {
24813  const unsigned nface_ele = unsorted_face_ele_pt[iproc].size();
24814  for (unsigned e = 0; e < nface_ele; e++)
24815  {
24816  delete unsorted_face_ele_pt[iproc][e];
24817  unsorted_face_ele_pt[iproc][e] = 0;
24818  } // for (e < nface_ele)
24819 
24820  } // for (iproc < nproc)
24821 
24822  // The time to create the new shared curves
24823  if (Print_timings_level_load_balance > 2)
24824  {
24825  oomph_info
24826  << "CPU for creating the new shared curves (load balance) [9.8]: "
24827  << TimingHelpers::timer() - tt_start_create_new_shared_curves
24828  << std::endl;
24829  }
24830 
24831  // ==================================================================
24832  // END: SORT THE SHARED BOUNDARIES AND CREATE SHARED CURVES (A SET
24833  // OF CONTIGUOUS SHARED POLYLINES). STORE THEM IN THE GLOBAL
24834  // CONTAINER FOR SHARED BOUNDARIES. FREE MEMORY BY DELETING FACE
24835  // ELEMENTS
24836  // ==================================================================
24837  }
24838 
24839  //======================================================================
24840  // Computes the degree of the nodes on the shared boundaries, the
24841  // degree of the node is computed from the global graph created by the
24842  // shared boundaries of all processors
24843  //======================================================================
24844  template<class ELEMENT>
24846  Vector<Vector<FiniteElement*>>& unsorted_face_ele_pt,
24847  std::map<Node*, unsigned>& global_node_degree)
24848  {
24849  // Get the rank and number of processors
24850  const unsigned nproc = this->communicator_pt()->nproc();
24851  const unsigned my_rank = this->communicator_pt()->my_rank();
24852 
24853  // Store a temporary sorting of the nodes, starting from the
24854  // lower-left position
24855  Vector<Vector<Node*>> tmp_sorted_shared_node_pt(nproc);
24856 
24857  // Store the alias of the node, it may be shared by more than two
24858  // processors, they should know that the node is the same
24859  // [0] iproc, processor with which the current processor shared the node
24860  // [1] node #, number of node in the number of nodes shared with iproc
24861  // processor
24862  std::map<Node*, Vector<Vector<unsigned>>> node_alias;
24863 
24864  // Stores the local adjacency matrix
24865  // (nproc*n_shared_nodes*n_shared_nodes)
24866  Vector<Vector<Vector<unsigned>>> local_adjacency_matrix(nproc);
24867 
24868  // Sort the nodes and create the adjacency matrix of each sub-graph
24869  // created by the shared edges
24870  create_adjacency_matrix_new_shared_edges_helper(unsorted_face_ele_pt,
24871  tmp_sorted_shared_node_pt,
24872  node_alias,
24873  local_adjacency_matrix);
24874 
24875  // Prepare the info. to be sent to the root processor, which will be
24876  // in charge of updating the nodes degree by combining the info. of
24877  // all the processors
24878 
24879  // The flat package with the info. to send to root
24880  Vector<unsigned> package_unsigned_send_data_to_root;
24881 
24882  // Encode the info. that will be sent to the root processor
24883 
24884  // Loop over the temporary sorted nodes between each pair of
24885  // processors
24886  for (unsigned iproc = 0; iproc < nproc; iproc++)
24887  {
24888  // Send the processor index
24889  package_unsigned_send_data_to_root.push_back(iproc);
24890 
24891  // Get the number of nodes shared between the processors
24892  const unsigned n_nodes = tmp_sorted_shared_node_pt[iproc].size();
24893 
24894  // Send the number of nodes shared with the iproc processor
24895  package_unsigned_send_data_to_root.push_back(n_nodes);
24896 
24897  // Loop over the nodes
24898  for (unsigned ishd = 0; ishd < n_nodes; ishd++)
24899  {
24900  // Get the node
24901  Node* shd_node_pt = tmp_sorted_shared_node_pt[iproc][ishd];
24902 
24903  // Get the alias info.
24904  Vector<Vector<unsigned>> alias_node_info = node_alias[shd_node_pt];
24905 
24906  // Get the number of alias for the node
24907  const unsigned n_alias = alias_node_info.size();
24908 
24909  // Send the number of alias assigned to the node
24910  package_unsigned_send_data_to_root.push_back(n_alias);
24911 
24912  // Loop over the alias to include them in the package
24913  for (unsigned i = 0; i < n_alias; i++)
24914  {
24915  // Send the alias info.
24916  // The current processor
24917  package_unsigned_send_data_to_root.push_back(alias_node_info[i][0]);
24918  // The prociesso with which is shared
24919  package_unsigned_send_data_to_root.push_back(alias_node_info[i][1]);
24920  // The index of the node
24921  package_unsigned_send_data_to_root.push_back(alias_node_info[i][2]);
24922  } // for (i < n_alias)
24923 
24924  } // for (ishd < n_nodes)
24925 
24926  // Now send the adjacency matrix
24927  for (unsigned i = 0; i < n_nodes; i++)
24928  {
24929  for (unsigned j = 0; j < n_nodes; j++)
24930  {
24931  // Package the adjacency matrix
24932  package_unsigned_send_data_to_root.push_back(
24933  local_adjacency_matrix[iproc][i][j]);
24934 
24935  } // for (j < n_nodes)
24936 
24937  } // for (i < n_nodes)
24938 
24939  } // for (iproc < nproc)
24940 
24941  // Define the root processor
24942  const unsigned root_processor = 0;
24943 
24944  // Get the communicator of the mesh
24945  OomphCommunicator* comm_pt = this->communicator_pt();
24946 
24947  // Number of data send. from this processor to root processor
24948  unsigned n_unsigned_data_send_to_root =
24949  package_unsigned_send_data_to_root.size();
24950 
24951  // Store the number of data to receive from each processor in root
24952  Vector<int> n_unsigned_data_received_in_root(nproc, 0);
24953 
24954  // Send the number of data that each processor will send to root
24955  // Gather the info. in the "root_processor"
24956  MPI_Gather(&n_unsigned_data_send_to_root, // Info. sent from
24957  // each processor
24958  1, // Total number of data to send from each processor
24959  MPI_UNSIGNED,
24960  &n_unsigned_data_received_in_root[0], // Container where
24961  // to receive the
24962  // info. from all
24963  // the processors
24964  1, // Number of data to receive from each processor
24965  MPI_UNSIGNED,
24966  root_processor, // The processor that receives all the
24967  // info.
24968  comm_pt->mpi_comm());
24969 
24970  // Compute the total number of data to receive from all processors
24971  unsigned n_unsigned_total_data_receive_in_root = 0;
24972  for (unsigned iproc = 0; iproc < nproc; iproc++)
24973  {
24974  // Add the number of data to receive from each processor
24975  n_unsigned_total_data_receive_in_root +=
24976  n_unsigned_data_received_in_root[iproc];
24977  }
24978 
24979  // Compute the offsets from each processor
24980  Vector<int> root_unsigned_offsets_receive(nproc, 0);
24981  root_unsigned_offsets_receive[0] = 0;
24982  for (unsigned iproc = 1; iproc < nproc; iproc++)
24983  {
24984  // Compute the offset to store the values received from each
24985  // processor
24986  root_unsigned_offsets_receive[iproc] =
24987  root_unsigned_offsets_receive[iproc - 1] +
24988  n_unsigned_data_received_in_root[iproc - 1];
24989  }
24990 
24991  // Create at least one entry so we don't get a seg fault below
24992  if (package_unsigned_send_data_to_root.size() == 0)
24993  {
24994  package_unsigned_send_data_to_root.resize(1);
24995  }
24996 
24997  // Vector where to receive the data sent from each processor
24998  Vector<unsigned> package_unsigned_data_received_root(
24999  n_unsigned_total_data_receive_in_root);
25000  if (my_rank != root_processor)
25001  {
25002  // Create at least one entry so we don't get a seg fault below
25003  if (package_unsigned_data_received_root.size() == 0)
25004  {
25005  package_unsigned_data_received_root.resize(1);
25006  }
25007  } // if (my_rank!=root_processor)
25008 
25009  // Gather the info. from all processors
25010  MPI_Gatherv(&package_unsigned_send_data_to_root[0], // Flat package
25011  // to send
25012  // info. from
25013  // each
25014  // processor
25015  n_unsigned_data_send_to_root, // Total number of data to
25016  // send from each
25017  // processor
25018  MPI_UNSIGNED,
25019  &package_unsigned_data_received_root[0], // Container
25020  // where to
25021  // receive the
25022  // info. from
25023  // all the
25024  // processors
25025  &n_unsigned_data_received_in_root[0], // Number of data
25026  // to receive from
25027  // each processor
25028  &root_unsigned_offsets_receive[0], // The offset to
25029  // store the
25030  // info. from each
25031  // processor
25032  MPI_UNSIGNED,
25033  root_processor, // The processor that receives all the
25034  // info.
25035  comm_pt->mpi_comm());
25036 
25037  // Store the info. to be sent by root to other processors
25038  Vector<unsigned> package_unsigned_data_sent_from_root;
25039  // Total data sent to each processor from root
25040  Vector<int> n_unsigned_data_sent_from_root(nproc, 0);
25041 
25042  // The root processor now has all the info. regarding the shared
25043  // nodes and the adjacency matrix of each pair of processors
25044  if (my_rank == root_processor)
25045  {
25046  // Decode the info. received from all processors
25047  // Counter to decode the info.
25048  unsigned decode_counter = 0;
25049 
25050  // Store the local alias of the nodes in each processor
25051  // [x][][][][] iproc
25052  // [][x][][][] jproc
25053  // [][][x][][] inode
25054  // [][][][x][] ialias
25055  // [][][][][x] alias_data
25056  Vector<Vector<Vector<Vector<Vector<unsigned>>>>> local_node_alias(nproc);
25057  // Store the local adjacency matrix of each processor
25058  Vector<Vector<Vector<Vector<unsigned>>>> local_adjacency_matrix(nproc);
25059 
25060  // Loop over all the processors
25061  for (unsigned iproc = 0; iproc < nproc; iproc++)
25062  {
25063  local_node_alias[iproc].resize(nproc);
25064 
25065  // Resize the local adjacency matrix to store the info. sent
25066  // from all processors
25067  local_adjacency_matrix[iproc].resize(nproc);
25068 
25069  if (n_unsigned_data_received_in_root[iproc] > 0)
25070  {
25071  // Loop over all the processors to decode the info. received
25072  // from each one
25073  for (unsigned jproc = 0; jproc < nproc; jproc++)
25074  {
25075  // Read the processor number to which the info. correspond
25076  const unsigned read_jproc =
25077  package_unsigned_data_received_root[decode_counter++];
25078 
25079  // The read processor must be the same as the jproc, if that
25080  // is not the case then there is a synchronisation issue
25081  if (read_jproc != jproc)
25082  {
25083  std::ostringstream error_stream;
25084  error_stream
25085  << "The read processor is different from the jproc, this is\n"
25086  << "a synchronisation issue. The data are not read in the\n"
25087  << "sameorder as the were packaged\n"
25088  << "Read processor: (" << read_jproc << ")\n"
25089  << "Current jproc: (" << jproc << ")\n\n";
25090  throw OomphLibError(
25091  error_stream.str(),
25092  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25093  OOMPH_EXCEPTION_LOCATION);
25094  }
25095 
25096  // Read the number of nodes in the shared boundaries between
25097  // iproc and jproc
25098  const unsigned read_n_shd_nodes_iproc_jproc =
25099  package_unsigned_data_received_root[decode_counter++];
25100 
25101  // Resize the container
25102  local_node_alias[iproc][jproc].resize(read_n_shd_nodes_iproc_jproc);
25103 
25104  // Loop over the number of nodes shared between iproc and
25105  // jproc
25106  for (unsigned ishd = 0; ishd < read_n_shd_nodes_iproc_jproc; ishd++)
25107  {
25108  // Read the number of alias of the current ishd node
25109  const unsigned read_n_alias_node_iproc_jproc =
25110  package_unsigned_data_received_root[decode_counter++];
25111 
25112  // Resize the container
25113  local_node_alias[iproc][jproc][ishd].resize(
25114  read_n_alias_node_iproc_jproc);
25115 
25116  for (unsigned ialias = 0; ialias < read_n_alias_node_iproc_jproc;
25117  ialias++)
25118  {
25119  // Resize the container, we know there are three data to
25120  // define the alias of a node
25121  local_node_alias[iproc][jproc][ishd][ialias].resize(3);
25122 
25123  // The 1st processor with which is shared
25124  local_node_alias[iproc][jproc][ishd][ialias][0] =
25125  package_unsigned_data_received_root[decode_counter++];
25126 
25127  // The 2nd processor with which is shared
25128  local_node_alias[iproc][jproc][ishd][ialias][1] =
25129  package_unsigned_data_received_root[decode_counter++];
25130 
25131  // The index of the node in the interaction iproc-jproc
25132  local_node_alias[iproc][jproc][ishd][ialias][2] =
25133  package_unsigned_data_received_root[decode_counter++];
25134 
25135  } // for (ialias < read_n_alias_node_iproc_jproc)
25136 
25137  } // for (ishd < read_n_shd_nodes_iproc_jproc)
25138 
25139  // Resize the local adjacency matrix
25140  local_adjacency_matrix[iproc][jproc].resize(
25141  read_n_shd_nodes_iproc_jproc);
25142  // Read the adjacency matrix sent to root processor
25143  for (unsigned i = 0; i < read_n_shd_nodes_iproc_jproc; i++)
25144  {
25145  // Resize the local adjacency matrix
25146  local_adjacency_matrix[iproc][jproc][i].resize(
25147  read_n_shd_nodes_iproc_jproc);
25148  for (unsigned j = 0; j < read_n_shd_nodes_iproc_jproc; j++)
25149  {
25150  // Read the adjacency matrix entry
25151  local_adjacency_matrix[iproc][jproc][i][j] =
25152  package_unsigned_data_received_root[decode_counter++];
25153  } // for (j < read_n_shd_nodes_iproc_jproc)
25154 
25155  } // for (i < read_n_shd_nodes_iproc_jproc)
25156 
25157  } // for (jproc < nproc)
25158 
25159  } // for (iproc < nproc)
25160 
25161  } // for (iproc < nproc)
25162 
25163 #ifdef PARANOID
25164  if (decode_counter != n_unsigned_total_data_receive_in_root)
25165  {
25166  std::ostringstream error_stream;
25167  error_stream
25168  << "The number of data decoded in root received from others\n"
25169  << "processors is different from the total number of data received\n"
25170  << "Data decoded: (" << decode_counter << ")\n"
25171  << "Data received: (" << n_unsigned_total_data_receive_in_root
25172  << ")\n\n"
25173  << "This is a synchronisation issue so you are probably sending\n"
25174  << "more or less info. than the one that is being decoded\n\n";
25175  throw OomphLibError(
25176  error_stream.str(),
25177  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25178  OOMPH_EXCEPTION_LOCATION);
25179  }
25180 #endif
25181 
25182  // Assign a unique id to the nodes (uses the alias information to
25183  // identify the repetition of a node in other processors). The
25184  // global node id is given by the position (index) in the global
25185  // node alias
25186 
25187  // Keep track of those alias already assigned a unique id
25188  std::map<Vector<unsigned>, bool> alias_done;
25189 
25190  // Store all the alias associated to each node
25191  Vector<Vector<Vector<unsigned>>> global_node_alias;
25192 
25193  // Loop over all the processors
25194  for (unsigned iproc = 0; iproc < nproc; iproc++)
25195  {
25196  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25197  {
25198  // Read the number of nodes shared between the processors
25199  const unsigned n_shd_nodes_iproc_jproc =
25200  local_node_alias[iproc][jproc].size();
25201 #ifdef PARANOID
25202  // Read the number of nodes shared in the other direction
25203  const unsigned n_shd_nodes_jproc_iproc =
25204  local_node_alias[jproc][iproc].size();
25205 
25206  if (n_shd_nodes_iproc_jproc != n_shd_nodes_jproc_iproc)
25207  {
25208  std::ostringstream error_stream;
25209  error_stream
25210  << "The number of nodes shared between iproc and jproc is\n"
25211  << "different from the number of nodes shared between jproc\n"
25212  << "and iproc\n"
25213  << "Nodes shared between processor (" << iproc << ") and "
25214  << "processor (" << jproc << "): (" << n_shd_nodes_iproc_jproc
25215  << ")\n"
25216  << "Nodes shared between processor (" << jproc << ") and "
25217  << "processor (" << iproc << "): (" << n_shd_nodes_jproc_iproc
25218  << ")\n\n";
25219  throw OomphLibError(
25220  error_stream.str(),
25221  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25222  OOMPH_EXCEPTION_LOCATION);
25223  } // if (n_shd_nodes_iproc_jproc != n_shd_nodes_jproc_iproc)
25224 #endif
25225 
25226  // Loop over the nodes shared between the processors
25227  for (unsigned ishd = 0; ishd < n_shd_nodes_iproc_jproc; ishd++)
25228  {
25229  // Get the number of alias associated to the node on each
25230  // processor
25231  const unsigned n_alias_iproc_jproc =
25232  local_node_alias[iproc][jproc][ishd].size();
25233  const unsigned n_alias_jproc_iproc =
25234  local_node_alias[jproc][iproc][ishd].size();
25235 
25236  // Store all the found alias to the node
25237  Vector<Vector<unsigned>> node_alias;
25238 
25239  // Flag to indicate if a new alias has been added
25240  bool new_alias_added = false;
25241 
25242  // Start by adding the "direct" alias of the node
25243  for (unsigned ialias = 0; ialias < n_alias_iproc_jproc; ialias++)
25244  {
25245  // Get the alias of the node
25246  Vector<unsigned> current_alias =
25247  local_node_alias[iproc][jproc][ishd][ialias];
25248  // Check if already done
25249  if (!alias_done[current_alias])
25250  {
25251  // Add the alias of the node
25252  node_alias.push_back(current_alias);
25253  // Set the flag to indicate a new alias has been added
25254  new_alias_added = true;
25255  // Mark the alias as done
25256  alias_done[current_alias] = true;
25257  } // if (!alias_done[i_alias])
25258 
25259  } // for (ialias < n_alias_iproc_jproc)
25260 
25261  // Start by adding the "direct" alias of the node
25262  for (unsigned ialias = 0; ialias < n_alias_jproc_iproc; ialias++)
25263  {
25264  // Get the alias of the node
25265  Vector<unsigned> current_alias =
25266  local_node_alias[jproc][iproc][ishd][ialias];
25267 
25268  // Check if already done
25269  if (!alias_done[current_alias])
25270  {
25271  // Add the alias of the node
25272  node_alias.push_back(current_alias);
25273  // Set the flag to indicate a new alias has been added
25274  new_alias_added = true;
25275  // Mark the alias as done
25276  alias_done[current_alias] = true;
25277  } // if (!alias_done[i_alias])
25278 
25279  } // for (ialias < n_alias_jproc_iproc)
25280 
25281  unsigned counter_alias = 0;
25282  // Visit the alias of the node and add any new found
25283  // alias, end until all its alias have been included
25284 
25285  unsigned n_current_alias = node_alias.size();
25286  while (new_alias_added || counter_alias < n_current_alias)
25287  // while(new_alias_added) // we need to check all the alias,
25288  // including those added during the process
25289  {
25290  new_alias_added = false;
25291  // Store the current visited alias
25292  Vector<unsigned> current_alias = node_alias[counter_alias];
25293 
25294  // Get the alias associated with the current alias
25295  Vector<Vector<unsigned>> alias_of_current_alias =
25296  local_node_alias[current_alias[0]][current_alias[1]]
25297  [current_alias[2]];
25298 
25299  // Get all the alias associated with the alias of the
25300  // current alias
25301  const unsigned n_alias = alias_of_current_alias.size();
25302 
25303  // Loop over the new alias and check if require to add
25304  // them
25305  for (unsigned k = 0; k < n_alias; k++)
25306  {
25307  // Get the alias of the node
25308  Vector<unsigned> add_alias = alias_of_current_alias[k];
25309 
25310  // Check if already done
25311  if (!alias_done[add_alias])
25312  {
25313  // Add the alias of the node
25314  node_alias.push_back(add_alias);
25315  // Set the flag to indicate a new alias has been
25316  // added
25317  new_alias_added = true;
25318  // Mark the alias ad done
25319  alias_done[add_alias] = true;
25320  } // if (!alias_done[i_alias])
25321 
25322  } // for (k < n_alias)
25323 
25324  // Get the alias associated with the current alias (in the
25325  // other direction)
25326  Vector<Vector<unsigned>> alias_of_current_alias2 =
25327  local_node_alias[current_alias[1]][current_alias[0]]
25328  [current_alias[2]];
25329 
25330  // Get all the alias associated with the current alias
25331  // (in the other direction)
25332  const unsigned n_alias2 = alias_of_current_alias2.size();
25333 
25334  // Loop over the new alias and check if require to add
25335  // them
25336  for (unsigned k = 0; k < n_alias2; k++)
25337  {
25338  // Get the alias of the node
25339  Vector<unsigned> add_alias = alias_of_current_alias2[k];
25340 
25341  // Check if already done
25342  if (!alias_done[add_alias])
25343  {
25344  // Add the alias of the node
25345  node_alias.push_back(add_alias);
25346  // Set the flag to indicate a new alias has been
25347  // added
25348  new_alias_added = true;
25349  // Mark the alias ad done
25350  alias_done[add_alias] = true;
25351  } // if (!alias_done[i_alias])
25352 
25353  } // for (k < n_alias)
25354 
25355  // Go for the next alias
25356  counter_alias++;
25357 
25358  // Update the number of alias so that the while stops when
25359  // all the alias have been visited and no new alias was
25360  // added
25361  n_current_alias = node_alias.size();
25362 
25363  } // while(new_alias_added || counter_alias < n_current_alias)
25364 
25365  // If the node has not been previously added, then include
25366  // all its alias
25367  if (node_alias.size() > 0)
25368  {
25369  // Add all the found alias of the node to the global alias
25370  // storage
25371  global_node_alias.push_back(node_alias);
25372  }
25373 
25374  } // for (ishd < n_shd_nodes_iproc_jproc)
25375 
25376  } // for (jproc < nproc)
25377 
25378  } // for (iproc < nproc)
25379 
25380  // We now have the global number of nodes, each with its own id
25381  // (the index in the global_node_alias vector)
25382 
25383  // Get the number of global shared nodes
25384  const unsigned n_global_shared_nodes = global_node_alias.size();
25385 
25386  // Create matrix from local to global shared node id
25387  Vector<Vector<Vector<int>>> local_to_global_shared_node(nproc);
25388 
25389  // Loop over all the processors to resize
25390  for (unsigned iproc = 0; iproc < nproc; iproc++)
25391  {
25392  // Resize the map matrix
25393  local_to_global_shared_node[iproc].resize(nproc);
25394  } // for (iproc < nproc)
25395 
25396  // Loop over all the processors to resize (the third direction,
25397  // required if we want to loop over the half of the matrix only)
25398  for (unsigned iproc = 0; iproc < nproc; iproc++)
25399  {
25400  // Loop over the half of the matrix to resize
25401  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25402  {
25403  // Read the number of nodes shared between the processors
25404  const unsigned n_shd_nodes = local_node_alias[iproc][jproc].size();
25405 
25406  // Resize the map matrix
25407  local_to_global_shared_node[iproc][jproc].resize(n_shd_nodes, -1);
25408 
25409  // ... and resize the other half map matrix
25410  local_to_global_shared_node[jproc][iproc].resize(n_shd_nodes, -1);
25411 
25412  } // for (jproc < nproc)
25413 
25414  } // for (iproc < nproc)
25415 
25416  // Fill the matrix for mapping from local to global node id
25417 
25418  // Loop over the global nodes, and for each alias assign the
25419  // corresponding global node id
25420  for (unsigned k = 0; k < n_global_shared_nodes; k++)
25421  {
25422  // Get the number of alias associated to the current global node
25423  const unsigned n_alias_global_node = global_node_alias[k].size();
25424  // Loop over the alias and assign the global node id
25425  for (unsigned l = 0; l < n_alias_global_node; l++)
25426  {
25427  // Get the 1st processor
25428  const unsigned iproc = global_node_alias[k][l][0];
25429  // Get the 2nd processor
25430  const unsigned jproc = global_node_alias[k][l][1];
25431  // Get the node number
25432  const unsigned ishd = global_node_alias[k][l][2];
25433  // Assign the global node id
25434  local_to_global_shared_node[iproc][jproc][ishd] = k;
25435 
25436  } // for (l < n_alias_global_node)
25437 
25438  } // for (k < n_global_shared_nodes)
25439 
25440  // Create the global adjacency matrix
25441  Vector<Vector<unsigned>> global_adjacency_matrix(n_global_shared_nodes);
25442  // Resize the global adjacency matrix
25443  for (unsigned k = 0; k < n_global_shared_nodes; k++)
25444  {
25445  // Resize
25446  global_adjacency_matrix[k].resize(n_global_shared_nodes, 0);
25447  } // for (k < n_global_shared_nodes)
25448 
25449  // Add the entries to the global adjacency matrix and compute the
25450  // degree of each node
25451 
25452  // Store the degree of the global nodes
25453  Vector<unsigned> global_node_degree(n_global_shared_nodes, 0);
25454 
25455  // Loop over the processors
25456  for (unsigned iproc = 0; iproc < nproc; iproc++)
25457  {
25458  // Loop over the half of the matrix to resize
25459  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25460  {
25461  // Get the number of nodes shared between the processors
25462  const unsigned n_shd_nodes = local_node_alias[iproc][jproc].size();
25463 
25464  // Search for entries in the local adjacency matrix that set a
25465  // connection among the nodes
25466 
25467  // Loop over the shared nodes in the current pair of
25468  // processors
25469  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25470  {
25471  for (unsigned jshd = ishd + 1; jshd < n_shd_nodes; jshd++)
25472  {
25473  // Are the nodes associated
25474  if (local_adjacency_matrix[iproc][jproc][ishd][jshd] > 0)
25475  {
25476  // Get the global nodes id
25477 
25478  // Get the "left-node" global id
25479  const int global_shd_node_left =
25480  local_to_global_shared_node[iproc][jproc][ishd];
25481 
25482  // Get the "right-node" global id
25483  const int global_shd_node_right =
25484  local_to_global_shared_node[iproc][jproc][jshd];
25485 
25486 #ifdef PARANOID
25487  // Check if the local nodes have a global node
25488  // associated
25489  if (global_shd_node_left == -1)
25490  {
25491  std::ostringstream error_stream;
25492  error_stream
25493  << "The local node in processors iproc and jproc has no\n"
25494  << "global node assigned\n"
25495  << "iproc processor: (" << iproc << ")\n"
25496  << "jproc processor: (" << jproc << ")\n"
25497  << "Local node: (" << ishd << ")\n\n";
25498  throw OomphLibError(error_stream.str(),
25499  "RefineableTriangleMesh::compute_shared_"
25500  "node_degree_helper()",
25501  OOMPH_EXCEPTION_LOCATION);
25502  }
25503 
25504  // Check if the local nodes have a global node
25505  // associated
25506  if (global_shd_node_right == -1)
25507  {
25508  std::ostringstream error_stream;
25509  error_stream
25510  << "The local node in processors iproc and jproc has no\n"
25511  << "global node assigned\n"
25512  << "iproc processor: (" << iproc << ")\n"
25513  << "jproc processor: (" << jproc << ")\n"
25514  << "Local node: (" << jshd << ")\n\n";
25515  throw OomphLibError(error_stream.str(),
25516  "RefineableTriangleMesh::compute_shared_"
25517  "node_degree_helper()",
25518  OOMPH_EXCEPTION_LOCATION);
25519  }
25520 #endif
25521  // Get the unsigned version of the indexes
25522  const unsigned uleft =
25523  static_cast<unsigned>(global_shd_node_left);
25524  const unsigned uright =
25525  static_cast<unsigned>(global_shd_node_right);
25526 
25527  // Add the entry in the global adjacency matrix
25528  global_adjacency_matrix[uleft][uright]++;
25529 
25530  // ... and in the other direction too
25531  global_adjacency_matrix[uright][uleft]++;
25532 
25533  // Add on to the degree of the left node
25534  global_node_degree[uleft]++;
25535 
25536  // Add on to the degree of the right node
25537  global_node_degree[uright]++;
25538 
25539  } // if (local_adjacency_matrix[iproc][jproc][ishd][jshd] > 0)
25540 
25541  } // // for (jshd < n_shd_nodes)
25542 
25543  } // for (ishd < n_shd_nodes)
25544 
25545  } // for (jproc < nproc)
25546 
25547  } // for (iproc < nproc)
25548 
25549  // Assign the global degree to the shared nodes between each pair
25550  // of processors
25551  Vector<Vector<Vector<unsigned>>> root_local_node_degree(nproc);
25552  // Resize the container
25553  for (unsigned iproc = 0; iproc < nproc; iproc++)
25554  {
25555  root_local_node_degree[iproc].resize(nproc);
25556  }
25557 
25558  // Loop over the processors and visited their shared nodes
25559  for (unsigned iproc = 0; iproc < nproc; iproc++)
25560  {
25561  // Only visit the half of the data
25562  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25563  {
25564  // Get the number of shared nodes between this pair of
25565  // processors (iproc, jproc)
25566  const unsigned n_shd_nodes = local_node_alias[iproc][jproc].size();
25567 
25568  // Resize the container to store the local degree of the nodes
25569  root_local_node_degree[iproc][jproc].resize(n_shd_nodes);
25570  // ... and in the other way too
25571  root_local_node_degree[jproc][iproc].resize(n_shd_nodes);
25572 
25573  // Loop over the number of nodes shared between the pair of
25574  // processors
25575  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25576  {
25577  // Get the global node id for the current shared node
25578  const int global_shd_node_id =
25579  local_to_global_shared_node[iproc][jproc][ishd];
25580 
25581 #ifdef PARANOID
25582  // Check if the local nodes have a global node associated
25583  if (global_shd_node_id == -1)
25584  {
25585  std::ostringstream error_stream;
25586  error_stream
25587  << "The local node in processors iproc and jproc has no\n"
25588  << "global node assigned\n"
25589  << "iproc processor: (" << iproc << ")\n"
25590  << "jproc processor: (" << jproc << ")\n"
25591  << "Local node: (" << ishd << ")\n\n";
25592  throw OomphLibError(
25593  error_stream.str(),
25594  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25595  OOMPH_EXCEPTION_LOCATION);
25596  }
25597 #endif
25598 
25599  // Get the unsigned version of the global index
25600  const unsigned uglobal_shd_node_id =
25601  static_cast<unsigned>(global_shd_node_id);
25602 
25603  // Get the degree of the node
25604  const unsigned node_degree =
25605  global_node_degree[uglobal_shd_node_id];
25606 
25607  // Set the degree in the container for the degree of the
25608  // nodes in the local interaction between processors
25609  root_local_node_degree[iproc][jproc][ishd] = node_degree;
25610  // ... and in the other way too
25611  root_local_node_degree[jproc][iproc][ishd] = node_degree;
25612 
25613  } // for (ishd < n_shd_nodes)
25614 
25615  } // for (jproc < nproc)
25616 
25617  } // for (iproc < nproc)
25618 
25619  // Clear the container where the info. will be sent back to each
25620  // processor
25621  package_unsigned_data_sent_from_root.clear();
25622 
25623  // Prepare the data to sent it back to each processor (encode the
25624  // info. to sent to all processors)
25625  for (unsigned iproc = 0; iproc < nproc; iproc++)
25626  {
25627  // Count the number of data sent to iproc processor
25628  unsigned count_n_data_sent_to_iproc = 0;
25629  for (unsigned jproc = 0; jproc < nproc; jproc++)
25630  {
25631  // No shared nodes between the same processor
25632  if (iproc != jproc)
25633  {
25634  // Get the number of nodes shared between the processors
25635  const unsigned n_shd_nodes =
25636  root_local_node_degree[iproc][jproc].size();
25637 
25638  // Add the number of data sent to iproc processor
25639  count_n_data_sent_to_iproc += n_shd_nodes;
25640 
25641  // Loop over the nodes shared between the pair of processors
25642  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25643  {
25644  package_unsigned_data_sent_from_root.push_back(
25645  root_local_node_degree[iproc][jproc][ishd]);
25646  } // for (ishd < n_shd_nodes)
25647 
25648  } // if (iproc != jproc)
25649 
25650  } // for (jproc < nproc)
25651 
25652  // Set the number of data sent to iproc processor
25653  n_unsigned_data_sent_from_root[iproc] = count_n_data_sent_to_iproc;
25654 
25655  } // for (iproc < nproc)
25656 
25657  } // if (my_rank == root_processor)
25658 
25659  // Total data received from root to this processor
25660  int n_unsigned_data_received_from_root = 0;
25661 
25662  // Get the number of data that each processor receives from root
25663  MPI_Scatter(&n_unsigned_data_sent_from_root[0], // Info. sent from
25664  // root to each
25665  // processor
25666  1, // The number of data sent from root to each
25667  // processor
25668  MPI_UNSIGNED,
25669  &n_unsigned_data_received_from_root, // Store the
25670  // info. received
25671  // from root
25672  1, // The number of data received from root
25673  MPI_UNSIGNED,
25674  root_processor, // The processor that sends the
25675  // info.
25676  comm_pt->mpi_comm());
25677 
25678  // Receive the info. sent by root
25679  Vector<unsigned> package_unsigned_data_received_from_root(
25680  n_unsigned_data_received_from_root);
25681 
25682  // Compute the offsets to each processor
25683  Vector<int> root_unsigned_offsets_sent(nproc, 0);
25684  root_unsigned_offsets_sent[0] = 0;
25685  for (unsigned iproc = 1; iproc < nproc; iproc++)
25686  {
25687  // Compute the offset to send the values to each processor
25688  root_unsigned_offsets_sent[iproc] =
25689  root_unsigned_offsets_sent[iproc - 1] +
25690  n_unsigned_data_sent_from_root[iproc - 1];
25691  }
25692 
25693  if (my_rank != root_processor)
25694  {
25695  // Create at least one entry so we don't get a seg fault below
25696  if (package_unsigned_data_sent_from_root.size() == 0)
25697  {
25698  package_unsigned_data_sent_from_root.resize(1);
25699  }
25700  } // if (my_rank!=root_processor)
25701 
25702  // Create at least one entry so we don't get a seg fault below
25703  if (package_unsigned_data_received_from_root.size() == 0)
25704  {
25705  package_unsigned_data_received_from_root.resize(1);
25706  }
25707 
25708  // Get the data from root
25709  MPI_Scatterv(&package_unsigned_data_sent_from_root[0], // The
25710  // info. sent
25711  // from root
25712  // to others
25713  // processors
25714  &n_unsigned_data_sent_from_root[0], // The number of
25715  // data sent from
25716  // root to others
25717  // processors
25718  &root_unsigned_offsets_sent[0], // The offsets to each
25719  // processors
25720  MPI_UNSIGNED,
25721  &package_unsigned_data_received_from_root[0], // The
25722  // storage
25723  // in the
25724  // processor
25725  // that
25726  // receives
25727  // the
25728  // info.
25729  n_unsigned_data_received_from_root, // The number of
25730  // data that the
25731  // current
25732  // processor
25733  // receives from
25734  // root
25735  MPI_UNSIGNED,
25736  root_processor, // The root processors
25737  comm_pt->mpi_comm());
25738 
25739  // Decode the info.
25740 
25741  // Keep track of the already nodes done
25742  std::map<Node*, bool> node_done;
25743 
25744  // Read the global degree assigned to the shared nodes between the
25745  // current processors and the other processors
25746  int decode_counter = 0;
25747  // Store the global degree of the local nodes
25748  Vector<Vector<unsigned>> local_node_degree(nproc);
25749  // Loop over the processors
25750  for (unsigned iproc = 0; iproc < nproc; iproc++)
25751  {
25752  // There are no shared nodes with the current processor itself
25753  if (iproc != my_rank)
25754  {
25755  // Get the number of nodes shared with the iproc processor
25756  const unsigned n_nodes = tmp_sorted_shared_node_pt[iproc].size();
25757 
25758  // Read the global degree of the node
25759  package_unsigned_send_data_to_root.push_back(n_nodes);
25760 
25761  // Loop over the nodes
25762  for (unsigned ishd = 0; ishd < n_nodes; ishd++)
25763  {
25764  // Get the node degree assigned to the ishd node in between
25765  // the interaction of the iproc and the current processor
25766  const unsigned node_degree =
25767  package_unsigned_data_received_from_root[decode_counter++];
25768 
25769  // Get the node
25770  Node* shd_node_pt = tmp_sorted_shared_node_pt[iproc][ishd];
25771 
25772  // Has the node been assigned a global degree
25773  if (!node_done[shd_node_pt])
25774  {
25775  // Assign the global degree to the node
25776  global_node_degree[shd_node_pt] = node_degree;
25777  // Mark the node as done
25778  node_done[shd_node_pt] = true;
25779  }
25780 #ifdef PARANOID
25781  else
25782  {
25783  // The node has been already done, check that the node
25784  // degree is the same as the already assigned
25785  if (global_node_degree[shd_node_pt] != node_degree)
25786  {
25787  std::ostringstream error_stream;
25788  error_stream
25789  << "The local node has already assigned a global degree,\n"
25790  << "however, a different degree for the same node has been\n"
25791  << "read from the data sent from root processor\n"
25792  << "iproc processor: (" << iproc << ")\n"
25793  << "Local node: (" << ishd << ")\n"
25794  << "---------------------------------------------------------\n"
25795  << "Already assigned degree: ("
25796  << global_node_degree[shd_node_pt] << ")\n"
25797  << "New found degree: (" << node_degree << ")\n"
25798  << "---------------------------------------------------------\n"
25799  << "Node coordinates: (" << shd_node_pt->x(0) << ", "
25800  << shd_node_pt->x(1) << ")\n\n";
25801  throw OomphLibError(
25802  error_stream.str(),
25803  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25804  OOMPH_EXCEPTION_LOCATION);
25805  }
25806 
25807  } // else if (!node_done[shd_node_pt])
25808 #endif // #ifdef PARANOID
25809 
25810  } // for (ishd < n_nodes)
25811 
25812  } // if (iproc != my_rank)
25813 
25814  } // for (iproc < nproc)
25815 
25816 #ifdef PARANOID
25817  // Ensure that all the info. sent from root processor has been read
25818  if (decode_counter != n_unsigned_data_received_from_root)
25819  {
25820  std::ostringstream error_stream;
25821  error_stream
25822  << "The number of data decoded received from root processor is\n"
25823  << "different from the total number of data received from the root\n"
25824  << "processor\n"
25825  << "Data decoded: (" << decode_counter << ")\n"
25826  << "Data received: (" << n_unsigned_data_received_from_root << ")\n\n"
25827  << "This is a synchronisation issue so you are probably sending\n"
25828  << "more or less info. than the one that is being decoded\n\n";
25829  throw OomphLibError(
25830  error_stream.str(),
25831  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25832  OOMPH_EXCEPTION_LOCATION);
25833  }
25834 #endif
25835  }
25836 
25837  //======================================================================
25838  // Sort the nodes on the new shared boundaries (after load balancing),
25839  // computes the alias of the nodes and creates the adjacency matrix
25840  // that represent the graph created by the shared edges between each
25841  // pair of processors
25842  // ======================================================================
25843  template<class ELEMENT>
25846  Vector<Vector<FiniteElement*>>& unsorted_face_ele_pt,
25847  Vector<Vector<Node*>>& tmp_sorted_shared_node_pt,
25848  std::map<Node*, Vector<Vector<unsigned>>>& node_alias,
25849  Vector<Vector<Vector<unsigned>>>& adjacency_matrix)
25850  {
25851  // Get the number of processors and the rank
25852  const unsigned nproc = this->communicator_pt()->nproc();
25853  const unsigned my_rank = this->communicator_pt()->my_rank();
25854 
25855  // Assign a unique id to each node shared between each pair of
25856  // processors, in this case the current processor and the iproc
25857 
25858  // ... also compute the alias of each node (processor and index of
25859  // the node in all processors where it appears)
25860 
25861  // Clear the alias info
25862  node_alias.clear();
25863 
25864  // Temporary storage for the index of the nodes
25865  Vector<std::map<Node*, unsigned>> tmp_node_index(nproc);
25866 
25867  // Loop over the processors
25868  for (unsigned iproc = 0; iproc < nproc; iproc++)
25869  {
25870  // There is no shared elements between the same processor
25871  if (iproc != my_rank)
25872  {
25873  // Map to mark those nodes already visited
25874  std::map<Node*, bool> done_node;
25875 
25876  // A map is used to sort the nodes using their coordinates as
25877  // the key of the map
25878  // std::map<std::pair<double, double>, Node*> sorted_nodes_pt;
25879  std::map<std::pair<double, double>, Node*, classcomp> sorted_nodes_pt;
25880 
25881  // Get the number of unsorted face elements
25882  const unsigned n_unsorted_face_ele = unsorted_face_ele_pt[iproc].size();
25883 
25884  // Loop over the unsorted elements
25885  for (unsigned e = 0; e < n_unsorted_face_ele; e++)
25886  {
25887  // Get a root element
25888  FiniteElement* face_ele_pt = unsorted_face_ele_pt[iproc][e];
25889  // Get the left node of the face element
25890  Node* left_node_pt = face_ele_pt->node_pt(0);
25891 
25892  // Check if the node has been already sorted in the
25893  // interaction between the current processor and iproc
25894  // processor
25895  if (!done_node[left_node_pt])
25896  {
25897  std::pair<double, double> vertex =
25898  std::make_pair(left_node_pt->x(0), left_node_pt->x(1));
25899  sorted_nodes_pt[vertex] = left_node_pt;
25900  // Mark the node as done
25901  done_node[left_node_pt] = true;
25902  }
25903 
25904  // Get the number of nodes of the face element
25905  const unsigned n_nodes = face_ele_pt->nnode();
25906  // Get the right node of the face element
25907  Node* right_node_pt = face_ele_pt->node_pt(n_nodes - 1);
25908 
25909  // Check if the node has been already sorted in the
25910  // interaction between the current processor and iproc
25911  // processor
25912  if (!done_node[right_node_pt])
25913  {
25914  std::pair<double, double> vertex =
25915  std::make_pair(right_node_pt->x(0), right_node_pt->x(1));
25916  sorted_nodes_pt[vertex] = right_node_pt;
25917  // Mark the node as done
25918  done_node[right_node_pt] = true;
25919  }
25920 
25921  } // for (e < nunsorted_face_ele)
25922 
25923  // The nodes are already sorted, we need to return them in the
25924  // proper container
25925 
25926  // The counter to enumerate the nodes
25927  unsigned counter = 0;
25928 
25929  // Go through the map container which already have the nodes
25930  // sorted they have the same sorting on all processors
25931  for (std::map<std::pair<double, double>, Node*>::iterator it =
25932  sorted_nodes_pt.begin();
25933  it != sorted_nodes_pt.end();
25934  it++)
25935  {
25936  // Get the node
25937  Node* node_pt = (*it).second;
25938  // Store the node at the corresponding index
25939  tmp_sorted_shared_node_pt[iproc].push_back(node_pt);
25940 
25941  // Create the temporary access to the node index
25942  tmp_node_index[iproc][node_pt] = counter;
25943 
25944  // Fill the info. for the node alias
25945  Vector<unsigned> alias(3);
25946  // The current processor
25947  alias[0] = my_rank;
25948  // The processor with which is shared
25949  alias[1] = iproc;
25950  // The index with that processor
25951  alias[2] = counter++;
25952 
25953  // Store the info. of the alias
25954  node_alias[node_pt].push_back(alias);
25955 
25956  } // Loop map
25957 
25958  } // if (iproc != my_rank)
25959 
25960  } // for (iproc < nproc)
25961 
25962  // Loop over the processors to resize and initialize the adjacency
25963  // matrix
25964  for (unsigned iproc = 0; iproc < nproc; iproc++)
25965  {
25966  // Get the number of nodes shared with iproc
25967  const unsigned n_shd_nodes = tmp_sorted_shared_node_pt[iproc].size();
25968  // Resize the adjacency matrix
25969  adjacency_matrix[iproc].resize(n_shd_nodes);
25970  for (unsigned i = 0; i < n_shd_nodes; i++)
25971  {
25972  // Resize the adjacency matrix
25973  adjacency_matrix[iproc][i].resize(n_shd_nodes);
25974 
25975  // Initialize the
25976  for (unsigned j = 0; j < n_shd_nodes; j++)
25977  {
25978  adjacency_matrix[iproc][i][j] = 0;
25979  } // for (j < n_shd_nodes)
25980 
25981  } // for (i < n_shd_nodes)
25982 
25983  } // for (iproc < nproc)
25984 
25985  // Loop over the processors to fill the adjacency matrix
25986  for (unsigned iproc = 0; iproc < nproc; iproc++)
25987  {
25988  // There is no shared elements between the same processor
25989  if (iproc != my_rank)
25990  {
25991  // Get the number of unsorted face elements
25992  const unsigned n_unsorted_face_ele = unsorted_face_ele_pt[iproc].size();
25993 
25994  // Loop over the unsorted elements
25995  for (unsigned e = 0; e < n_unsorted_face_ele; e++)
25996  {
25997  // Get a root element
25998  FiniteElement* face_ele_pt = unsorted_face_ele_pt[iproc][e];
25999  // Get the left node of the face element
26000  Node* left_node_pt = face_ele_pt->node_pt(0);
26001 
26002  // Get the number of nodes of the face element
26003  const unsigned n_nodes = face_ele_pt->nnode();
26004  // Get the right node of the face element
26005  Node* right_node_pt = face_ele_pt->node_pt(n_nodes - 1);
26006 
26007  // Get the index of each of the nodes
26008  const unsigned left_node_index = tmp_node_index[iproc][left_node_pt];
26009  const unsigned right_node_index =
26010  tmp_node_index[iproc][right_node_pt];
26011 
26012  // Add an entry to the adjacency matrix to indicate the
26013  // association of left and right node
26014  adjacency_matrix[iproc][left_node_index][right_node_index]++;
26015  // ... both directions
26016  adjacency_matrix[iproc][right_node_index][left_node_index]++;
26017 
26018  } // for (e < n_unsorted_face_ele)
26019 
26020  } // if (iproc != my_rank)
26021 
26022  } // for (iproc < nproc)
26023  }
26024 
26025  //======================================================================
26026  /// Get the nodes on the shared boundary (b), these are stored
26027  /// in the segment they belong
26028  //======================================================================
26029  template<class ELEMENT>
26032  const unsigned& shd_bnd_id, Vector<Vector<Node*>>& tmp_segment_nodes)
26033  {
26034  // Clear the data structure were to return the nodes
26035  tmp_segment_nodes.clear();
26036 
26037  // Get the face elements that created the shared boundary from the
26038  // bulk shared boundary elements
26039 
26040 #ifdef PARANOID
26041  // The temporary storage for the halo face elements
26042  Vector<FiniteElement*> halo_shared_face_ele_pt;
26043 #endif
26044  // The temporary storage for the nonhalo face elements
26045  Vector<FiniteElement*> nonhalo_shared_face_ele_pt;
26046 
26047  // Get the number of shared boundary elements associated with the
26048  // current shared boundary
26049  const unsigned nshared_bound_ele =
26050  this->nshared_boundary_element(shd_bnd_id);
26051 
26052  // Loop over the elements in the shared boundary to create the face
26053  // elements
26054  for (unsigned e = 0; e < nshared_bound_ele; e++)
26055  {
26056  // Get the shared boundary element
26057  FiniteElement* bulk_ele_pt =
26058  this->shared_boundary_element_pt(shd_bnd_id, e);
26059 
26060  // Get the face index
26061  int face_index = this->face_index_at_shared_boundary(shd_bnd_id, e);
26062 
26063  // Before adding the new element we need to ensure that the edge
26064  // that this element represents has not been already added
26065  FiniteElement* face_ele_pt =
26066  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
26067 
26068  // Nonhalo element
26069  if (!bulk_ele_pt->is_halo())
26070  {
26071  // Add nonhalo shared face element to the container
26072  nonhalo_shared_face_ele_pt.push_back(face_ele_pt);
26073  }
26074 #ifdef PARANOID
26075  else // halo element
26076  {
26077  // Add halo shared face element to the container
26078  halo_shared_face_ele_pt.push_back(face_ele_pt);
26079  }
26080 #endif
26081 
26082  } // for (e < nshared_bound_ele)
26083 
26084  // Mark the face elements already used
26085  std::map<FiniteElement*, bool> shared_face_done;
26086 
26087  // Get the number of nonhalo face elements
26088  const unsigned nnonhalo_face_shared_ele = nonhalo_shared_face_ele_pt.size();
26089 
26090  // If we are in PARANOID mode check that there is one halo element
26091  // for each nonhalo element
26092 #ifdef PARANOID
26093  // Get the number of halo face elements
26094  const unsigned nhalo_face_shared_ele = halo_shared_face_ele_pt.size();
26095 
26096  // The number of nonhalo shared face boundary elements must be the
26097  // half of the total number of shared boundary elements
26098  if (nshared_bound_ele / 2 != nnonhalo_face_shared_ele)
26099  {
26100  std::ostringstream error_message;
26101  error_message
26102  << "The number of shared boundary elements (" << nshared_bound_ele
26103  << ") is not the double\nof the number of unsorted nonhalo shared "
26104  << "face boundary elements (" << nnonhalo_face_shared_ele
26105  << ")\n for the current boundary (" << shd_bnd_id << ")\n\n";
26106  throw OomphLibError(
26107  error_message.str(),
26108  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
26109  OOMPH_EXCEPTION_LOCATION);
26110  }
26111 
26112  // The number of halo shared face boundary elements must be the
26113  // half of the total number of shared boundary elements
26114  if (nshared_bound_ele / 2 != nhalo_face_shared_ele)
26115  {
26116  std::ostringstream error_message;
26117  error_message
26118  << "The number of shared boundary elements (" << nshared_bound_ele
26119  << ") is not the double\nof the number of unsorted halo shared "
26120  << "face boundary elements (" << nhalo_face_shared_ele
26121  << ")\n for the current boundary (" << shd_bnd_id << ")\n\n";
26122  throw OomphLibError(
26123  error_message.str(),
26124  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
26125  OOMPH_EXCEPTION_LOCATION);
26126  }
26127 
26128  // ------------------------------------------------------------------
26129  // Loop over the nonhalo face elements and look for the halo face
26130  // element at the other side of the shared boundary
26131  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
26132  {
26133  // Get the inh-th face element
26134  FiniteElement* nonhalo_face_ele_pt = nonhalo_shared_face_ele_pt[inh];
26135 
26136  // Get the number of nodes on the face element
26137  const unsigned nnodes_nh = nonhalo_face_ele_pt->nnode();
26138  // Get the first and last node on the element
26139  Node* nh_first_node_pt = nonhalo_face_ele_pt->node_pt(0);
26140  Node* nh_last_node_pt = nonhalo_face_ele_pt->node_pt(nnodes_nh - 1);
26141 
26142  // Now find the (halo) face element at the other side of the
26143  // shared boundary
26144  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
26145  {
26146  // Get the ih-th face element
26147  FiniteElement* halo_face_ele_pt = halo_shared_face_ele_pt[ih];
26148 
26149  // Check that the face element has not been done
26150  if (!shared_face_done[halo_face_ele_pt])
26151  {
26152  // Get the number of nodes on the face element
26153  const unsigned nnodes_h = halo_face_ele_pt->nnode();
26154  // Get the first and last node on the element
26155  Node* h_first_node_pt = halo_face_ele_pt->node_pt(0);
26156  Node* h_last_node_pt = halo_face_ele_pt->node_pt(nnodes_h - 1);
26157 
26158  // If the nodes are the same then we have found the (halo)
26159  // face element at the other side of the shared boundary
26160  if (nh_first_node_pt == h_first_node_pt &&
26161  nh_last_node_pt == h_last_node_pt)
26162  {
26163  // Mark the face elements as done
26164  shared_face_done[nonhalo_face_ele_pt] = true;
26165  shared_face_done[halo_face_ele_pt] = true;
26166 
26167  // Break the loop for (ih < nhalo_face_shared_ele)
26168  break;
26169  } // if (nh_first_node_pt == h_first_node_pt &&
26170  // nh_last_node_pt == h_last_node_pt)
26171  else if (nh_first_node_pt == h_last_node_pt &&
26172  nh_last_node_pt == h_first_node_pt)
26173  {
26174  // Mark the face elements as done
26175  shared_face_done[nonhalo_face_ele_pt] = true;
26176  shared_face_done[halo_face_ele_pt] = true;
26177 
26178  // Break the loop for (ih < nhalo_face_shared_ele)
26179  break;
26180  } // else if (nh_first_node_pt == h_last_node_pt &&
26181  // nh_last_node_pt == h_first_node_pt)
26182 
26183  } // if (face_done[halo_face_ele_pt])
26184 
26185  } // for (ih < nhalo_face_shared_ele)
26186 
26187  } // for (inh < nnonhalo_face_shared_ele)
26188 
26189  // The number of done shared face elements MUST be the same as the
26190  // sum of the nonhalo and halo shared boundary face elements
26191  if ((nnonhalo_face_shared_ele + nhalo_face_shared_ele) !=
26192  shared_face_done.size())
26193  {
26194  std::ostringstream error_message;
26195  error_message << "The number of DONE shared boundary face elements ("
26196  << shared_face_done.size()
26197  << ") is not the same\n as the sum of"
26198  << "the nonhalo face shared boundary elements ("
26199  << nnonhalo_face_shared_ele
26200  << ")\nand the halo face shared "
26201  << "boundary elements (" << nhalo_face_shared_ele
26202  << ") for the\n/"
26203  << "current boundary (" << shd_bnd_id << ")\n\n";
26204  throw OomphLibError(
26205  error_message.str(),
26206  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
26207  OOMPH_EXCEPTION_LOCATION);
26208  }
26209 #endif // #ifdef PARANOID
26210 
26211  // -------------------------------------------------------------
26212  // Now sort the face elements
26213  // -------------------------------------------------------------
26214 
26215  // We already have the shared face elements that make the shared
26216  // boundary now sort them to create a contiguous boundary
26217 
26218  // Clear the already done face elements
26219  shared_face_done.clear();
26220 
26221  unsigned nsorted_face_ele = 0;
26222 
26223  // Storing for the sorting nodes extracted from the face elements
26224  std::list<Node*> sorted_nodes;
26225 
26226  // Get the root face element
26227  FiniteElement* root_face_ele_pt = nonhalo_shared_face_ele_pt[0];
26228  nsorted_face_ele++;
26229 
26230  // Mark face as done
26231  shared_face_done[root_face_ele_pt] = true;
26232 
26233  // The initial and final node on the list
26234  const unsigned nnodes_root = root_face_ele_pt->nnode();
26235  Node* first_node_pt = root_face_ele_pt->node_pt(0);
26236  Node* last_node_pt = root_face_ele_pt->node_pt(nnodes_root - 1);
26237 
26238  // Push back on the list the new nodes
26239  sorted_nodes.push_back(first_node_pt);
26240  sorted_nodes.push_back(last_node_pt);
26241 
26242  // Sort the face elements
26243  while (nsorted_face_ele < nnonhalo_face_shared_ele)
26244  {
26245  // Flag to indicate when a node was added
26246  bool node_added = false;
26247 
26248  // Start from the next edge since we have already added the
26249  // previous one as the initial face element
26250  for (unsigned iface = 1; iface < nnonhalo_face_shared_ele; iface++)
26251  {
26252  FiniteElement* tmp_shared_face_ele_pt =
26253  nonhalo_shared_face_ele_pt[iface];
26254 
26255  // If face has not been sorted
26256  if (!shared_face_done[tmp_shared_face_ele_pt])
26257  {
26258  // Get the number of nodes for the current face element
26259  const unsigned tmp_nnodes = tmp_shared_face_ele_pt->nnode();
26260 
26261  // Get each individual node
26262  Node* left_node_pt = tmp_shared_face_ele_pt->node_pt(0);
26263  Node* right_node_pt = tmp_shared_face_ele_pt->node_pt(tmp_nnodes - 1);
26264 
26265  if (left_node_pt == first_node_pt)
26266  {
26267  // Push front the new node
26268  sorted_nodes.push_front(right_node_pt);
26269  first_node_pt = right_node_pt;
26270  node_added = true;
26271  }
26272  else if (left_node_pt == last_node_pt)
26273  {
26274  // Push back the new node
26275  sorted_nodes.push_back(right_node_pt);
26276  last_node_pt = right_node_pt;
26277  node_added = true;
26278  }
26279  else if (right_node_pt == first_node_pt)
26280  {
26281  // Push front the new node
26282  sorted_nodes.push_front(left_node_pt);
26283  first_node_pt = left_node_pt;
26284  node_added = true;
26285  }
26286  else if (right_node_pt == last_node_pt)
26287  {
26288  // Push back the new node
26289  sorted_nodes.push_back(left_node_pt);
26290  last_node_pt = left_node_pt;
26291  node_added = true;
26292  }
26293 
26294  if (node_added)
26295  {
26296  // Mark as done only if one of its nodes has been added to
26297  // the list
26298  shared_face_done[tmp_shared_face_ele_pt] = true;
26299  nsorted_face_ele++;
26300 
26301  // Break the for
26302  break;
26303  }
26304 
26305  } // if (!shared_face_done[tmp_shared_face_ele_pt])
26306 
26307  } // for (iface < nnonhalo_face_shared_ele)
26308 
26309  } // while (nsorted_face_ele < nnonhalo_face_shared_ele))
26310 
26311  // Here we can safely delete the face elements, they are no longer
26312  // required
26313 
26314  // First the nonhalo face elements
26315  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
26316  {
26317  delete nonhalo_shared_face_ele_pt[inh];
26318  nonhalo_shared_face_ele_pt[inh] = 0;
26319  } // for (inh < nnonhalo_face_shared_ele)
26320 
26321 #ifdef PARANOID
26322  // ... then the halo face elements
26323  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
26324  {
26325  delete halo_shared_face_ele_pt[ih];
26326  halo_shared_face_ele_pt[ih] = 0;
26327  } // for (inh < nhalo_face_shared_ele)
26328 #endif
26329 
26330  // ------------------------------------------------
26331  // Now copy the nodes to the output container
26332  // ------------------------------------------------
26333  // Get the number of nodes in the container
26334  const unsigned n_nodes = sorted_nodes.size();
26335 
26336  // First resize the container
26337  tmp_segment_nodes.resize(1);
26338  tmp_segment_nodes[0].resize(n_nodes);
26339 
26340  // Counter
26341  unsigned counter = 0;
26342 
26343  // Loop over the list of nodes and copy them in the output container
26344  for (std::list<Node*>::iterator it = sorted_nodes.begin();
26345  it != sorted_nodes.end();
26346  it++)
26347  {
26348  tmp_segment_nodes[0][counter] = (*it);
26349  counter++;
26350  } // Loop over sorted nodes
26351  }
26352 
26353  //=====start of get_required_elemental_information_load_balance_helper====
26354  /// Helper function to get the required elemental information from
26355  /// the element that will be sent to iproc processor.
26356  /// This info. involves the association of the element to a boundary or
26357  /// region.
26358  //========================================================================
26359  template<class ELEMENT>
26362  unsigned& iproc,
26363  Vector<Vector<FiniteElement*>>& f_haloed_ele_pt,
26364  FiniteElement* ele_pt)
26365  {
26366  // Check if the element is associated with the original boundaries
26367  const unsigned nbound = this->initial_shared_boundary_id();
26368 
26369  // Get the number of processors
26370  const unsigned nproc = this->communicator_pt()->nproc();
26371 
26372  // ------------------------------------------------------------------
26373  // Stores the information regarding the boundaries associated to the
26374  // element (it that is the case)
26375  Vector<unsigned> associated_boundaries;
26376  Vector<unsigned> face_index_on_boundary;
26377 
26378  unsigned counter_face_indexes = 0;
26379 
26380  for (unsigned b = 0; b < nbound; b++)
26381  {
26382  // Get the number of elements associated to boundary i
26383  const unsigned nboundary_ele = nboundary_element(b);
26384  for (unsigned e = 0; e < nboundary_ele; e++)
26385  {
26386  if (ele_pt == this->boundary_element_pt(b, e))
26387  {
26388  // Keep track of the boundaries associated to the element
26389  associated_boundaries.push_back(b);
26390  // Get the face index
26391  face_index_on_boundary.push_back(face_index_at_boundary(b, e));
26392  counter_face_indexes++;
26393 #ifdef PARANOID
26394  if (counter_face_indexes > 2)
26395  {
26396  std::stringstream error_message;
26397  error_message
26398  << "A triangular element can not have more than two of its faces "
26399  << "on a boundary!!!\n\n";
26400  throw OomphLibError(error_message.str(),
26401  "RefineableTriangleMesh::get_required_"
26402  "elemental_information_helper()",
26403  OOMPH_EXCEPTION_LOCATION);
26404  }
26405 #else
26406  // Already found 2 face indexes on the same boundary?
26407  if (counter_face_indexes == 2)
26408  {
26409  break;
26410  }
26411 #endif // #ifdef PARANOID
26412 
26413  } // if (ele_pt == this->boundary_element_pt(b,e))
26414 
26415  } // (e < nboundary_ele)
26416 
26417  } // (b < nbound)
26418 
26419  // If the element is associated to any boundary then package all the
26420  // relevant info
26421  const unsigned nassociated_boundaries = associated_boundaries.size();
26422  if (nassociated_boundaries > 0)
26423  {
26424  Flat_packed_unsigneds.push_back(1);
26425 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26426  Flat_packed_unsigneds_string.push_back(
26427  "The element is a boundary element");
26428 #endif
26429  Flat_packed_unsigneds.push_back(nassociated_boundaries);
26430 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26431  std::stringstream junk;
26432  junk << "The elements is associated to " << nassociated_boundaries
26433  << " boundaries";
26434  Flat_packed_unsigneds_string.push_back(junk.str());
26435 #endif
26436 
26437  // Package the ids of the associated boundaries and the
26438  // corresponding face index for each boundary (if the element is a
26439  // corner element, it will have two faces associated to the
26440  // boundary)
26441  for (unsigned i = 0; i < nassociated_boundaries; i++)
26442  {
26443  unsigned b = associated_boundaries[i];
26444  Flat_packed_unsigneds.push_back(b);
26445 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26446  std::stringstream junk;
26447  junk << "Element associated to boundary " << b << " of "
26448  << nassociated_boundaries << " total associated boundaries";
26449  Flat_packed_unsigneds_string.push_back(junk.str());
26450 #endif
26451  unsigned f = face_index_on_boundary[i];
26452  Flat_packed_unsigneds.push_back(f);
26453 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26454  std::stringstream junk2;
26455  junk2 << "Face index " << f << " for associated boundary " << b;
26456  Flat_packed_unsigneds_string.push_back(junk2.str());
26457 #endif
26458  }
26459 
26460  // If the element is associated to any boundary then we should
26461  // check if the mesh has regions, if that is the case then we need
26462  // to check to which region the boundary element does belong
26463 
26464  // If the mesh has regions we should look for the element
26465  // associated to a boundary and a specified region
26466  Vector<Vector<unsigned>> associated_boundaries_and_regions;
26467  Vector<unsigned> face_index_on_boundary_and_region;
26468 
26469  // Now check for the case when we have regions in the mesh
26470  const unsigned n_regions = this->nregion();
26471  if (n_regions > 1)
26472  {
26473  // Used to count the number of faces associated with
26474  // boundary-regions
26475  unsigned counter_face_indexes_in_regions = 0;
26476  // Loop over the boundaries
26477  for (unsigned b = 0; b < nbound; b++)
26478  {
26479  // Go through each region by getting the region id
26480  for (unsigned i_reg = 0; i_reg < n_regions; i_reg++)
26481  {
26482  // Get thre region id associated with the (i_reg)-th region
26483  const unsigned region_id =
26484  static_cast<unsigned>(this->Region_attribute[i_reg]);
26485 
26486  // Loop over all elements associated with the current boundary
26487  // and the i_reg-th region and check if the element is part of
26488  // any region
26489  const unsigned nele_in_region =
26490  this->nboundary_element_in_region(b, region_id);
26491  for (unsigned ee = 0; ee < nele_in_region; ee++)
26492  {
26493  // Check if the boundary-region element is the same as the
26494  // element
26495  if (ele_pt ==
26496  this->boundary_element_in_region_pt(b, region_id, ee))
26497  {
26498  // Storage for the boundary and region associated to the
26499  // element
26500  Vector<unsigned> bound_and_region(2);
26501 
26502  // Keep track of the boundaries associated to the element
26503  bound_and_region[0] = b;
26504  // Keep track of the regions associated to the element
26505  bound_and_region[1] = region_id;
26506  // Add the boundaries and regions in the storage to be
26507  // sent to other processors
26508  associated_boundaries_and_regions.push_back(bound_and_region);
26509  // Get the face index and keep track of it
26510  face_index_on_boundary_and_region.push_back(
26511  this->face_index_at_boundary_in_region(b, region_id, ee));
26512 
26513  // Increase the number of faces of the element associated
26514  // to boundary-regions
26515  counter_face_indexes_in_regions++;
26516 
26517 #ifdef PARANOID
26518  if (counter_face_indexes_in_regions > 2)
26519  {
26520  std::stringstream error_message;
26521  error_message << "A triangular element can not have more "
26522  "than two of its\n"
26523  << "faces on a boundary!!!\n\n";
26524  throw OomphLibError(error_message.str(),
26525  "RefineableTriangleMesh::get_required_"
26526  "elemental_information_helper()",
26527  OOMPH_EXCEPTION_LOCATION);
26528  } // if (counter_face_indexes_in_regions > 2)
26529 #endif
26530 
26531  } // The element is a boundary-region element
26532 
26533  } // for (ee < nele_in_region)
26534 
26535  } // for (i_reg < n_regions)
26536 
26537  } // for (b < nbound)
26538 
26539  } // if (n_regions > 1)
26540 
26541  // Now package the info. to be sent to other processors
26542  const unsigned nassociated_boundaries_and_regions =
26543  associated_boundaries_and_regions.size();
26544  if (nassociated_boundaries_and_regions > 0)
26545  {
26546  Flat_packed_unsigneds.push_back(1);
26547 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26548  Flat_packed_unsigneds_string.push_back(
26549  "The element is associated to boundaries and regions");
26550 #endif
26551 
26552  Flat_packed_unsigneds.push_back(nassociated_boundaries_and_regions);
26553 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26554  std::stringstream junk;
26555  junk << "The element is associated to "
26556  << nassociated_boundaries_and_regions << " boundaries-regions";
26557  Flat_packed_unsigneds_string.push_back(junk.str());
26558 #endif
26559 
26560  // Package the ids of the associated boundaries, regions and the
26561  // corresponding face index for each boundary-region (if the
26562  // element is a corner element, it will have two faces
26563  // associated to the boundary-region)
26564  for (unsigned i = 0; i < nassociated_boundaries_and_regions; i++)
26565  {
26566  const unsigned b = associated_boundaries_and_regions[i][0];
26567  Flat_packed_unsigneds.push_back(b);
26568 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26569  std::stringstream junk;
26570  junk << "Element associated to boundary " << b << " of "
26571  << nassociated_boundaries_and_regions
26572  << " total associated boundaries-regions";
26573  Flat_packed_unsigneds_string.push_back(junk.str());
26574 #endif
26575 
26576  const unsigned r = associated_boundaries_and_regions[i][1];
26577  Flat_packed_unsigneds.push_back(r);
26578 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26579  std::stringstream junk2;
26580  junk2 << "Element associated to region " << r << " of "
26581  << nassociated_boundaries_and_regions
26582  << " total associated boundaries-regions";
26583  Flat_packed_unsigneds_string.push_back(junk2.str());
26584 #endif
26585 
26586  const unsigned f = face_index_on_boundary_and_region[i];
26587  Flat_packed_unsigneds.push_back(f);
26588 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26589  std::stringstream junk3;
26590  junk3 << "Face index " << f << " for associated boundary-region ("
26591  << b << "-" << r << ")";
26592  Flat_packed_unsigneds_string.push_back(junk3.str());
26593 #endif
26594  } // for (i < nassociated_boundaries_and_regions)
26595  } // if (nassociated_boundaries_and_regions > 0)
26596  else
26597  {
26598  Flat_packed_unsigneds.push_back(0);
26599 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26600  Flat_packed_unsigneds_string.push_back(
26601  "The element is NOT associated to boundaries and regions");
26602 #endif
26603  } // else if (nassociated_boundaries_and_regions > 0)
26604  }
26605  else
26606  {
26607  Flat_packed_unsigneds.push_back(0);
26608 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26609  Flat_packed_unsigneds_string.push_back(
26610  "The element is not associated to any original boundary");
26611 #endif
26612  }
26613 
26614  // ------------------------------------------------------------
26615  // Now review if the element is associated to a shared boundary
26616 
26617  // Store the shared boundaries, and therefore the face indexes
26618  // associated to the element
26619  Vector<unsigned> associated_shared_boundaries;
26620  Vector<unsigned> face_index_on_shared_boundary;
26621 
26622  // Get the shared boundaries in this processor
26623  Vector<unsigned> my_rank_shared_boundaries_ids;
26624  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
26625 
26626  // Get the number of shared boundaries
26627  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
26628  // Loop over the shared boundaries
26629  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
26630  {
26631  // Get the boundary id
26632  const unsigned sb = my_rank_shared_boundaries_ids[i];
26633 
26634  // Get the number of elements associated to shared boundary sb
26635  const unsigned nboundary_ele = this->nshared_boundary_element(sb);
26636  for (unsigned e = 0; e < nboundary_ele; e++)
26637  {
26638  if (ele_pt == this->shared_boundary_element_pt(sb, e))
26639  {
26640  // Keep track of the boundaries associated to the element
26641  associated_shared_boundaries.push_back(sb);
26642  // Get the face index
26643  face_index_on_shared_boundary.push_back(
26644  this->face_index_at_shared_boundary(sb, e));
26645  }
26646  } // (e < nboundary_ele)
26647  } // (i < nmy_rank_shd_bnd)
26648 
26649  // If the element is associated to a shared boundary then package
26650  // all the relevant info
26651  const unsigned nassociated_shared_boundaries =
26652  associated_shared_boundaries.size();
26653  if (nassociated_shared_boundaries > 0)
26654  {
26655  Flat_packed_unsigneds.push_back(3);
26656 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26657  Flat_packed_unsigneds_string.push_back(
26658  "The element is a shared boundary element");
26659 #endif
26660  Flat_packed_unsigneds.push_back(nassociated_shared_boundaries);
26661 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26662  std::stringstream junk;
26663  junk << "The elements is associated to " << nassociated_shared_boundaries
26664  << "shared boundaries";
26665  Flat_packed_unsigneds_string.push_back(junk.str());
26666 #endif
26667 
26668  // Package the ids of the associated boundaries
26669  for (unsigned i = 0; i < nassociated_shared_boundaries; i++)
26670  {
26671  const unsigned b = associated_shared_boundaries[i];
26672  Flat_packed_unsigneds.push_back(b);
26673 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26674  std::stringstream junk;
26675  junk << "Element associated to shared boundary " << b << " of "
26676  << nassociated_shared_boundaries << " total associated boundaries";
26677  Flat_packed_unsigneds_string.push_back(junk.str());
26678 #endif
26679 
26680  const unsigned f = face_index_on_shared_boundary[i];
26681  Flat_packed_unsigneds.push_back(f);
26682 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26683  std::stringstream junk2;
26684  junk2 << "Face index " << f << " for associated shared boundary " << b;
26685  Flat_packed_unsigneds_string.push_back(junk2.str());
26686 #endif
26687  }
26688  }
26689  else
26690  {
26691  Flat_packed_unsigneds.push_back(0);
26692 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26693  Flat_packed_unsigneds_string.push_back(
26694  "The element is not associated to any shared boundary");
26695 #endif
26696  }
26697 
26698  // Now check if the element is haloed with any processor
26699 
26700  // Store the index of the haloed element with the jproc
26701  Vector<Vector<unsigned>> index_haloed(nproc);
26702 
26703  // Loop over the processors
26704  for (unsigned jproc = 0; jproc < nproc; jproc++)
26705  {
26706  // Get the number of haloed elements with jproc
26707  const unsigned n_haloed_jproc = f_haloed_ele_pt[jproc].size();
26708  // Loop over the haloed elements with jproc
26709  for (unsigned ihd = 0; ihd < n_haloed_jproc; ihd++)
26710  {
26711  // Is a haloed element?
26712  if (ele_pt == f_haloed_ele_pt[jproc][ihd])
26713  {
26714  // Store the haloed index with the jproc processor
26715  index_haloed[jproc].push_back(ihd);
26716  // Break the searching with the jproc processor
26717  break;
26718  } // if (ele_pt == f_haloed_ele_pt[jproc][ihd])
26719 
26720  } // for (ihd < n_haloed_jproc)
26721 
26722  } // for (jproc < nproc)
26723 
26724  // Send the haloed info.
26725  // Loop over the processors
26726  for (unsigned jproc = 0; jproc < nproc; jproc++)
26727  {
26728  // Is the element haloed with the jproc processor
26729  const unsigned n_index_haloed_jproc = index_haloed[jproc].size();
26730  Flat_packed_unsigneds.push_back(n_index_haloed_jproc);
26731 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26732  Flat_packed_unsigneds_string.push_back(
26733  "The number of haloed indexes the element is with processor jproc");
26734 #endif
26735  for (unsigned ihd = 0; ihd < n_index_haloed_jproc; ihd++)
26736  {
26737  Flat_packed_unsigneds.push_back(index_haloed[jproc][ihd]);
26738 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26739  Flat_packed_unsigneds_string.push_back(
26740  "The haloed index of the element with jproc");
26741 #endif
26742  } // for (ihd < n_index_haloed_jproc)
26743 
26744  } // for (jproc < nproc)
26745  }
26746 
26747  //======================================================================
26748  /// Helper function to add nodes on a new domain as a result of
26749  /// load balance
26750  //======================================================================
26751  template<class ELEMENT>
26753  unsigned& iproc,
26754  Vector<Vector<FiniteElement*>>& f_halo_ele_pt,
26755  Vector<Node*>& new_nodes_on_domain,
26756  Node* nod_pt)
26757  {
26758  // Attempt to add this node to the new domain
26759  const unsigned nnew_nodes_on_domain = new_nodes_on_domain.size();
26760  const unsigned new_added_node_index =
26761  this->try_to_add_node_pt_load_balance(new_nodes_on_domain, nod_pt);
26762 
26763  // If it was added then the new index should match the size of the storage
26764  if (new_added_node_index == nnew_nodes_on_domain)
26765  {
26766  Flat_packed_unsigneds.push_back(1);
26767 
26768 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26769  std::stringstream junk;
26770  junk << "Node needs to be constructed [size="
26771  << Flat_packed_unsigneds.size() << "]; last entry: "
26772  << Flat_packed_unsigneds[Flat_packed_unsigneds.size() - 1];
26773  Flat_packed_unsigneds_string.push_back(junk.str());
26774 #endif
26775 
26776  // This helper function gets all the required information for the
26777  // specified node and stores it into MPI-sendable information
26778  // so that a new copy can be made on the receiving process
26779  get_required_nodal_information_load_balance_helper(
26780  f_halo_ele_pt, iproc, nod_pt);
26781  }
26782  else // It was already added
26783  {
26784  Flat_packed_unsigneds.push_back(0);
26785 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26786  std::stringstream junk;
26787  junk << "Node was already added [size=" << Flat_packed_unsigneds.size()
26788  << "]; last entry: "
26789  << Flat_packed_unsigneds[Flat_packed_unsigneds.size() - 1];
26790 
26791  Flat_packed_unsigneds_string.push_back(junk.str());
26792 #endif
26793 
26794  // This node has been already added, so tell the other process
26795  // its index in the equivalent storage
26796  Flat_packed_unsigneds.push_back(new_added_node_index);
26797 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26798  Flat_packed_unsigneds_string.push_back("new added node index");
26799 #endif
26800  }
26801  }
26802 
26803  //======start of get_required_nodal_information_load_balance_helper=======
26804  /// Helper function to get the required nodal information from an
26805  /// haloed node so that a fully-functional halo node (and therefore element)
26806  /// can be created on the receiving process
26807  //========================================================================
26808  template<class ELEMENT>
26811  Vector<Vector<FiniteElement*>>& f_halo_ele_pt,
26812  unsigned& iproc,
26813  Node* nod_pt)
26814  {
26815  unsigned my_rank = this->communicator_pt()->my_rank();
26816  const unsigned nproc = this->communicator_pt()->nproc();
26817 
26818  // Tell the halo copy of this node how many values there are
26819  // [NB this may be different for nodes within the same element, e.g.
26820  // when using Lagrange multipliers]
26821  unsigned n_val = nod_pt->nvalue();
26822  Flat_packed_unsigneds.push_back(n_val);
26823 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26824  Flat_packed_unsigneds_string.push_back("Number of values");
26825 #endif
26826 
26827  unsigned n_dim = nod_pt->ndim();
26828 
26829  // Default number of previous values to 1
26830  unsigned n_prev = 1;
26831  if (this->Time_stepper_pt != 0)
26832  {
26833  // Add number of history values to n_prev
26834  n_prev = this->Time_stepper_pt->ntstorage();
26835  }
26836 
26837  // -----------------------------------------------------
26838  // Is the node on an original boundary?
26839  // Store the original boundaries where the node may be
26840  Vector<unsigned> original_boundaries;
26841  // Loop over the original boundaries of the mesh and check if live
26842  // on one of them
26843  const unsigned n_bnd = this->initial_shared_boundary_id();
26844  for (unsigned bb = 0; bb < n_bnd; bb++)
26845  {
26846  // Which boundaries (could be more than one) is it on?
26847  if (nod_pt->is_on_boundary(bb))
26848  {
26849  original_boundaries.push_back(bb);
26850  }
26851  }
26852 
26853  const unsigned n_original_boundaries = original_boundaries.size();
26854  // Is the node on any original boundary?
26855  if (n_original_boundaries > 0)
26856  {
26857  // Indicate that the node is on an original boundary
26858  Flat_packed_unsigneds.push_back(2);
26859 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26860  Flat_packed_unsigneds_string.push_back(
26861  "Node is on the original boundaries");
26862 #endif
26863 
26864  Flat_packed_unsigneds.push_back(n_original_boundaries);
26865 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26866  std::stringstream junk;
26867  junk << "Node is on " << n_original_boundaries << " original boundaries";
26868  Flat_packed_unsigneds_string.push_back(junk.str());
26869 #endif
26870 
26871  // Loop over the original boundaries the node is on
26872  for (unsigned i = 0; i < n_original_boundaries; i++)
26873  {
26874  Flat_packed_unsigneds.push_back(original_boundaries[i]);
26875 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26876  std::stringstream junk;
26877  junk << "Node is on boundary " << original_boundaries[i] << " of "
26878  << nb;
26879  Flat_packed_unsigneds_string.push_back(junk.str());
26880 #endif
26881  // Get the boundary coordinate of the node
26882  Vector<double> zeta(1);
26883  nod_pt->get_coordinates_on_boundary(original_boundaries[i], zeta);
26884  Flat_packed_doubles.push_back(zeta[0]);
26885  }
26886  }
26887  else
26888  {
26889  // Indicate that the node is NOT on an original boundary
26890  Flat_packed_unsigneds.push_back(0);
26891 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26892  Flat_packed_unsigneds_string.push_back(
26893  "Node is on any original boundary");
26894 #endif
26895  }
26896 
26897  // -------------------------------------------------------
26898  // Is the node on shared boundaries?
26899  bool node_on_shared_boundary = false;
26900  // Loop over the shared boundaries with the iproc processors and
26901  // check if live on one of them
26902  const unsigned n_shd_bnd = this->nshared_boundaries(my_rank, iproc);
26903  for (unsigned bb = 0; bb < n_shd_bnd; bb++)
26904  {
26905  // Get the boundary id
26906  unsigned i_bnd = this->shared_boundaries_ids(my_rank, iproc, bb);
26907  // Which boundaries (could be more than one) is it on?
26908  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
26909  {
26910  node_on_shared_boundary = true;
26911  break;
26912  }
26913  }
26914 
26915  // If the node live on any of the shared boundaries with the iproc
26916  // processor then just get the node number according to the
26917  // sorted_shared_boundary_node_pt() scheme and send it accross
26918  if (node_on_shared_boundary)
26919  {
26920  Flat_packed_unsigneds.push_back(1);
26921 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26922  Flat_packed_unsigneds_string.push_back("Node is on shared boundary");
26923 #endif
26924 
26925  // Store the shared boundaries where the node is on
26926  Vector<unsigned> shd_boundaries;
26927  // Loop over the shared boundaries with the iproc processor
26928  for (unsigned bb = 0; bb < n_shd_bnd; bb++)
26929  {
26930  // Get the boundary id
26931  const unsigned i_bnd = this->shared_boundaries_ids(my_rank, iproc, bb);
26932  // Which boundaries (could be more than one) is it on?
26933  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
26934  {
26935  shd_boundaries.push_back(i_bnd);
26936  }
26937  }
26938 
26939  // Get the number of shared boundaries the node is on
26940  const unsigned n_shd_bnd_is_on = shd_boundaries.size();
26941  // Send the number of shared boundaries the node is on
26942  Flat_packed_unsigneds.push_back(n_shd_bnd_is_on);
26943 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26944  std::stringstream junk;
26945  junk << "Node is on " << n_shd_bnd_is_on << " shared boundaries";
26946  Flat_packed_unsigneds_string.push_back(junk.str());
26947 #endif
26948 
26949  // Loop over the shared boundaries to send their ids
26950  for (unsigned i = 0; i < n_shd_bnd_is_on; i++)
26951  {
26952  Flat_packed_unsigneds.push_back(shd_boundaries[i]);
26953 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26954  std::stringstream junk;
26955  junk << "Node is on boundary " << shd_boundaries[i] << " of " << nb;
26956  Flat_packed_unsigneds_string.push_back(junk.str());
26957 #endif
26958  }
26959 
26960  // Given that the node is on at least one boundary get the index
26961  // of the node in one of the boundaries and send this index
26962  unsigned shared_boundary_id = shd_boundaries[0];
26963  // Get the number of nodes on the given shared boundary
26964  const unsigned n_nodes_on_shared_boundary =
26965  nsorted_shared_boundary_node(shared_boundary_id);
26966  // Store the index of the node on the shared boundary
26967  unsigned index_node_on_shared_boundary;
26968 #ifdef PARANOID
26969  // Flag to know if the node has been found
26970  bool found_index_node_on_shared_boundary = false;
26971 #endif
26972  // Loop over the nodes on the shared boundary to find the node
26973  for (unsigned i = 0; i < n_nodes_on_shared_boundary; i++)
26974  {
26975  // Get the i-th node on the shared boundary
26976  Node* shared_node_pt =
26977  sorted_shared_boundary_node_pt(shared_boundary_id, i);
26978  // Is the node we are looking for
26979  if (shared_node_pt == nod_pt)
26980  {
26981  // Store the index
26982  index_node_on_shared_boundary = i;
26983 #ifdef PARANOID
26984  // Mark as found
26985  found_index_node_on_shared_boundary = true;
26986 #endif
26987  break; // break
26988  }
26989 
26990  } // for (i < nnodes_on_shared_boundary)
26991 
26992 #ifdef PARANOID
26993  if (!found_index_node_on_shared_boundary)
26994  {
26995  std::ostringstream error_message;
26996  error_message << "The index of the node on boundary ("
26997  << shared_boundary_id << ") was not found.\n"
26998  << "The node coordinates are (" << nod_pt->x(0) << ","
26999  << nod_pt->x(1) << ").\n";
27000  throw OomphLibError(
27001  error_message.str(),
27002  "RefineableTriangleMesh::get_required_nodal_information_helper()",
27003  OOMPH_EXCEPTION_LOCATION);
27004  }
27005 #endif
27006  // Send the index of the node on the shared boundary
27007  Flat_packed_unsigneds.push_back(index_node_on_shared_boundary);
27008 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27009  std::stringstream junk2;
27010  junk2 << "Node index on boundary " << boundaries[0] << " is "
27011  << index_node_on_shared_boundary;
27012  Flat_packed_unsigneds_string.push_back(junk2.str());
27013 #endif
27014 
27015  } // if (node_on_shared_boundary)
27016  else
27017  {
27018  // The node is not on a shared boundary
27019  Flat_packed_unsigneds.push_back(0);
27020 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27021  Flat_packed_unsigneds_string.push_back(
27022  "Node is not on a shared boundary");
27023 #endif
27024  }
27025 
27026  // ----------------------------------------------------------------
27027  // Is the node on any shared boundary where the receiver processor
27028  // is not involved?
27029 
27030  // Now check if the node is on a shared boundary created by the
27031  // current processor (my_rank) and other processor different that
27032  // the iproc processor. This info. will help to complete the sending
27033  // of halo(ed) information between processors
27034 
27035  // Flag to know if the node is on a shared boundary with other
27036  // processor
27037  bool node_on_shared_boundary_with_other_processors = false;
27038  // Count the number of other shared boundaries it could be on
27039  unsigned nshared_boundaries_with_other_processors_have_node = 0;
27040 
27041  // Loop over the shared boundaries of the sent processor (my_rank)
27042  // and other processors (jproc)
27043  for (unsigned jproc = 0; jproc < nproc; jproc++)
27044  {
27045  // Do not search with the iproc processor, that was done before
27046  // above
27047  if (jproc != iproc)
27048  {
27049  // Get the number of shared boundaries with the jproc processor
27050  const unsigned n_jshd_bnd = this->nshared_boundaries(my_rank, jproc);
27051  // Loop over the shared boundaries
27052  for (unsigned bb = 0; bb < n_jshd_bnd; bb++)
27053  {
27054  // Get the boundary id
27055  const unsigned j_shd_bnd =
27056  this->shared_boundaries_ids(my_rank, jproc, bb);
27057  // Is the node part of this boundary?
27058  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
27059  {
27060  // DEBP("Sending to");
27061  // DEBP(iproc);
27062  // DEBP("Pair of procs where other shared");
27063  // DEBP(my_rank);
27064  // DEBP(jproc);
27065  // DEBP(i_bnd);
27066  node_on_shared_boundary_with_other_processors = true;
27067  // Increase the counter for the number of shared boundaries
27068  // with other processors the node is on
27069  nshared_boundaries_with_other_processors_have_node++;
27070  } // if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt)
27071 
27072  } // for (bb<n_jshd_bnd)
27073 
27074  } // if (jproc != iproc)
27075 
27076  } // for (jproc < nproc)
27077 
27078  // If the node is on a shared boundary with another processor
27079  // (my_rank, jproc), then send the flag and look for the info.
27080  if (node_on_shared_boundary_with_other_processors)
27081  {
27082  Flat_packed_unsigneds.push_back(4);
27083 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27084  Flat_packed_unsigneds_string.push_back(
27085  "Node is on shared boundary no related with the received processor: 4");
27086 #endif
27087 
27088  // The number of packages of information that will be sent to the
27089  // "iproc" processor. This helps to know how many packages of data
27090  // read from the received processor
27091  Flat_packed_unsigneds.push_back(
27092  nshared_boundaries_with_other_processors_have_node);
27093 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27094  std::stringstream junk;
27095  junk << "Number of other shared boundaries that the node is on: "
27096  << nshared_boundaries_with_other_processors_have_node;
27097  Flat_packed_unsigneds_string.push_back(junk.str());
27098 #endif
27099 
27100  // Counter to ensure that the correct number of data has been sent
27101  unsigned counter_shd_bnd_with_other_procs_have_node = 0;
27102  // Loop over the shared boundaries with other processors and get:
27103  // 1) The processors defining the shared boundary
27104  // 2) The shared boundary id
27105  // 3) The index of the node on the shared boundary
27106  Vector<unsigned> other_processor_1;
27107  Vector<unsigned> other_processor_2;
27108  Vector<unsigned> shd_bnd_ids;
27109  Vector<unsigned> indexes;
27110  // Loop over the processors again
27111  for (unsigned jproc = 0; jproc < nproc; jproc++)
27112  {
27113  // Do not search with the iproc processor, that was done before
27114  // above
27115  if (jproc != iproc)
27116  {
27117  // Get the number of shared boundaries with the jproc
27118  // processor
27119  const unsigned n_jshd_bnd = this->nshared_boundaries(my_rank, jproc);
27120  for (unsigned bb = 0; bb < n_jshd_bnd; bb++)
27121  {
27122  // Get the boundary id
27123  const unsigned j_shd_bnd =
27124  this->shared_boundaries_ids(my_rank, jproc, bb);
27125  // Is the node part of this boundary?
27126  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
27127  {
27128  // Include the first processor
27129  other_processor_1.push_back(my_rank);
27130  // Include the second processor
27131  other_processor_2.push_back(jproc);
27132  // Include the shared boundary id
27133  shd_bnd_ids.push_back(j_shd_bnd);
27134  // Increase the counter for found shared boundaries with
27135  // other processors
27136  counter_shd_bnd_with_other_procs_have_node++;
27137  }
27138 
27139  } // for (bb < nshared_bnd)
27140 
27141  } // if (jproc != iproc)
27142 
27143  } // for (jproc < nproc)
27144 
27145  // Get the indexes of the node on all the shared boundaries where
27146  // it was found
27147  const unsigned n_other_processors = other_processor_1.size();
27148  // Loop over the processors where the node was found
27149  for (unsigned i = 0; i < n_other_processors; i++)
27150  {
27151  // Get the shared boundary id
27152  unsigned shd_bnd_id = shd_bnd_ids[i];
27153  // Get the number of nodes on that shared boundary
27154  const unsigned n_nodes_on_shd_bnd =
27155  nsorted_shared_boundary_node(shd_bnd_id);
27156 
27157 #ifdef PARANOID
27158  bool found_index_node_on_shared_boundary = false;
27159 #endif
27160  for (unsigned i = 0; i < n_nodes_on_shd_bnd; i++)
27161  {
27162  // Get the i-th shared boundary node
27163  Node* shared_node_pt = sorted_shared_boundary_node_pt(shd_bnd_id, i);
27164  // Is the same node?
27165  if (shared_node_pt == nod_pt)
27166  {
27167  // DEBP(i_node);
27168  // DEBP(nod_pt->x(0));
27169  // DEBP(nod_pt->x(1));
27170  // Include the index of the node
27171  indexes.push_back(i);
27172 #ifdef PARANOID
27173  // Mark as found the node
27174  found_index_node_on_shared_boundary = true;
27175 #endif
27176  break;
27177  } // if (shared_node_pt == nod_pt)
27178 
27179  } // for (i < n_nodes_on_shd_bnd)
27180 
27181 #ifdef PARANOID
27182  if (!found_index_node_on_shared_boundary)
27183  {
27184  std::ostringstream error_message;
27185  error_message << "The index of the node on boundary (" << shd_bnd_id
27186  << "), shared by other processors\nwas not found.\n"
27187  << "The node coordinates are (" << nod_pt->x(0) << ","
27188  << nod_pt->x(1) << ").\n";
27189  throw OomphLibError(
27190  error_message.str(),
27191  "RefineableTriangleMesh::get_required_nodal_information_helper()",
27192  OOMPH_EXCEPTION_LOCATION);
27193  }
27194 #endif
27195  } // for (i < n_other_processors)
27196 
27197  // Now send the info. but first check that the number of found
27198  // nodes be the same that the previously found shared boundaries
27199  // with the node
27200 #ifdef PARANOID
27201  if (counter_shd_bnd_with_other_procs_have_node !=
27202  nshared_boundaries_with_other_processors_have_node)
27203  {
27204  std::ostringstream error_message;
27205  error_message << "The number of shared boundaries where the node is on "
27206  << "is different:\n"
27207  << "nshared_boundaries_with_other_processors_have_node: ("
27208  << nshared_boundaries_with_other_processors_have_node
27209  << ")\n"
27210  << "counter_shd_bnd_with_other_procs_have_node: ("
27211  << counter_shd_bnd_with_other_procs_have_node << ")\n";
27212  throw OomphLibError(
27213  error_message.str(),
27214  "RefineableTriangleMesh::get_required_nodal_information_helper()",
27215  OOMPH_EXCEPTION_LOCATION);
27216  } // if (counter_shd_bnd_with_other_procs_have_node !=
27217  // nshared_boundaries_with_other_processors_have_node)
27218 #endif
27219 
27220  // Loop over the info. to send it
27221  for (unsigned i = 0; i < n_other_processors; i++)
27222  {
27223  Flat_packed_unsigneds.push_back(other_processor_1[i]);
27224 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27225  std::stringstream junk1;
27226  junk1 << "Processor where the other shared boundary "
27227  << "has the node: " << other_processor_1[i];
27228  Flat_packed_unsigneds_string.push_back(junk1.str());
27229 #endif
27230 
27231  Flat_packed_unsigneds.push_back(other_processor_2[i]);
27232 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27233  std::stringstream junk2;
27234  junk2 << "Processor where the other shared boundary "
27235  << "has the node: " << other_processor_2[i];
27236  Flat_packed_unsigneds_string.push_back(junk2.str());
27237 #endif
27238 
27239  Flat_packed_unsigneds.push_back(shd_bnd_ids[i]);
27240 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27241  std::stringstream junk3;
27242  junk3 << "Other shared boundary id where the node is on"
27243  << boundaries[i];
27244  Flat_packed_unsigneds_string.push_back(junk3.str());
27245 #endif
27246 
27247  Flat_packed_unsigneds.push_back(indexes[i]);
27248 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27249  std::stringstream junk4;
27250  junk4 << "Node index on other shared boundary " << boundaries[i]
27251  << " is " << indexes[i];
27252  Flat_packed_unsigneds_string.push_back(junk4.str());
27253 #endif
27254 
27255  } // for (i < n_other_processors)
27256 
27257  } // if (node_on_shared_boundary_with_other_processors)
27258  else
27259  {
27260  Flat_packed_unsigneds.push_back(0);
27261 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27262  Flat_packed_unsigneds_string.push_back(
27263  "Node is on any shared boundary with other processors");
27264 #endif
27265  } // else if (node_on_shared_boundary_with_other_processors)
27266 
27267  // It may still be possible that the node be shared with the
27268  // processor that receives the info. but it is neither on shared
27269  // boundary with the receiver processor nor on a shared boundary
27270  // with others processors. Think in the next case:
27271 
27272  // |-----|-----| - The elements in processor 3 need to be sent to
27273  // | 4 | 3 | processor 1, and that is all
27274  // |-----*-----| - When processor 1 receives the data from node (*)
27275  // | 1 | 2 | it just RE-CREATES it becasuse it is does not know
27276  // |-----|-----| that the node is also on the shared boundary that
27277  // processor 1 and 2 or processor 1 and 4 share.
27278 
27279  // This problem become even worse if there would be more processors
27280  // between processor 3 and 2, or/and processor 3 and 4. Think in
27281  // triangles sharing the node (*)
27282 
27283  // To solve this check if the node that we are trying to send is
27284  // part of the halo elements of the curreent processor (my_rank)
27285  // with any other processor (we need to check with all the
27286  // processors and not just with the processors to which we will send
27287  // to cover more cases)
27288 
27289  // Store the halo element number with jproc where the node was found
27290  Vector<Vector<unsigned>> halo_element_number(nproc);
27291  // Store the node number on the halo element where the node was found
27292  Vector<Vector<unsigned>> halo_node_number_in_halo_element(nproc);
27293 
27294  // Loop over the processor
27295  for (unsigned jproc = 0; jproc < nproc; jproc++)
27296  {
27297  // Get the number of halo elements with the jproc processor
27298  const unsigned n_halo_jproc = f_halo_ele_pt[jproc].size();
27299  // Loop over the halo elements
27300  for (unsigned jh = 0; jh < n_halo_jproc; jh++)
27301  {
27302  FiniteElement* halo_ele_pt = f_halo_ele_pt[jproc][jh];
27303  // Get the number of nodes of the halo element
27304  const unsigned n_node = halo_ele_pt->nnode();
27305  // Loop over the nodes
27306  for (unsigned n = 0; n < n_node; n++)
27307  {
27308  // Is the node part of the ih-th halo element with jproc
27309  if (nod_pt == halo_ele_pt->node_pt(n))
27310  {
27311  halo_element_number[jproc].push_back(jh);
27312  halo_node_number_in_halo_element[jproc].push_back(n);
27313  // break with the nodes, no need to look for more nodes in
27314  // the element
27315  break;
27316  } // if (nod_pt == halo_ele_pt->node_pt(n))
27317 
27318  } // for (n < n_node)
27319 
27320  } // for (jh < n_halo_jproc)
27321 
27322  } // for (jproc < nproc)
27323 
27324  // Send the info. related with if the node is on halo elements with
27325  // any processor
27326 
27327  // Loop over the processors
27328  for (unsigned jproc = 0; jproc < nproc; jproc++)
27329  {
27330  // Get the number of halo elements with jproc processor where the
27331  // node is
27332  const unsigned n_jproc_halo_ele_node_is_on =
27333  halo_element_number[jproc].size();
27334  // Send the number of halo elements with jproc where the node is
27335  Flat_packed_unsigneds.push_back(n_jproc_halo_ele_node_is_on);
27336 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27337  std::stringstream junk5;
27338  junk5 << "Node is on " << n_jproc_halo_ele_node_is_on << " halo "
27339  << "elements with " << jproc << "-th processor";
27340  Flat_packed_unsigneds_string.push_back(junk5.str());
27341 #endif
27342  // Send the halo elements indexes (which will be haloed elements
27343  // indexes in the receiver processor), and the indexes of the
27344  // nodes in each halo element
27345  for (unsigned i = 0; i < n_jproc_halo_ele_node_is_on; i++)
27346  {
27347  // The halo element index
27348  const unsigned halo_element_index = halo_element_number[jproc][i];
27349  Flat_packed_unsigneds.push_back(halo_element_index);
27350 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27351  std::stringstream junk6;
27352  junk6 << "Halo element index is (" << halo_element_index
27353  << ") with processor (" << jproc << ")";
27354  Flat_packed_unsigneds_string.push_back(junk6.str());
27355 #endif
27356  // The node index on the halo element
27357  const unsigned node_index = halo_node_number_in_halo_element[jproc][i];
27358  Flat_packed_unsigneds.push_back(node_index);
27359 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27360  std::stringstream junk7;
27361  junk7 << "The node index on the halo element index is (" << node_index;
27362  Flat_packed_unsigneds_string.push_back(junk7.str());
27363 #endif
27364 
27365  } // for (i < n_jproc_halo_ele_node_is_on)
27366 
27367  } // for (jproc < nproc)
27368 
27369  // Now check if it is required to send the info. of the node. If the
27370  // node is not on a shared boundary with the iproc processor then we
27371  // need to send the info.
27372 
27373  // Flag to indicate if it is on a halo element with the iproc
27374  // processor. If this flag is true then there is no need to send the
27375  // info. to create the node, in the receiver processor the info is
27376  // copied from the indicated haloed element-node
27377  bool on_halo_element_with_iproc_processor = false;
27378  if (halo_element_number[iproc].size() > 0)
27379  {
27380  on_halo_element_with_iproc_processor = true;
27381  } // if (halo_element_number[iproc].size() > 0)
27382 
27383  // if (!node_on_shared_boundary)
27384  if (!node_on_shared_boundary && !on_halo_element_with_iproc_processor)
27385  {
27386  // Send all the info. to create it
27387 
27388  // Is the Node algebraic? If so, send its ref values and
27389  // an indication of its geometric objects if they are stored
27390  // in the algebraic mesh
27391  AlgebraicNode* alg_nod_pt = dynamic_cast<AlgebraicNode*>(nod_pt);
27392  if (alg_nod_pt != 0)
27393  {
27394  // The external mesh should be algebraic
27395  AlgebraicMesh* alg_mesh_pt = dynamic_cast<AlgebraicMesh*>(this);
27396 
27397  // Get default node update function ID
27398  unsigned update_id = alg_nod_pt->node_update_fct_id();
27399  Flat_packed_unsigneds.push_back(update_id);
27400 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27401  Flat_packed_unsigneds_string.push_back("Alg Node update id");
27402 #endif
27403 
27404  // Get reference values at default...
27405  unsigned n_ref_val = alg_nod_pt->nref_value();
27406  Flat_packed_unsigneds.push_back(n_ref_val);
27407 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27408  Flat_packed_unsigneds_string.push_back("Alg Node n ref values");
27409 #endif
27410  for (unsigned i_ref_val = 0; i_ref_val < n_ref_val; i_ref_val++)
27411  {
27412  Flat_packed_doubles.push_back(alg_nod_pt->ref_value(i_ref_val));
27413  }
27414 
27415  // Access geometric objects at default...
27416  unsigned n_geom_obj = alg_nod_pt->ngeom_object();
27417  Flat_packed_unsigneds.push_back(n_geom_obj);
27418 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27419  Flat_packed_unsigneds_string.push_back("Alg Node n geom objects");
27420 #endif
27421  for (unsigned i_geom = 0; i_geom < n_geom_obj; i_geom++)
27422  {
27423  GeomObject* geom_obj_pt = alg_nod_pt->geom_object_pt(i_geom);
27424 
27425  // Check this against the stored geometric objects in mesh
27426  unsigned n_geom_list = alg_mesh_pt->ngeom_object_list_pt();
27427 
27428  // Default found index to zero
27429  unsigned found_geom_object = 0;
27430  for (unsigned i_list = 0; i_list < n_geom_list; i_list++)
27431  {
27432  if (geom_obj_pt == alg_mesh_pt->geom_object_list_pt(i_list))
27433  {
27434  found_geom_object = i_list;
27435  }
27436  }
27437  Flat_packed_unsigneds.push_back(found_geom_object);
27438 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27439  Flat_packed_unsigneds_string.push_back("Found geom object");
27440 #endif
27441  }
27442  } // (if alg_nod_pt!=0)
27443 
27444  // Is it a SolidNode?
27445  SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(nod_pt);
27446  if (solid_nod_pt != 0)
27447  {
27448  unsigned n_solid_val = solid_nod_pt->variable_position_pt()->nvalue();
27449  for (unsigned i_val = 0; i_val < n_solid_val; i_val++)
27450  {
27451  for (unsigned t = 0; t < n_prev; t++)
27452  {
27453  Flat_packed_doubles.push_back(
27454  solid_nod_pt->variable_position_pt()->value(t, i_val));
27455  }
27456  }
27457 
27458  Vector<double> values_solid_node;
27459  solid_nod_pt->add_values_to_vector(values_solid_node);
27460  const unsigned nvalues_solid_node = values_solid_node.size();
27461  Flat_packed_unsigneds.push_back(nvalues_solid_node);
27462 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27463  std::stringstream junk;
27464  junk << "Number of values solid node: " << nvalues_solid_node;
27465  Flat_packed_unsigneds_string.push_back(junk.str());
27466 #endif
27467  for (unsigned i = 0; i < nvalues_solid_node; i++)
27468  {
27469  Flat_packed_doubles.push_back(values_solid_node[i]);
27470  }
27471  }
27472 
27473  // Finally copy info required for all node types
27474  for (unsigned i_val = 0; i_val < n_val; i_val++)
27475  {
27476  for (unsigned t = 0; t < n_prev; t++)
27477  {
27478  Flat_packed_doubles.push_back(nod_pt->value(t, i_val));
27479  }
27480  }
27481 
27482  // Now do positions
27483  for (unsigned idim = 0; idim < n_dim; idim++)
27484  {
27485  for (unsigned t = 0; t < n_prev; t++)
27486  {
27487  Flat_packed_doubles.push_back(nod_pt->x(t, idim));
27488  // DEBP(nod_pt->x(t,idim));
27489  }
27490  }
27491 
27492  } // if (!node_on_shared_boundary && !on_halo_element_with_iproc_processor)
27493  }
27494 
27495  //======================================================================
27496  /// Helper function to create elements on the loop
27497  /// process based on the info received in
27498  /// send_and_received_elements_nodes_info
27499  //======================================================================
27500  template<class ELEMENT>
27502  unsigned& iproc,
27503  Vector<Vector<FiniteElement*>>& f_haloed_ele_pt,
27504  Vector<Vector<std::map<unsigned, FiniteElement*>>>&
27505  received_old_haloed_element_pt,
27506  Vector<FiniteElement*>& new_elements_on_domain,
27507  Vector<Node*>& new_nodes_on_domain,
27508  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
27509  other_proc_shd_bnd_node_pt,
27510  Vector<Vector<Vector<unsigned>>>& global_node_names,
27511  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
27512  Vector<Node*>& global_shared_node_pt)
27513  {
27514 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27515  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27516  << " Bool: New element needs to be constructed "
27517  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27518  << std::endl;
27519 #endif
27520 
27521  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
27522  {
27523  // Create a new element from the communicated values
27524  // and coords from the process that located zeta
27525  GeneralisedElement* new_el_pt = new ELEMENT;
27526 
27527  // Add the new element to the mesh - Do not add the element yet
27528  // since no retained elements still need to be deleted
27529  // this->add_element_pt(new_el_pt);
27530 
27531  // Cast to the FE pointer
27532  FiniteElement* f_el_pt = dynamic_cast<FiniteElement*>(new_el_pt);
27533 
27534  // Add the element to the new elements in the domain container
27535  new_elements_on_domain.push_back(f_el_pt);
27536 
27537  // Set any additional information for the element
27538  this->add_element_load_balance_helper(
27539  iproc, received_old_haloed_element_pt, f_el_pt);
27540 
27541  // Add nodes to the new element
27542  unsigned n_node = f_el_pt->nnode();
27543  for (unsigned j = 0; j < n_node; j++)
27544  {
27545  Node* new_nod_pt = 0;
27546 
27547  // Call the add halo node helper function
27548  add_received_node_load_balance_helper(new_nod_pt,
27549  f_haloed_ele_pt,
27550  received_old_haloed_element_pt,
27551  new_nodes_on_domain,
27552  other_proc_shd_bnd_node_pt,
27553  iproc,
27554  j,
27555  f_el_pt,
27556  global_node_names,
27557  node_name_to_global_index,
27558  global_shared_node_pt);
27559  }
27560  }
27561  else // the element already exists
27562  {
27563 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27564  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27565  << " Index of existing element "
27566  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27567  << std::endl;
27568 #endif
27569 
27570  // Incrase the index, we do anything else with the element
27571  Counter_for_flat_packed_unsigneds++;
27572 
27573  } // else the element already exists
27574  }
27575 
27576  //========start of add_element_load_balance_helper=====================
27577  /// Helper function to create elements on the loop
27578  /// process based on the info received in
27579  /// send_and_received_elements_nodes_info
27580  /// This function is in charge of verify if the element is associated
27581  /// to a boundary and associate to it if that is the case
27582  //======================================================================
27583  template<class ELEMENT>
27585  const unsigned& iproc,
27586  Vector<Vector<std::map<unsigned, FiniteElement*>>>&
27587  received_old_haloed_element_pt,
27588  FiniteElement* ele_pt)
27589  {
27590  // Get the number of processors
27591  const unsigned nproc = this->communicator_pt()->nproc();
27592 
27593 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27594  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27595  << " Bool: Element is associated to a boundary "
27596  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27597  << std::endl;
27598 #endif
27599 
27600  // Is on an original boundary?
27601  const unsigned is_on_original_boundary =
27602  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27603  if (is_on_original_boundary == 1)
27604  {
27605 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27606  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27607  << " How many boundaries are associated with the element "
27608  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27609  << std::endl;
27610 #endif
27611  // Number of boundaries the element is associated with
27612  const unsigned nassociated_boundaries =
27613  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27614 
27615  // Loop over the associated boundaries
27616  for (unsigned b = 0; b < nassociated_boundaries; b++)
27617  {
27618 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27619  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27620  << " Boundary associated to the element "
27621  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27622  << std::endl;
27623 #endif
27624 
27625  // The boundary id
27626  const unsigned bnd =
27627  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27628 
27629 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27630  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27631  << " Face index of the element "
27632  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27633  << std::endl;
27634 #endif
27635 
27636  // The face index
27637  const unsigned face_index =
27638  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27639 
27640  // Associate the element with the boundary and establish as many
27641  // face indexes it has
27642  this->Boundary_element_pt[bnd].push_back(ele_pt);
27643  this->Face_index_at_boundary[bnd].push_back(face_index);
27644 
27645  } // (b < nassociated_boundaries)
27646 
27647  // Here read the info. regarding the boundary-region of the element
27648 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27649  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27650  << " Bool: Element is associated to a boundary-region "
27651  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27652  << std::endl;
27653 #endif
27654 
27655  // Is the element associated to a boundary-region?
27656  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
27657  {
27658 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27659  oomph_info
27660  << "Rec:" << Counter_for_flat_packed_unsigneds
27661  << " How many boundaries-regions are associated with the element "
27662  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27663  << std::endl;
27664 #endif
27665  // Number of boundary-regions the element is associated
27666  const unsigned nassociated_boundaries_and_regions =
27667  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27668 
27669  for (unsigned br = 0; br < nassociated_boundaries_and_regions; br++)
27670  {
27671 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27672  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27673  << " Boundary associated to the element "
27674  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27675  << std::endl;
27676 #endif
27677  // The boundary id
27678  const unsigned bnd =
27679  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27680 
27681 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27682  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27683  << " Region associated to the element "
27684  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27685  << std::endl;
27686 #endif
27687  // The region id
27688  const unsigned region =
27689  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27690 
27691 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27692  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27693  << " Face index of the element in boundary-region "
27694  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27695  << std::endl;
27696 #endif
27697  const unsigned face_index =
27698  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27699 
27700  // Associate the element with the boundary-regions and establish
27701  // as many face indexes it has
27702  this->Boundary_region_element_pt[bnd][region].push_back(ele_pt);
27703  this->Face_index_region_at_boundary[bnd][region].push_back(
27704  face_index);
27705 
27706  } // for (br < nassociated_boundaries_and_regions)
27707 
27708  } // Is the element associated with a boundary-region?
27709 
27710  } // The element is associated with an original boundary
27711 #ifdef PARANOID
27712  else
27713  {
27714  if (is_on_original_boundary != 0)
27715  {
27716  std::ostringstream error_message;
27717  error_message
27718  << "The current element is not on an original boundary, this should\n"
27719  << "be indicated by a zero flag. However, the read value for\n"
27720  << "that flag is (" << is_on_original_boundary << ").\n\n";
27721  throw OomphLibError(
27722  error_message.str(),
27723  "RefineableTriangleMesh::add_element_load_balance_helper()",
27724  OOMPH_EXCEPTION_LOCATION);
27725  } // if (is_on_shared_boundary != 0)
27726  }
27727 #endif
27728 
27729 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27730  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27731  << " Bool: Element is associated to a shared boundary "
27732  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27733  << std::endl;
27734 #endif
27735 
27736  // Is the element a shared boundary element?
27737  const unsigned is_on_shared_boundary =
27738  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27739  if (is_on_shared_boundary == 3)
27740  {
27741 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27742  oomph_info
27743  << "Rec:" << Counter_for_flat_packed_unsigneds
27744  << " How many shared boundaries are associated with the element "
27745  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27746  << std::endl;
27747 #endif
27748 
27749  // The number of shared boundaries the element is associated
27750  const unsigned nassociated_shared_boundaries =
27751  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27752 
27753  // Loop over the associated shared boundaries
27754  for (unsigned b = 0; b < nassociated_shared_boundaries; b++)
27755  {
27756 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27757  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27758  << " Shared boundary associated to the element "
27759  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27760  << std::endl;
27761 #endif
27762  const unsigned bnd =
27763  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27764 
27765 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27766  oomph_info
27767  << "Rec:" << Counter_for_flat_packed_unsigneds
27768  << " Face index of the element associated to the shared boundary "
27769  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27770  << std::endl;
27771 #endif
27772 
27773  const unsigned face_index =
27774  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27775 
27776  this->add_shared_boundary_element(bnd, ele_pt);
27777  this->add_face_index_at_shared_boundary(bnd, face_index);
27778 
27779  } // (b < nassociated_shared_boundaries)
27780 
27781  } // The element is associted with a shared boundary
27782 #ifdef PARANOID
27783  else
27784  {
27785  if (is_on_shared_boundary != 0)
27786  {
27787  std::ostringstream error_message;
27788  error_message
27789  << "The current element is not on a shared boundary, this should\n"
27790  << "be indicated by a zero flag. However, the read value for\n"
27791  << "that flag is (" << is_on_shared_boundary << ").\n\n";
27792  throw OomphLibError(
27793  error_message.str(),
27794  "RefineableTriangleMesh::add_element_load_balance_helper()",
27795  OOMPH_EXCEPTION_LOCATION);
27796  } // if (is_on_shared_boundary != 0)
27797  }
27798 #endif
27799 
27800  // Now check if the element is a haloed element in the sender
27801  // processor with any other processor
27802 
27803  // Loop over the processors
27804  for (unsigned jproc = 0; jproc < nproc; jproc++)
27805  {
27806 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27807  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27808  << " Bool: Number of haloed indexes of the element with the "
27809  << jproc << " processor: "
27810  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27811  << std::endl;
27812 #endif
27813  // Is the element haloed with the jproc processor
27814  const unsigned n_index_haloed_jproc =
27815  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27816  // Loop over the number of haloed indexes
27817  for (unsigned ihd = 0; ihd < n_index_haloed_jproc; ihd++)
27818  {
27819 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27820  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27821  << " Bool: The haloed element index with the " << jproc
27822  << " processor: "
27823  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27824  << std::endl;
27825 #endif
27826  const unsigned haloed_index =
27827  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27828 
27829  // Set the halod element in the proper storage
27830  received_old_haloed_element_pt[iproc][jproc][haloed_index] = ele_pt;
27831 
27832  } // for (ihd < n_index_haloed_jproc)
27833 
27834  } // for (jproc < nproc)
27835  }
27836 
27837  //======================================================================
27838  /// Helper function to add a new node from load balance
27839  //======================================================================
27840  template<class ELEMENT>
27842  Node*& new_nod_pt,
27843  Vector<Vector<FiniteElement*>>& f_haloed_ele_pt,
27844  Vector<Vector<std::map<unsigned, FiniteElement*>>>&
27845  received_old_haloed_element_pt,
27846  Vector<Node*>& new_nodes_on_domain,
27847  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
27848  other_proc_shd_bnd_node_pt,
27849  unsigned& iproc,
27850  unsigned& node_index,
27851  FiniteElement* const& new_el_pt,
27852  Vector<Vector<Vector<unsigned>>>& global_node_names,
27853  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
27854  Vector<Node*>& global_shared_node_pt)
27855  {
27856  // Given the node, received information about it from processor
27857  // iproc, construct it on the current process
27858 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27859  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27860  << " Bool: New node needs to be constructed "
27861  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27862  << std::endl;
27863 #endif
27864  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
27865  {
27866  // Construct a new node based upon sent information, or copy a node
27867  // from one of the shared boundaries
27868  construct_new_node_load_balance_helper(new_nod_pt,
27869  f_haloed_ele_pt,
27870  received_old_haloed_element_pt,
27871  new_nodes_on_domain,
27872  other_proc_shd_bnd_node_pt,
27873  iproc,
27874  node_index,
27875  new_el_pt,
27876  global_node_names,
27877  node_name_to_global_index,
27878  global_shared_node_pt);
27879  }
27880  else
27881  {
27882 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27883  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27884  << " Index of existing halo node "
27885  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27886  << std::endl;
27887 #endif
27888  // The node already exist, copy it from the indicated position
27889 
27890  // Get the node's index, and copy it
27891  new_nod_pt = new_nodes_on_domain
27892  [Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]];
27893 
27894  // Set the node in the current element
27895  new_el_pt->node_pt(node_index) = new_nod_pt;
27896  }
27897  }
27898 
27899  //============start_of_construct_new_node_load_balance_helper()=========
27900  /// Helper function which constructs a new node (on an
27901  /// element) with the information sent from the load balance
27902  /// process
27903  //======================================================================
27904  template<class ELEMENT>
27906  Node*& new_nod_pt,
27907  Vector<Vector<FiniteElement*>>& f_haloed_ele_pt,
27908  Vector<Vector<std::map<unsigned, FiniteElement*>>>&
27909  received_old_haloed_element_pt,
27910  Vector<Node*>& new_nodes_on_domain,
27911  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
27912  other_proc_shd_bnd_node_pt,
27913  unsigned& iproc,
27914  unsigned& node_index,
27915  FiniteElement* const& new_el_pt,
27916  Vector<Vector<Vector<unsigned>>>& global_node_names,
27917  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
27918  Vector<Node*>& global_shared_node_pt)
27919  {
27920  // Get the number of processors
27921  const unsigned nproc = this->communicator_pt()->nproc();
27922  // Get the rank of the current processor
27923  const unsigned my_rank = this->communicator_pt()->my_rank();
27924 
27925  // The first entry indicates the number of values at this new Node
27926  //(which may be different across the same element e.g. Lagrange multipliers)
27927 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27928  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27929  << " Number of values of external halo node "
27930  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27931  << std::endl;
27932 #endif
27933  unsigned n_val = Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27934 
27935  // Null TimeStepper for now
27936  TimeStepper* time_stepper_pt = this->Time_stepper_pt;
27937  // Default number of previous values to 1
27938  unsigned n_prev = time_stepper_pt->ntstorage();
27939 
27940  // ------------------------------------------------------
27941  // Check if the node is on an original boundary
27942 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27943  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27944  << " Is the node on an original boundary "
27945  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27946  << std::endl;
27947 #endif
27948 
27949  // Flag to indicate if the node is on original boundaries
27950  const unsigned node_on_original_boundaries =
27951  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27952 
27953  // Store the original boundaries where the node is on
27954  Vector<unsigned> original_boundaries_node_is_on;
27955  // Store the zeta coordinates of the node on the original boundaries
27956  Vector<double> zeta_coordinates;
27957  // Store the number of original boundaries the node is on
27958  unsigned n_original_boundaries_node_is_on = 0;
27959 
27960  if (node_on_original_boundaries == 2)
27961  {
27962  // How many original boundaries does the node live on?
27963 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27964  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27965  << " Number of boundaries the node is on: "
27966  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27967  << std::endl;
27968 #endif
27969  n_original_boundaries_node_is_on =
27970  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27971 
27972  // Resize the containers
27973  original_boundaries_node_is_on.resize(n_original_boundaries_node_is_on);
27974  zeta_coordinates.resize(n_original_boundaries_node_is_on);
27975 
27976  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
27977  {
27978  // Boundary number
27979 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27980  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27981  << " Node is on boundary "
27982  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27983  << std::endl;
27984 #endif
27985  original_boundaries_node_is_on[i] =
27986  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27987  zeta_coordinates[i] =
27988  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
27989  }
27990 
27991  } // if (node_on_original_boundaries==2)
27992 #ifdef PARANOID
27993  else
27994  {
27995  if (node_on_original_boundaries != 0)
27996  {
27997  std::ostringstream error_message;
27998  error_message
27999  << "The current node is not on an original boundary, this should\n"
28000  << "be indicated by a zero flag. However, the read value for\n"
28001  << "that flag is (" << node_on_original_boundaries << ").\n\n";
28002  throw OomphLibError(
28003  error_message.str(),
28004  "RefineableTriangleMesh::construct_new_halo_node_helper()",
28005  OOMPH_EXCEPTION_LOCATION);
28006  } // if (node_on_original_boundaries != 0)
28007  }
28008 #endif
28009 
28010  // --------------------------------------------------------------
28011  // Check if the node was on a shared boundary with the iproc
28012  // processor
28013 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28014  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28015  << " Is node on shared boundary? "
28016  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28017  << std::endl;
28018 #endif
28019  const unsigned is_node_on_shared_boundary =
28020  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28021  if (is_node_on_shared_boundary == 1)
28022  {
28023  // How many shared boundaries does the node live on?
28024 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28025  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28026  << " Number of boundaries the node is on: "
28027  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28028  << std::endl;
28029 #endif
28030  const unsigned n_shd_bnd_node_is_on =
28031  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28032  Vector<unsigned> shd_bnds_node_is_on(n_shd_bnd_node_is_on);
28033  for (unsigned i = 0; i < n_shd_bnd_node_is_on; i++)
28034  {
28035  // Shared boundary number
28036 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28037  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28038  << " Node is on boundary "
28039  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28040  << std::endl;
28041 #endif
28042  shd_bnds_node_is_on[i] =
28043  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28044  }
28045 
28046  // Get the index of the node on the shared boundary
28047 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28048  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28049  << " Index of node on boundary "
28050  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28051  << std::endl;
28052 #endif
28053  // Get the node index of the node on the shared boundary
28054  unsigned node_index_on_shared_boundary =
28055  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28056 
28057  // Get the pointer to the node with the received info.
28058  new_nod_pt = this->sorted_shared_boundary_node_pt(
28059  shd_bnds_node_is_on[0], node_index_on_shared_boundary);
28060 
28061  } // if (is_node_on_shared_boundary == 1)
28062 #ifdef PARANOID
28063  else
28064  {
28065  if (is_node_on_shared_boundary != 0)
28066  {
28067  std::ostringstream error_message;
28068  error_message
28069  << "The current node is not on a shared boundary, this should\n"
28070  << "be indicated by a zero flag. However, the read value for\n"
28071  << "that flag is (" << is_node_on_shared_boundary << ").\n\n";
28072  throw OomphLibError(
28073  error_message.str(),
28074  "RefineableTriangleMesh::construct_new_halo_node_helper()",
28075  OOMPH_EXCEPTION_LOCATION);
28076  } // if (node_on_shared_boundary != 0)
28077  }
28078 #endif
28079 
28080  // ------------------------------------------------------------
28081  // Is the node on a shared boundary with other processor?
28082 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28083  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28084  << " Is the node on shared boundaries with other processors "
28085  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28086  << std::endl;
28087 #endif
28088 
28089  // Is the node in shared boundaries no associated with the
28090  // receiver processor
28091  const unsigned is_the_node_in_shared_boundaries_with_other_processors =
28092  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28093 
28094  // The containers where to store the info.
28095  Vector<unsigned> other_processor_1;
28096  Vector<unsigned> other_processor_2;
28097  Vector<unsigned> other_shared_boundaries;
28098  Vector<unsigned> other_indexes;
28099 
28100  // How many shared bounaries with other processors the node lives on
28101  unsigned n_shd_bnd_with_other_procs_have_node = 0;
28102 
28103  // Is the node on shared boundaries with other processors
28104  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
28105  {
28106 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28107  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28108  << " In how many shared boundaries with other "
28109  << "processors is the node "
28110  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28111  << std::endl;
28112 #endif
28113 
28114  // How many nodes on other shared boundaries were found
28115  n_shd_bnd_with_other_procs_have_node =
28116  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28117 
28118  // Resize the containers
28119  other_processor_1.resize(n_shd_bnd_with_other_procs_have_node);
28120  other_processor_2.resize(n_shd_bnd_with_other_procs_have_node);
28121  other_shared_boundaries.resize(n_shd_bnd_with_other_procs_have_node);
28122  other_indexes.resize(n_shd_bnd_with_other_procs_have_node);
28123 
28124  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
28125  {
28126 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28127  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28128  << " Processor where the other shared boundary"
28129  << "has the node"
28130  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28131  << std::endl;
28132 #endif
28133  // Read the other processor 1
28134  other_processor_1[i] =
28135  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28136 
28137 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28138  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28139  << " Processor where the other shared boundary"
28140  << "has the node"
28141  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28142  << std::endl;
28143 #endif
28144  // Read the other processor 2
28145  other_processor_2[i] =
28146  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28147 
28148 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28149  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28150  << " Other shared boundary id where the node is on: "
28151  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28152  << std::endl;
28153 #endif
28154 
28155  // Read the other shared boundary id
28156  other_shared_boundaries[i] =
28157  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28158 
28159 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28160  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28161  << " Node index on the other shared boundary "
28162  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28163  << std::endl;
28164 #endif
28165 
28166  // Read the node index on the other shared boundary
28167  other_indexes[i] =
28168  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28169 
28170  } // for (i < n_shd_bnd_with_other_procs_have_node)
28171 
28172  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
28173 #ifdef PARANOID
28174  else
28175  {
28176  if (is_the_node_in_shared_boundaries_with_other_processors != 0)
28177  {
28178  std::ostringstream error_message;
28179  error_message
28180  << "The current node is not on a shared boundary with\n"
28181  << "other processors, this should be indicated by a zero flag.\n"
28182  << "However, the read value for that flag is ("
28183  << is_the_node_in_shared_boundaries_with_other_processors << ").\n\n";
28184  throw OomphLibError(
28185  error_message.str(),
28186  "RefineableTriangleMesh::construct_new_node_load_balance_helper()",
28187  OOMPH_EXCEPTION_LOCATION);
28188  }
28189  }
28190 #endif
28191 
28192  // ------------------------------------------------------------
28193  // Receive the info. to check if the node is on a haloed element
28194  // with any processor
28195 
28196  // Store the halo element number with jproc where the node was found
28197  Vector<Vector<unsigned>> halo_element_number(nproc);
28198  // Store the node number on the halo element where the node was found
28199  Vector<Vector<unsigned>> halo_node_number_in_halo_element(nproc);
28200 
28201  // Loop over the processors
28202  for (unsigned jproc = 0; jproc < nproc; jproc++)
28203  {
28204 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28205  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28206  << " The node is on "
28207  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28208  << " halo elements with " << jproc << " processor"
28209  << std::endl;
28210 #endif
28211  // Get the number of halo elements with jproc processor where the
28212  // node was found
28213  const unsigned n_jproc_halo_ele_node_is_on =
28214  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28215 
28216  // Resize the containers
28217  halo_element_number[jproc].resize(n_jproc_halo_ele_node_is_on);
28218  halo_node_number_in_halo_element[jproc].resize(
28219  n_jproc_halo_ele_node_is_on);
28220 
28221  // Read halo elements indexes (which are indexes of the halo
28222  // elements of the sender processor (iproc) with other processors
28223  // (included my_rank)
28224  for (unsigned i = 0; i < n_jproc_halo_ele_node_is_on; i++)
28225  {
28226  // Get the halo element index in the jproc processor
28227 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28228  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28229  << " The halo element index where the node is on "
28230  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28231  << std::endl;
28232 #endif
28233  // Get the node index on the halo element
28234  const unsigned halo_ele_index =
28235  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28236 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28237  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28238  << " The node index on the halo element where the node "
28239  << "is on "
28240  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28241  << std::endl;
28242 #endif
28243  const unsigned node_index_on_halo_ele =
28244  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28245 
28246  // Store the halo element number
28247  halo_element_number[jproc][i] = halo_ele_index;
28248  // Store the index of on the haloed element
28249  halo_node_number_in_halo_element[jproc][i] = node_index_on_halo_ele;
28250 
28251  } // for (i < n_jproc_halo_ele_node_is_on)
28252 
28253  } // for (jproc < nproc)
28254 
28255  // Store the node pointers obtained from the indicated halo elements
28256  // (use a set to check for the case when the node pointer is
28257  // different)
28258  std::set<Node*> set_haloed_node_pt;
28259 
28260  // Store the node pointer obtained from the haloed elements
28261  Node* haloed_node_pt = 0;
28262 
28263  // Flag to indicate if it is on a haloed element of the current
28264  // processor with the iproc processor. If this flag is true then
28265  // there is no need to read the info. to create the node, only copy
28266  // the node from the indicated haloed element-node
28267  bool on_haloed_element_with_iproc_processor = false;
28268  if (halo_element_number[my_rank].size() > 0)
28269  {
28270  // The node is part of the haloed element in the current processor
28271  // (my_rank) with the receiver processor
28272  on_haloed_element_with_iproc_processor = true;
28273 
28274  // Get the number of haloed elements in the current processor
28275  const unsigned n_haloed_indexes = halo_element_number[my_rank].size();
28276  // Loop over the different haloed indexes, and get the nodes
28277  // instances from all the indicated haloed elements (all of them
28278  // should be the same)
28279  for (unsigned i = 0; i < n_haloed_indexes; i++)
28280  {
28281  // Get the haloed element numbers where the node is on
28282  const unsigned haloed_index = halo_element_number[my_rank][i];
28283  // Get the node index on the haloed element
28284  const unsigned haloed_node_index =
28285  halo_node_number_in_halo_element[my_rank][i];
28286 
28287  // Get the haloed element (with iproc)
28288  FiniteElement* tmp_haloed_ele_pt = f_haloed_ele_pt[iproc][haloed_index];
28289  // Get the node on the indicated node number
28290  Node* tmp_haloed_node_pt =
28291  tmp_haloed_ele_pt->node_pt(haloed_node_index);
28292 
28293  // Set the pointer for the obtained haloed node
28294  haloed_node_pt = tmp_haloed_node_pt;
28295 
28296  // Add the node to the set of node pointers
28297  set_haloed_node_pt.insert(tmp_haloed_node_pt);
28298 
28299 #ifdef PARANOID
28300  if (set_haloed_node_pt.size() > 1)
28301  {
28302  std::ostringstream error_message;
28303  error_message
28304  << "When adding the " << haloed_node_index << " node of the "
28305  << haloed_index << "-th haloed element\n"
28306  << "in the currrent processor with the " << iproc << " processor"
28307  << "it was found that\nthe node pointer is different from the other"
28308  << "instances of the node.\nIt means we have a repeated node."
28309  << "This are the node coordinates of the previous node instances\n"
28310  << "The last entry is for the just added node with a different "
28311  "node\n"
28312  << "pointer\n";
28313  for (std::set<Node*>::iterator it = set_haloed_node_pt.begin();
28314  it != set_haloed_node_pt.end();
28315  it++)
28316  {
28317  error_message << "Node: (" << (*it)->x(0) << ", " << (*it)->x(1)
28318  << ")\n";
28319  }
28320  error_message << "\n";
28321  throw OomphLibError(
28322  error_message.str(),
28323  "RefineableTriangleMesh::construct_new_node_load_balance_helper()",
28324  OOMPH_EXCEPTION_LOCATION);
28325  }
28326 #endif
28327 
28328  } // for (i < n_haloed_indexes)
28329 
28330  } // if (halo_element_number[iproc].size() > 0)
28331 
28332  // Flag to indicate if the node has been found on a haloed element
28333  // of other processor with the iproc processor
28334  bool found_on_haloed_element_with_other_processor = false;
28335  // Loop over the processors (only until the iproc since no info. of
28336  // higher processors has been received)
28337  for (unsigned jproc = 0; jproc < iproc; jproc++)
28338  {
28339  // Is the node on a halo element with the jproc processor
28340  if (halo_element_number[jproc].size() > 0)
28341  {
28342  // Get the number of halo elements with the jproc processor
28343  const unsigned n_halo_indexes = halo_element_number[jproc].size();
28344  // Loop over the different halo indexes, and get the nodes
28345  // instances from all the indicated halo elements (all of them
28346  // should be the same)
28347  for (unsigned i = 0; i < n_halo_indexes; i++)
28348  {
28349  // Get the haloed element numbers where the node is on
28350  const unsigned haloed_index = halo_element_number[jproc][i];
28351  // Get the node index on the haloed element
28352  const unsigned haloed_node_index =
28353  halo_node_number_in_halo_element[jproc][i];
28354 
28355  // Have we received the indicated element? (Get the haloed
28356  // element on jproc with the iproc processor)
28357  std::map<unsigned, FiniteElement*>::iterator it_map =
28358  received_old_haloed_element_pt[jproc][iproc].find(haloed_index);
28359  // Have we received the indicated element?
28360  if (it_map != received_old_haloed_element_pt[jproc][iproc].end())
28361  {
28362  // Set the flag of found element in other processors haloed
28363  // element, in this case in haloed elements of processor
28364  // jproc wiht iproc processor
28365  found_on_haloed_element_with_other_processor = true;
28366 
28367  // Get the element
28368  FiniteElement* tmp_haloed_ele_pt = (*it_map).second;
28369  // Get the node on the indicated node number
28370  Node* tmp_haloed_node_pt =
28371  tmp_haloed_ele_pt->node_pt(haloed_node_index);
28372 
28373  // Set the pointer for the obtained haloed node
28374  haloed_node_pt = tmp_haloed_node_pt;
28375 
28376  // Add the node to the set of node pointers
28377  set_haloed_node_pt.insert(tmp_haloed_node_pt);
28378 
28379 #ifdef PARANOID
28380  if (set_haloed_node_pt.size() > 1)
28381  {
28382  std::ostringstream error_message;
28383  error_message
28384  << "When adding the " << haloed_node_index << " node of the "
28385  << haloed_index << "-th haloed element "
28386  << "of the " << jproc << " processor\nwith the " << iproc
28387  << " processor, it was found that\n"
28388  << "the node pointer is different from the other\n"
28389  << "instances of the node.\nThis means we have a repeated "
28390  "node.\n"
28391  << "These are the node coordinates of the previous node "
28392  << "instances\n"
28393  << "The last entry is for the just added node with a "
28394  "different\n"
28395  << "node pointer\n";
28396  for (std::set<Node*>::iterator it = set_haloed_node_pt.begin();
28397  it != set_haloed_node_pt.end();
28398  it++)
28399  {
28400  error_message << "Node: (" << (*it)->x(0) << ", " << (*it)->x(1)
28401  << ")\n";
28402  }
28403  error_message << "\n";
28404  throw OomphLibError(error_message.str(),
28405  "RefineableTriangleMesh::construct_new_node_"
28406  "load_balance_helper()",
28407  OOMPH_EXCEPTION_LOCATION);
28408  }
28409 #endif
28410 
28411  } // if (it_map != received_old_haloed_element_pt[jproc][iproc].end())
28412  // Have we received the element?
28413 
28414  } // for (i < n_haloed_indexes)
28415 
28416  } // if (halo_element_number[iproc].size() > 0)
28417 
28418  } // for (jproc < nproc)
28419 
28420  // If the node was found in the haloed elements of the current
28421  // processor with the iproc processor, or in the haloed elements of
28422  // any other processor with the iproc processor then copy the node
28423  // pointer (no problem if we overwrite the node info. it should be
28424  // the same node pointer)
28425  if (on_haloed_element_with_iproc_processor ||
28426  found_on_haloed_element_with_other_processor)
28427  {
28428  // Set the node pointer
28429  new_nod_pt = haloed_node_pt;
28430  }
28431 
28432  // Now we have all the info. to decide if the node should be created
28433  // or not
28434 
28435  // First check if the node is a shared boundary node, or if it has
28436  // been found on haloed elements
28437  if (is_node_on_shared_boundary == 1 ||
28438  (on_haloed_element_with_iproc_processor))
28439  {
28440  // We already have the node, we do not need to create it
28441 
28442  // Only check if we need to add boundary info. to the node
28443  if (node_on_original_boundaries == 2)
28444  {
28445  // The node is a boundary node, add the boundary info. before
28446  // adding it to the domain
28447 
28448  // Associate the node to the given boundaries
28449  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
28450  {
28451  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
28452  // Establish the boundary coordinates for the node
28453  Vector<double> zeta(1);
28454  zeta[0] = zeta_coordinates[i];
28455  new_nod_pt->set_coordinates_on_boundary(
28456  original_boundaries_node_is_on[i], zeta);
28457  }
28458 
28459  } // if (node_on_original_boundaries==2)
28460 
28461  // Add the node to the domain
28462  new_nodes_on_domain.push_back(new_nod_pt);
28463 
28464  // Add the node to the element
28465  new_el_pt->node_pt(node_index) = new_nod_pt;
28466 
28467  } // if (is_node_on_shared_boundary == 1)
28468 
28469  // Now check if the node is on a shared boundary with another
28470  // processor, if that is the case try to find the node that may have
28471  // been already sent by the other processors
28472 
28473  // This flags indicates if the node was found, and then decide if it
28474  // is required to create the node
28475  bool found_node_in_other_shared_boundaries = false;
28476  // Flag to indicate whether the node should be created as a boundary
28477  // node or not. If the node lies on a shared boundary with other
28478  // processor the we create it as a boundary node. The processor from
28479  // which we are receiving info. (iproc) may not know that the node
28480  // lies on an original boundary. If the node lies on an original
28481  // boundary then its info. will be sent by another processor, then
28482  // we can set its boundary info. since the node was constructed as a
28483  // boundary node
28484  bool build_node_as_boundary_node = false;
28485 
28486  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
28487  {
28488  // Build the node as a boundary node
28489  build_node_as_boundary_node = true;
28490 
28491  // Try to get the node pointer in case that the node has been
28492  // already sent by the other processors
28493 
28494  // Get the number of initial shared boundaries to correct the
28495  // index of the shared boundary
28496  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
28497 
28498  // Add the found nodes in the container, should be the same but
28499  // better check
28500  Vector<Node*> found_node_pt;
28501 
28502  // Now try to find the node in any of the other shared boundaries
28503  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
28504  {
28505  unsigned oproc1 = other_processor_1[i];
28506  unsigned oproc2 = other_processor_2[i];
28507 
28508  // Check that we always check with the lower processors number
28509  // first
28510  if (oproc1 > oproc2)
28511  {
28512  oproc2 = oproc1;
28513  oproc1 = other_processor_2[i];
28514  } // if (oproc1 > oproc2)
28515 
28516  // Re-compute the shared boundary id between the other
28517  // processors
28518  const unsigned shd_bnd_id =
28519  other_shared_boundaries[i] - initial_shd_bnd_id;
28520  // Read the index
28521  const unsigned index = other_indexes[i];
28522 
28523  // Check if there are nodes received from the other processor
28524  // and with the given shared boundary
28525  const unsigned n_nodes_on_other_processor =
28526  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].size();
28527 
28528  if (n_nodes_on_other_processor > 0)
28529  {
28530  // Check if we can find the index of the node in that other
28531  // processor and shared boundary id
28532  std::map<unsigned, Node*>::iterator it =
28533  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].find(index);
28534 
28535  // If the index exist then get the node pointer
28536  if (it !=
28537  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
28538  {
28539  // Mark the node as found
28540  found_node_in_other_shared_boundaries = true;
28541  // Get the node pointer
28542  Node* tmp_node_pt =
28543  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id][index];
28544  found_node_pt.push_back(tmp_node_pt);
28545  } // if (it!=
28546  // other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
28547 
28548  } // if (n_nodes_on_other_processor > 0)
28549 
28550  } // for (i < n_shd_bnd_with_other_procs_have_node)
28551 
28552  // If the node was found, then all their instances should be the
28553  // same but better check
28554  if (found_node_in_other_shared_boundaries)
28555  {
28556 #ifdef PARANOID
28557  const unsigned ntimes_node_found = found_node_pt.size();
28558  for (unsigned j = 1; j < ntimes_node_found; j++)
28559  {
28560  if (found_node_pt[j - 1] != found_node_pt[j])
28561  {
28562  std::ostringstream error_message;
28563  error_message
28564  << "The instances of the node that was found to be on a\n"
28565  << "shared boundary with other processors are not the same,\n"
28566  << "the coordinates for the nodes are these:\n"
28567  << "(" << found_node_pt[j - 1]->x(0) << ", "
28568  << found_node_pt[j - 1]->x(1) << ")\n"
28569  << "(" << found_node_pt[j]->x(0) << ", " << found_node_pt[j]->x(1)
28570  << ")\n"
28571  << "Not be surprised if they are the same since the node is\n"
28572  << "repeated!!!\n";
28573  throw OomphLibError(
28574  error_message.str(),
28575  "RefineableTriangleMesh::construct_new_halo_node_helper()",
28576  OOMPH_EXCEPTION_LOCATION);
28577 
28578  } // if (found_node_pt[j-1] != found_node_pt[j])
28579 
28580  } // for (j < ntimes_node_found)
28581 #endif
28582 
28583  // Check if the node is a shared boundary node from the current
28584  // processor and the iproc processor, if that is the case, and
28585  // the node is also on a shared boundary with other processor,
28586  // then the pointer should be the same!!!
28587  if (is_node_on_shared_boundary == 1)
28588  {
28589  // The pointer to the node is already assigned, it was
28590  // assigned when thenode was found to be on a shared boundary
28591  // with the iproc processor
28592  if (found_node_pt[0] != new_nod_pt)
28593  {
28594  std::ostringstream error_message;
28595  error_message
28596  << "The pointer of the node that was found to be on a\n"
28597  << "shared boundary with other processor(s) and the pointer\n"
28598  << "of the node on shared boundary with the receiver\n"
28599  << "processor (iproc) are not the same. This means we have a\n"
28600  << "repeated node)\n"
28601  << "The coordinates for the nodes are:\n"
28602  << "(" << found_node_pt[0]->x(0) << ", " << found_node_pt[0]->x(1)
28603  << ")\n"
28604  << "(" << new_nod_pt->x(0) << ", " << new_nod_pt->x(1) << ")\n"
28605  << "Not to be surprised if they are the same since the node is\n"
28606  << "repeated!!!\n";
28607  throw OomphLibError(
28608  error_message.str(),
28609  "RefineableTriangleMesh::construct_new_halo_node_helper()",
28610  OOMPH_EXCEPTION_LOCATION);
28611  } // if (found_node_pt[0] != new_nod_pt)
28612 
28613  } // if (is_node_on_shared_boundary == 1)
28614  else
28615  {
28616  // Take the first instance of the node in case that it was
28617  // found and is not on a shared boundary with the iproc
28618  // processor
28619  new_nod_pt = found_node_pt[0];
28620  }
28621 
28622  } // if (found_node_in_other_shared_boundaries)
28623 
28624  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
28625 
28626  // -----------------------------------------------------------------
28627  // Create the node or read the received info if the node is not on a
28628  // shared boundary with the iproc processor and if the node is not
28629  // part of the haloed elements with the iproc processor in the
28630  // current processors
28631  if (is_node_on_shared_boundary != 1 &&
28632  !on_haloed_element_with_iproc_processor)
28633  {
28634  // If the node is on a shared boundary with other processor we
28635  // need to read all the info. since the processor that sent the
28636  // info. did not know that the node is part of another shared
28637  // boundary
28638 
28639  // If the node is not a shared boundary (with any processor), or
28640  // if this is the first time that the info. of the node is
28641  // received from any of the processors with which is has a shared
28642  // boundary, then we create the node
28643 
28644  // Is the node a boundary node or should it be build as a boundary
28645  // node because it is on a shared boundary with other processors
28646  if (node_on_original_boundaries == 2 || build_node_as_boundary_node)
28647  {
28648  // Check if necessary to create the node, or if it has been
28649  // already found in shared boundaries with other processors or
28650  // in the haloed elements with of other processors with the
28651  // iproc processor
28652  if (!found_node_in_other_shared_boundaries ||
28653  !found_on_haloed_element_with_other_processor)
28654  {
28655  // Construct a boundary node
28656  if (time_stepper_pt != 0)
28657  {
28658  new_nod_pt =
28659  new_el_pt->construct_boundary_node(node_index, time_stepper_pt);
28660  }
28661  else
28662  {
28663  new_nod_pt = new_el_pt->construct_boundary_node(node_index);
28664  }
28665 
28666  } // if (!found_node_in_other_shared_boundaries ||
28667  // !found_on_haloed_element_with_other_processor)
28668  else
28669  {
28670  // If the node was found then assign the node to the element
28671  new_el_pt->node_pt(node_index) = new_nod_pt;
28672  } // else if (!found_node_in_other_shared_boundaries ||
28673  // !found_on_haloed_element_with_other_processor)
28674 
28675  // Associate the node to the given boundaries
28676  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
28677  {
28678  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
28679  // Establish the boundary coordinates for the node
28680  Vector<double> zeta(1);
28681  zeta[0] = zeta_coordinates[i];
28682  new_nod_pt->set_coordinates_on_boundary(
28683  original_boundaries_node_is_on[i], zeta);
28684  }
28685 
28686  } // if (node is on an original boundary)
28687  else
28688  {
28689  // Check if necessary to create the node, or if it has been
28690  // already found in shared boundaries with other processors or
28691  // in the haloed elements with of other processors with the
28692  // iproc processor
28693  if (!found_node_in_other_shared_boundaries ||
28694  !found_on_haloed_element_with_other_processor)
28695  {
28696  // Construct an ordinary (non-boundary) node
28697  if (time_stepper_pt != 0)
28698  {
28699  new_nod_pt = new_el_pt->construct_node(node_index, time_stepper_pt);
28700  }
28701  else
28702  {
28703  new_nod_pt = new_el_pt->construct_node(node_index);
28704  }
28705  } // if (!found_node_in_other_shared_boundaries ||
28706  // !found_on_haloed_element_with_other_processor)
28707  else
28708  {
28709  // If the node was found then assign the node to the element
28710  new_el_pt->node_pt(node_index) = new_nod_pt;
28711  } // else // if (!found_node_in_other_shared_boundaries ||
28712  // !found_on_haloed_element_with_other_processor)
28713 
28714  } // else (the node is not a boundary node)
28715 
28716  // ... and gather all its information
28717 
28718  // If the node was found or not in other shared boundaries, this
28719  // is the first time the node is received from this processor
28720  // (iproc), therefore it is added to the vector of nodes received
28721  // from this processor (iproc)
28722  new_nodes_on_domain.push_back(new_nod_pt);
28723 
28724  // Check if necessary to state all the info. to the node if it has
28725  // been already found in shared boundaries with other processors
28726  // or in the haloed elements with of other processors with the
28727  // iproc processor
28728  if (!found_node_in_other_shared_boundaries ||
28729  !found_on_haloed_element_with_other_processor)
28730  {
28731  // Add the node to the general node storage
28732  this->add_node_pt(new_nod_pt);
28733  } // if (!found_node_in_other_shared_boundaries ||
28734  // !found_on_haloed_element_with_other_processor)
28735 
28736  // Is the new constructed node Algebraic?
28737  AlgebraicNode* new_alg_nod_pt = dynamic_cast<AlgebraicNode*>(new_nod_pt);
28738 
28739  // If it is algebraic, its node update functions will
28740  // not yet have been set up properly
28741  if (new_alg_nod_pt != 0)
28742  {
28743  // The AlgebraicMesh is the external mesh
28744  AlgebraicMesh* alg_mesh_pt = dynamic_cast<AlgebraicMesh*>(this);
28745 
28746  /// The first entry of All_alg_nodal_info contains
28747  /// the default node update id
28748  /// e.g. for the quarter circle there are
28749  /// "Upper_left_box", "Lower right box" etc...
28750 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28751  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28752  << " Alg node update id "
28753  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28754  << std::endl;
28755 #endif
28756 
28757  unsigned update_id =
28758  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28759 
28760  Vector<double> ref_value;
28761 
28762  // The size of this vector is in the next entry
28763  // of All_alg_nodal_info
28764 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28765  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28766  << " Alg node # of ref values "
28767  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28768  << std::endl;
28769 #endif
28770  unsigned n_ref_val =
28771  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28772 
28773  // The reference values themselves are in
28774  // All_alg_ref_value
28775  ref_value.resize(n_ref_val);
28776  for (unsigned i_ref = 0; i_ref < n_ref_val; i_ref++)
28777  {
28778  ref_value[i_ref] =
28779  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
28780  }
28781 
28782  Vector<GeomObject*> geom_object_pt;
28783  /// again we need the size of this vector as it varies
28784  /// between meshes; we also need some indication
28785  /// as to which geometric object should be used...
28786 
28787  // The size of this vector is in the next entry
28788  // of All_alg_nodal_info
28789 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28790  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28791  << " Alg node # of geom objects "
28792  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28793  << std::endl;
28794 #endif
28795  unsigned n_geom_obj =
28796  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28797 
28798  // The remaining indices are in the rest of
28799  // All_alg_nodal_info
28800  geom_object_pt.resize(n_geom_obj);
28801  for (unsigned i_geom = 0; i_geom < n_geom_obj; i_geom++)
28802  {
28803 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28804  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28805  << " Alg node: geom object index "
28806  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28807  << std::endl;
28808 #endif
28809  unsigned geom_index =
28810  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28811  // This index indicates which of the AlgebraicMesh's
28812  // stored geometric objects should be used
28813  // (0 is a null pointer; everything else should have
28814  // been filled in by the specific Mesh). If it
28815  // hasn't been filled in then the update_node_update
28816  // call should fix it
28817  geom_object_pt[i_geom] = alg_mesh_pt->geom_object_list_pt(geom_index);
28818  }
28819 
28820  // Check if necessary to state all the info. to the node if it
28821  // has been already found in shared boundaries with other
28822  // processors or in the haloed elements with of other processors
28823  // with the iproc processor
28824  if (!found_node_in_other_shared_boundaries ||
28825  !found_on_haloed_element_with_other_processor)
28826  {
28827  /// For the received update_id, ref_value, geom_object
28828  /// call add_node_update_info
28829  new_alg_nod_pt->add_node_update_info(
28830  update_id, alg_mesh_pt, geom_object_pt, ref_value);
28831 
28832  /// Now call update_node_update
28833  alg_mesh_pt->update_node_update(new_alg_nod_pt);
28834 
28835  } // if (!found_node_in_other_shared_boundaries ||
28836  // !found_on_haloed_element_with_other_processor)
28837 
28838  } // if (new_alg_nod_pt!=0)
28839 
28840  // Check if necessary to state all the info. to the node if it has
28841  // been already found in shared boundaries with other processors
28842  // or in the haloed elements with of other processors with the
28843  // iproc processor
28844  if (!found_node_in_other_shared_boundaries ||
28845  !found_on_haloed_element_with_other_processor)
28846  {
28847  // Is the node a MacroElementNodeUpdateNode?
28848  MacroElementNodeUpdateNode* macro_nod_pt =
28849  dynamic_cast<MacroElementNodeUpdateNode*>(new_nod_pt);
28850 
28851  if (macro_nod_pt != 0)
28852  {
28853  // Need to call set_node_update_info; this requires
28854  // a Vector<GeomObject*> (taken from the mesh)
28855  Vector<GeomObject*> geom_object_vector_pt;
28856 
28857  // Access the required geom objects from the
28858  // MacroElementNodeUpdateMesh
28859  MacroElementNodeUpdateMesh* macro_mesh_pt =
28860  dynamic_cast<MacroElementNodeUpdateMesh*>(this);
28861  geom_object_vector_pt = macro_mesh_pt->geom_object_vector_pt();
28862 
28863  // Get local coordinate of node in new element
28864  Vector<double> s_in_macro_node_update_element;
28865  new_el_pt->local_coordinate_of_node(node_index,
28866  s_in_macro_node_update_element);
28867 
28868  // Set node update info for this node
28869  macro_nod_pt->set_node_update_info(
28870  new_el_pt, s_in_macro_node_update_element, geom_object_vector_pt);
28871  }
28872 
28873  } // if (!found_node_in_other_shared_boundaries ||
28874  // !found_on_haloed_element_with_other_processor)
28875 
28876  // If there are additional values, resize the node
28877  unsigned n_new_val = new_nod_pt->nvalue();
28878 
28879  // Check if necessary to state all the info. to the node if it has
28880  // been already found in shared boundaries with other processors
28881  // or in the haloed elements with of other processors with the
28882  // iproc processor
28883  if (!found_node_in_other_shared_boundaries ||
28884  !found_on_haloed_element_with_other_processor)
28885  {
28886  if (n_val > n_new_val)
28887  {
28888  // If it has been necessary to resize then it may be becuse
28889  // the node is on a FSI boundary, if that is the case we need
28890  // to set a map for these external values
28891 
28892  // Cast to a boundary node
28893  BoundaryNodeBase* bnod_pt =
28894  dynamic_cast<BoundaryNodeBase*>(new_nod_pt);
28895 
28896  // Create storage, if it doesn't already exist, for the map
28897  // that will contain the position of the first entry of
28898  // this face element's additional values,
28899  if (bnod_pt->index_of_first_value_assigned_by_face_element_pt() == 0)
28900  {
28901  bnod_pt->index_of_first_value_assigned_by_face_element_pt() =
28902  new std::map<unsigned, unsigned>;
28903  }
28904 
28905  // Get pointer to the map
28906  std::map<unsigned, unsigned>* map_pt =
28907  bnod_pt->index_of_first_value_assigned_by_face_element_pt();
28908 
28909  // The id of the face to which this node belong in the bulk
28910  // element
28911  const unsigned id_face = 0;
28912  // We only resize the node values Vector if we haven't done it yet
28913  std::map<unsigned, unsigned>::const_iterator p =
28914  map_pt->find(id_face);
28915 
28916  // If this node hasn't been resized for current id
28917  if (p == map_pt->end())
28918  {
28919  // assign the face element id and the position of the
28920  // first entry to the boundary node
28921  (*map_pt)[id_face] = n_new_val;
28922 
28923  // resize the node vector of values
28924  new_nod_pt->resize(n_val);
28925  }
28926 
28927  } // if (n_val>n_new_val)
28928 
28929  } // if (!found_node_in_other_shared_boundaries ||
28930  // !found_on_haloed_element_with_other_processor)
28931 
28932  // Is the new node a SolidNode?
28933  SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(new_nod_pt);
28934  if (solid_nod_pt != 0)
28935  {
28936  unsigned n_solid_val = solid_nod_pt->variable_position_pt()->nvalue();
28937  for (unsigned i_val = 0; i_val < n_solid_val; i_val++)
28938  {
28939  for (unsigned t = 0; t < n_prev; t++)
28940  {
28941  double read_data =
28942  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
28943 
28944  // Check if necessary to state all the info. to the node if
28945  // it has been already found in shared boundaries with other
28946  // processors or in the haloed elements with of other
28947  // processors with the iproc processor
28948  if (!found_node_in_other_shared_boundaries ||
28949  !found_on_haloed_element_with_other_processor)
28950  {
28951  solid_nod_pt->variable_position_pt()->set_value(
28952  t, i_val, read_data);
28953  } // if (!found_node_in_other_shared_boundaries ||
28954  // !found_on_haloed_element_with_other_processor)
28955  }
28956  }
28957 
28958 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28959  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28960  << " Number of values solid node: "
28961  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28962  << std::endl;
28963 #endif
28964  const unsigned nvalues_solid_node =
28965  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28966  Vector<double> values_solid_node(nvalues_solid_node);
28967  for (unsigned i = 0; i < nvalues_solid_node; i++)
28968  {
28969  values_solid_node[i] =
28970  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
28971  }
28972 
28973  // Check if necessary to state all the info. to the node if it
28974  // has been already found in shared boundaries with other
28975  // processors or in the haloed elements with of other processors
28976  // with the iproc processor
28977  if (!found_node_in_other_shared_boundaries ||
28978  !found_on_haloed_element_with_other_processor)
28979  {
28980  unsigned index = 0;
28981  solid_nod_pt->read_values_from_vector(values_solid_node, index);
28982  } // if (!found_node_in_other_shared_boundaries ||
28983  // !found_on_haloed_element_with_other_processor)
28984  }
28985 
28986  // Get copied history values
28987  // unsigned n_val=new_nod_pt->nvalue();
28988  for (unsigned i_val = 0; i_val < n_val; i_val++)
28989  {
28990  for (unsigned t = 0; t < n_prev; t++)
28991  {
28992  double read_data =
28993  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
28994 
28995  // Check if necessary to state all the info. to the node if it
28996  // has been already found in shared boundaries with other
28997  // processors or in the haloed elements with of other
28998  // processors with the iproc processor
28999  if (!found_node_in_other_shared_boundaries ||
29000  !found_on_haloed_element_with_other_processor)
29001  {
29002  new_nod_pt->set_value(t, i_val, read_data);
29003  } // if (!found_node_in_other_shared_boundaries ||
29004  // !found_on_haloed_element_with_other_processor)
29005  }
29006  }
29007 
29008  // Get copied history values for positions
29009  unsigned n_dim = new_nod_pt->ndim();
29010  for (unsigned idim = 0; idim < n_dim; idim++)
29011  {
29012  for (unsigned t = 0; t < n_prev; t++)
29013  {
29014  double read_data =
29015  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
29016 
29017  // Check if necessary to state all the info. to the node if it
29018  // has been already found in shared boundaries with other
29019  // processors or in the haloed elements with of other
29020  // processors with the iproc processor
29021  if (!found_node_in_other_shared_boundaries ||
29022  !found_on_haloed_element_with_other_processor)
29023  {
29024  // Copy to coordinate
29025  new_nod_pt->x(t, idim) = read_data;
29026  // DEBP(new_nod_pt->x(t,idim));
29027  } // if (!found_node_in_other_shared_boundaries ||
29028  // !found_on_haloed_element_with_other_processor)
29029  }
29030  }
29031 
29032  } // if (is_node_on_shared_boundary != 1)
29033 
29034  // If the node was not found in other shared boundaries (possibly
29035  // because it is the first time the node has been sent) then copy
29036  // the node to the shared boundaries where it should be, use the
29037  // special container for this cases
29038  if (n_shd_bnd_with_other_procs_have_node > 0 && // The node is on
29039  // shared
29040  // boundaries with
29041  // other processors
29042  !found_node_in_other_shared_boundaries) // The node has not
29043  // been previously
29044  // set as with
29045  // shared with
29046  // other processors
29047  // (first time)
29048  {
29049  // Update the node pointer in all the references of the node
29050  this->update_other_proc_shd_bnd_node_helper(new_nod_pt,
29051  other_proc_shd_bnd_node_pt,
29052  other_processor_1,
29053  other_processor_2,
29054  other_shared_boundaries,
29055  other_indexes,
29056  global_node_names,
29057  node_name_to_global_index,
29058  global_shared_node_pt);
29059 
29060  } // if (!found_node_in_other_shared_boundaries)
29061  }
29062 
29063 #endif // #ifdef OOMPH_HAS_MPI
29064 
29065  //======================================================================
29066  /// Get the nodes on the boundary (b), these are stored in the
29067  /// segment they belong (also used by the load balance method to
29068  /// re-set the number of segments per boundary after load balance has
29069  /// taken place)
29070  //======================================================================
29071  template<class ELEMENT>
29073  const unsigned& b, Vector<Vector<Node*>>& tmp_segment_nodes)
29074  {
29075  // Clear the data structure were to return the nodes
29076  tmp_segment_nodes.clear();
29077 
29078  // Temporary storage for face elements
29079  Vector<FiniteElement*> face_el_pt;
29080 
29081  // Temporary storage for number of elements adjacent to the boundary
29082  unsigned nel = 0;
29083 
29084  // Temporary storage for elements adjacent to the boundary that have
29085  // a common edge (related with internal boundaries)
29086  unsigned n_repeated_ele = 0;
29087 
29088  // Get the number of regions
29089  const unsigned n_regions = this->nregion();
29090 
29091  // Temporary storage for already visited pair of nodes (edges)
29092  Vector<std::pair<Node*, Node*>> done_nodes_pt;
29093 
29094  // Are there more than one region?
29095  if (n_regions > 1)
29096  {
29097  for (unsigned rr = 0; rr < n_regions; rr++)
29098  {
29099  const unsigned region_id =
29100  static_cast<unsigned>(this->Region_attribute[rr]);
29101 
29102  // Loop over all elements on boundaries in region rr
29103  const unsigned nel_in_region =
29104  this->nboundary_element_in_region(b, region_id);
29105 
29106  // Number of repeated element in region
29107  unsigned nel_repeated_in_region = 0;
29108 
29109  // Only bother to do anything else, if there are elements
29110  // associated with the boundary and the current region
29111  if (nel_in_region > 0)
29112  {
29113  // Flag that activates when a repeated face element is found,
29114  // possibly because we are dealing with an internal boundary
29115  bool repeated = false;
29116 
29117  // Loop over the bulk elements adjacent to boundary b
29118  for (unsigned e = 0; e < nel_in_region; e++)
29119  {
29120  // Get pointer to the bulk element that is adjacent to boundary b
29121  FiniteElement* bulk_elem_pt =
29122  this->boundary_element_in_region_pt(b, region_id, e);
29123 
29124 #ifdef OOMPH_HAS_MPI
29125  // In a distributed mesh only work with nonhalo elements
29126  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
29127  {
29128  // Increase the number of repeated elements
29129  n_repeated_ele++;
29130  // Go for the next element
29131  continue;
29132  }
29133 #endif
29134 
29135  // Find the index of the face of element e along boundary b
29136  int face_index =
29137  this->face_index_at_boundary_in_region(b, region_id, e);
29138 
29139  // Before adding the new element we need to be sure that the
29140  // edge that this element represents has not been already
29141  // added
29142  FiniteElement* tmp_ele_pt =
29143  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
29144 
29145  // Number of nodes in the face element
29146  const unsigned n_nodes = tmp_ele_pt->nnode();
29147 
29148  std::pair<Node*, Node*> tmp_pair = std::make_pair(
29149  tmp_ele_pt->node_pt(0), tmp_ele_pt->node_pt(n_nodes - 1));
29150 
29151  std::pair<Node*, Node*> tmp_pair_inverse = std::make_pair(
29152  tmp_ele_pt->node_pt(n_nodes - 1), tmp_ele_pt->node_pt(0));
29153 
29154  // Search for repeated nodes
29155  unsigned n_done_nodes = done_nodes_pt.size();
29156  for (unsigned l = 0; l < n_done_nodes; l++)
29157  {
29158  if (tmp_pair == done_nodes_pt[l] ||
29159  tmp_pair_inverse == done_nodes_pt[l])
29160  {
29161  nel_repeated_in_region++;
29162  repeated = true;
29163  break;
29164  }
29165 
29166  } // for (l < n_done_nodes)
29167 
29168  // Create new face element?
29169  if (!repeated)
29170  {
29171  // Add the pair of nodes (edge) to the node dones
29172  done_nodes_pt.push_back(tmp_pair);
29173  // Add the face element to the storage
29174  face_el_pt.push_back(tmp_ele_pt);
29175  }
29176  else
29177  {
29178  // Clean up
29179  delete tmp_ele_pt;
29180  tmp_ele_pt = 0;
29181  }
29182 
29183  // Re-start
29184  repeated = false;
29185 
29186  } // for (e < nel_in_region)
29187 
29188  // Add on the number of elements in the boundary with the
29189  // current region
29190  nel += nel_in_region;
29191 
29192  // Add on the number of repeated elements
29193  n_repeated_ele += nel_repeated_in_region;
29194 
29195  } // if (nel_in_region > 0)
29196 
29197  } // for (rr < n_regions)
29198 
29199  } // if (n_regions > 1)
29200  // Otherwise it's just the normal boundary functions
29201  else
29202  {
29203  // Assign the number of boundary elements
29204  nel = this->nboundary_element(b);
29205 
29206  // Only bother to do anything else, if there are elements
29207  if (nel > 0)
29208  {
29209  // Flag that activates when a repeated face element is found,
29210  // possibly because we are dealing with an internal boundary
29211  bool repeated = false;
29212 
29213  // Loop over the bulk elements adjacent to boundary b
29214  for (unsigned e = 0; e < nel; e++)
29215  {
29216  // Get pointer to the bulk element that is adjacent to boundary b
29217  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
29218 
29219 #ifdef OOMPH_HAS_MPI
29220  // In a distributed mesh only work with nonhalo elements
29221  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
29222  {
29223  // Increase the number of repeated elements
29224  n_repeated_ele++;
29225  // Go for the next element
29226  continue;
29227  }
29228 #endif
29229 
29230  // Find the index of the face of element e along boundary b
29231  int face_index = this->face_index_at_boundary(b, e);
29232 
29233  // Before adding the new element we need to be sure that the
29234  // edge that this element represent has not been already added
29235  FiniteElement* tmp_ele_pt =
29236  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
29237 
29238  // Number of nodes in the face element
29239  const unsigned n_nodes = tmp_ele_pt->nnode();
29240 
29241  std::pair<Node*, Node*> tmp_pair = std::make_pair(
29242  tmp_ele_pt->node_pt(0), tmp_ele_pt->node_pt(n_nodes - 1));
29243 
29244  std::pair<Node*, Node*> tmp_pair_inverse = std::make_pair(
29245  tmp_ele_pt->node_pt(n_nodes - 1), tmp_ele_pt->node_pt(0));
29246 
29247  // Search for repeated nodes
29248  unsigned n_done_nodes = done_nodes_pt.size();
29249  for (unsigned l = 0; l < n_done_nodes; l++)
29250  {
29251  if (tmp_pair == done_nodes_pt[l] ||
29252  tmp_pair_inverse == done_nodes_pt[l])
29253  {
29254  n_repeated_ele++;
29255  repeated = true;
29256  break;
29257  }
29258 
29259  } // for (l < n_done_nodes)
29260 
29261  // Create new face element
29262  if (!repeated)
29263  {
29264  // Add the pair of nodes (edge) to the node dones
29265  done_nodes_pt.push_back(tmp_pair);
29266  // Add the face element to the storage
29267  face_el_pt.push_back(tmp_ele_pt);
29268  }
29269  else
29270  {
29271  // Free the repeated bulk element!!
29272  delete tmp_ele_pt;
29273  tmp_ele_pt = 0;
29274  }
29275 
29276  // Re-start
29277  repeated = false;
29278 
29279  } // for (e < nel)
29280 
29281  } // if (nel > 0)
29282 
29283  } // else if (n_regions > 1)
29284 
29285  // Substract the repeated elements
29286  nel -= n_repeated_ele;
29287 
29288 #ifdef PARANOID
29289  if (nel != face_el_pt.size())
29290  {
29291  std::ostringstream error_message;
29292  error_message
29293  << "The independet counting of face elements (" << nel << ") for "
29294  << "boundary (" << b << ") is different\n"
29295  << "from the real number of face elements in the container ("
29296  << face_el_pt.size() << ")\n";
29297  throw OomphLibError(
29298  error_message.str(),
29299  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29300  OOMPH_EXCEPTION_LOCATION);
29301  }
29302 #endif
29303 
29304  // Only bother to do anything else, if there are elements
29305  if (nel > 0)
29306  {
29307  // Assign the number of nonhalo face elements
29308  const unsigned nnon_halo_face_elements = nel;
29309 
29310  // The vector of list to store the "segments" that compound the
29311  // boundary (segments may appear only in a distributed mesh)
29312  Vector<std::list<FiniteElement*>> segment_sorted_ele_pt;
29313 
29314  // Number of already sorted face elements (only nonhalo face
29315  // elements for a distributed mesh)
29316  unsigned nsorted_face_elements = 0;
29317 
29318  // Keep track of who's done (in a distributed mesh this apply to
29319  // nonhalo only)
29320  std::map<FiniteElement*, bool> done_ele;
29321 
29322  // Keep track of which element is inverted (in distributed mesh
29323  // the elements may be inverted with respect to the segment they
29324  // belong)
29325  std::map<FiniteElement*, bool> is_inverted;
29326 
29327  // Iterate until all possible segments have been created. In a non
29328  // distributed mesh there is only one segment which defines the
29329  // complete boundary
29330  while (nsorted_face_elements < nnon_halo_face_elements)
29331  {
29332  // The ordered list of face elements (in a distributed mesh a
29333  // collection of continuous face elements define a segment)
29334  std::list<FiniteElement*> sorted_el_pt;
29335 
29336 #ifdef PARANOID
29337  // Select an initial element for the segment
29338  bool found_initial_face_element = false;
29339 #endif
29340 
29341  FiniteElement* ele_face_pt = 0;
29342 
29343  unsigned iface = 0;
29344 #ifdef OOMPH_HAS_MPI
29345  if (this->is_mesh_distributed())
29346  {
29347  for (iface = 0; iface < nel; iface++)
29348  {
29349  ele_face_pt = face_el_pt[iface];
29350  // If not done then take it as initial face element
29351  if (!done_ele[ele_face_pt])
29352  {
29353 #ifdef PARANOID
29354  // Set the flag to indicate the initial element was
29355  // found
29356  found_initial_face_element = true;
29357 #endif
29358  // Increase the number of sorted face elements
29359  nsorted_face_elements++;
29360  // Set the index to the next face element
29361  iface++;
29362  // Add the face element in the container
29363  sorted_el_pt.push_back(ele_face_pt);
29364  // Mark as done
29365  done_ele[ele_face_pt] = true;
29366  break;
29367  } // if (!done_el[ele_face_pt])
29368  } // for (iface < nel)
29369  } // if (this->is_mesh_distributed())
29370  else
29371  {
29372 #endif // #ifdef OOMPH_HAS_MPI
29373 
29374  // When the mesh is not distributed just take the first
29375  // element and put it in the ordered list
29376  ele_face_pt = face_el_pt[0];
29377 #ifdef PARANOID
29378  // Set the flag to indicate the initial element was found
29379  found_initial_face_element = true;
29380 #endif
29381  // Increase the number of sorted face elements
29382  nsorted_face_elements++;
29383  // Set the index to the next face element
29384  iface = 1;
29385  // Add the face element in the container
29386  sorted_el_pt.push_back(ele_face_pt);
29387  // Mark as done
29388  done_ele[ele_face_pt] = true;
29389 #ifdef OOMPH_HAS_MPI
29390  } // else if (this->is_mesh_distributed())
29391 #endif
29392 
29393 #ifdef PARANOID
29394  if (!found_initial_face_element)
29395  {
29396  std::ostringstream error_message;
29397  error_message << "Could not find an initial face element for the "
29398  "current segment\n";
29399  throw OomphLibError(
29400  error_message.str(),
29401  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29402  OOMPH_EXCEPTION_LOCATION);
29403  }
29404 #endif
29405 
29406  // Number of nodes in the face element
29407  const unsigned nnod = ele_face_pt->nnode();
29408 
29409  // Left and rightmost nodes (the left and right nodes of the
29410  // current face element)
29411  Node* left_node_pt = ele_face_pt->node_pt(0);
29412  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
29413 
29414  // Continue iterating if a new face element has been added to
29415  // the list
29416  bool face_element_added = false;
29417 
29418  // While a new face element has been added to the set of sorted
29419  // face elements continue iterating
29420  do
29421  {
29422  // Start from the next face element since we have already
29423  // added the previous one as the initial face element (any
29424  // previous face element had to be added on previous
29425  // iterations)
29426  for (unsigned iiface = iface; iiface < nel; iiface++)
29427  {
29428  // Re-start flag
29429  face_element_added = false;
29430 
29431  // Get the candidate element
29432  ele_face_pt = face_el_pt[iiface];
29433 
29434  // Check that the candidate element has not been done and is
29435  // not a halo element
29436  if (!done_ele[ele_face_pt])
29437  {
29438  // Get the left and right nodes of the current element
29439  Node* local_left_node_pt = ele_face_pt->node_pt(0);
29440  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
29441 
29442  // New element fits at the left of segment and is not inverted
29443  if (left_node_pt == local_right_node_pt)
29444  {
29445  left_node_pt = local_left_node_pt;
29446  sorted_el_pt.push_front(ele_face_pt);
29447  is_inverted[ele_face_pt] = false;
29448  face_element_added = true;
29449  }
29450  // New element fits at the left of segment and is inverted
29451  else if (left_node_pt == local_left_node_pt)
29452  {
29453  left_node_pt = local_right_node_pt;
29454  sorted_el_pt.push_front(ele_face_pt);
29455  is_inverted[ele_face_pt] = true;
29456  face_element_added = true;
29457  }
29458  // New element fits on the right of segment and is not inverted
29459  else if (right_node_pt == local_left_node_pt)
29460  {
29461  right_node_pt = local_right_node_pt;
29462  sorted_el_pt.push_back(ele_face_pt);
29463  is_inverted[ele_face_pt] = false;
29464  face_element_added = true;
29465  }
29466  // New element fits on the right of segment and is inverted
29467  else if (right_node_pt == local_right_node_pt)
29468  {
29469  right_node_pt = local_left_node_pt;
29470  sorted_el_pt.push_back(ele_face_pt);
29471  is_inverted[ele_face_pt] = true;
29472  face_element_added = true;
29473  }
29474 
29475  if (face_element_added)
29476  {
29477  // Mark the face element as done
29478  done_ele[ele_face_pt] = true;
29479  nsorted_face_elements++;
29480  break;
29481  }
29482 
29483  } // if (!done_el[ele_face_pt])
29484 
29485  } // for (iiface<nnon_halo_face_element)
29486 
29487  } while (face_element_added &&
29488  (nsorted_face_elements < nnon_halo_face_elements));
29489 
29490  // Store the created segment in the vector of segments
29491  segment_sorted_ele_pt.push_back(sorted_el_pt);
29492 
29493  } // while(nsorted_face_elements < nnon_halo_face_elements);
29494 
29495  // The number of boundary segments in this processor
29496  const unsigned nsegments = segment_sorted_ele_pt.size();
29497 
29498 #ifdef PARANOID
29499  if (nnon_halo_face_elements > 0 && nsegments == 0)
29500  {
29501  std::ostringstream error_message;
29502  error_message
29503  << "The number of segments is zero, but the number of nonhalo\n"
29504  << "elements is: (" << nnon_halo_face_elements << ")\n";
29505  throw OomphLibError(
29506  error_message.str(),
29507  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29508  OOMPH_EXCEPTION_LOCATION);
29509  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
29510 #endif
29511 
29512  // Go through all the segments, visit each face element in order
29513  // and get the nodes based that represent the boundary segment
29514 
29515  // Resize the container to store the nodes with the required
29516  // number of segments
29517  tmp_segment_nodes.resize(nsegments);
29518 
29519  for (unsigned is = 0; is < nsegments; is++)
29520  {
29521 #ifdef PARANOID
29522  if (segment_sorted_ele_pt[is].size() == 0)
29523  {
29524  std::ostringstream error_message;
29525  error_message << "The (" << is << ")-th segment has no elements\n";
29526  throw OomphLibError(
29527  error_message.str(),
29528  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29529  OOMPH_EXCEPTION_LOCATION);
29530  } // if (segment_sorted_ele_pt[is].size() == 0)
29531 #endif
29532 
29533  // Get access to the first element on the segment
29534  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
29535 
29536  // Number of nodes
29537  const unsigned nnod = first_ele_pt->nnode();
29538 
29539  // Get the first node of the current segment
29540  Node* first_node_pt = first_ele_pt->node_pt(0);
29541  if (is_inverted[first_ele_pt])
29542  {
29543  first_node_pt = first_ele_pt->node_pt(nnod - 1);
29544  }
29545 
29546  // Add the node to the corresponding segment
29547  tmp_segment_nodes[is].push_back(first_node_pt);
29548 
29549  // Now loop over face elements in order to get the nodes
29550  for (std::list<FiniteElement*>::iterator it =
29551  segment_sorted_ele_pt[is].begin();
29552  it != segment_sorted_ele_pt[is].end();
29553  it++)
29554  {
29555  // Get element
29556  FiniteElement* ele_pt = *it;
29557 
29558  // The last node pointer
29559  Node* last_node_pt = 0;
29560 
29561  // Get the last node
29562  if (!is_inverted[ele_pt])
29563  {
29564  last_node_pt = ele_pt->node_pt(nnod - 1);
29565  }
29566  else
29567  {
29568  last_node_pt = ele_pt->node_pt(0);
29569  }
29570 
29571  // Add the node to the corresponding segment
29572  tmp_segment_nodes[is].push_back(last_node_pt);
29573 
29574  } // iterator over the elements in the segment
29575 
29576  } // for (is < nsegments)
29577 
29578  } // for (if (nel > 0))
29579 
29580  // Free memory allocation
29581  for (unsigned e = 0; e < nel; e++)
29582  {
29583  delete face_el_pt[e];
29584  face_el_pt[e] = 0;
29585  } // for (e < nel)
29586  }
29587 
29588  //======================================================================
29589  /// Adapt problem based on specified elemental error estimates
29590  /// This function implement serial and parallel mesh adaptation, the
29591  /// sections for parallel mesh adaptation are clearly identified by
29592  /// checking whether the mesh is distributed or not
29593  //======================================================================
29594  template<class ELEMENT>
29595  void RefineableTriangleMesh<ELEMENT>::adapt(const Vector<double>& elem_error)
29596  {
29597  double t_start_overall = TimingHelpers::timer();
29598 
29599  // ==============================================================
29600  // BEGIN: Compute target areas
29601  // ==============================================================
29602 
29603  // Get refinement targets
29604  Vector<double> target_area(elem_error.size());
29605  double min_angle = compute_area_target(elem_error, target_area);
29606 
29607  // Post-process to allow only quantised target areas
29608  // in an attempt to more closely mimick the structured
29609  // case and limit the diffusion of small elements.
29610  bool quantised_areas = true;
29611  if (quantised_areas)
29612  {
29613  unsigned n = target_area.size();
29614  double total_area = 0;
29615  // If the mesh is distributed then we need to get the contribution
29616  // of all processors to compute the total areas
29617  // ------------------------------------------
29618  // DISTRIBUTED MESH: BEGIN
29619  // ------------------------------------------
29620 #ifdef OOMPH_HAS_MPI
29621  if (this->is_mesh_distributed())
29622  {
29623  // When working in parallel we get the total area from the sum
29624  // of the the sub-areas of all the meshes
29625  double sub_area = 0.0;
29626 
29627  // Only add the area of nonhalo elements
29628  for (unsigned e = 0; e < n; e++)
29629  {
29630  // Get the pointer to the element
29631  FiniteElement* ele_pt = this->finite_element_pt(e);
29632  if (!ele_pt->is_halo())
29633  {
29634  sub_area += ele_pt->size();
29635  }
29636  } // for (e<n)
29637 
29638  // Get the communicator of the mesh
29639  OomphCommunicator* comm_pt = this->communicator_pt();
29640 
29641  // Get the total area
29642  MPI_Allreduce(
29643  &sub_area, &total_area, 1, MPI_DOUBLE, MPI_SUM, comm_pt->mpi_comm());
29644  }
29645  else
29646  {
29647  for (unsigned e = 0; e < n; e++)
29648  {
29649  total_area += this->finite_element_pt(e)->size();
29650  }
29651  }
29652  // ------------------------------------------
29653  // DISTRIBUTED MESH: END
29654  // ------------------------------------------
29655 #else // #ifdef OOMPH_HAS_MPI
29656  for (unsigned e = 0; e < n; e++)
29657  {
29658  total_area += this->finite_element_pt(e)->size();
29659  }
29660 #endif // #ifdef OOMPH_HAS_MPI
29661 
29662  for (unsigned e = 0; e < n; e++)
29663  {
29664  unsigned level =
29665  unsigned(ceil(log(target_area[e] / total_area) / log(1.0 / 3.0))) - 1;
29666  double new_target_area = total_area * pow(1.0 / 3.0, int(level));
29667  target_area[e] = new_target_area;
29668  }
29669  }
29670 
29671  // std::ofstream tmp;
29672  // tmp.open((Global_string_for_annotation::
29673  // String[0]+"overall_target_areas"+
29674  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
29675 
29676  // Get maximum target area
29677  unsigned n = target_area.size();
29678  double max_area = 0.0;
29679  double min_area = DBL_MAX;
29680  for (unsigned e = 0; e < n; e++)
29681  {
29682  if (target_area[e] > max_area) max_area = target_area[e];
29683  if (target_area[e] < min_area) min_area = target_area[e];
29684 
29685  // tmp << (finite_element_pt(e)->node_pt(0)->x(0)+
29686  // finite_element_pt(e)->node_pt(1)->x(0)+
29687  // finite_element_pt(e)->node_pt(2)->x(0))/3.0 << " "
29688  // << (finite_element_pt(e)->node_pt(0)->x(1)+
29689  // finite_element_pt(e)->node_pt(1)->x(1)+
29690  // finite_element_pt(e)->node_pt(2)->x(1))/3.0 << " "
29691  // << target_area[e] << " "
29692  // << finite_element_pt(e)->size() << " "
29693  // << elem_error[e] << " " << std::endl;
29694  }
29695 
29696  // tmp.close();
29697 
29698  oomph_info << "Maximum target area: " << max_area << std::endl;
29699  oomph_info << "Minimum target area: " << min_area << std::endl;
29700  oomph_info << "Number of elements to be refined: " << this->Nrefined
29701  << std::endl;
29702  oomph_info << "Number of elements to be unrefined: " << this->Nunrefined
29703  << std::endl;
29704  oomph_info << "Min. angle: " << min_angle << std::endl;
29705 
29706  double orig_max_area, orig_min_area;
29707  this->max_and_min_element_size(orig_max_area, orig_min_area);
29708  oomph_info << "Max./min. element size in original mesh: " << orig_max_area
29709  << " " << orig_min_area << std::endl;
29710 
29711  // ==============================================================
29712  // END: Compute target areas
29713  // ==============================================================
29714 
29715  // Check if boundaries need to be updated (regardless of
29716  // requirements of bulk error estimator) but don't do anything!
29717  bool check_only = true;
29718  bool outer_boundary_update_necessary = false;
29719  bool inner_boundary_update_necessary = false;
29720  bool inner_open_boundary_update_necessary = false;
29721 
29722  // Get the number of outer boundaries and check if they require
29723  // update
29724  const unsigned nouter = this->Outer_boundary_pt.size();
29725 
29726  if (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29727  {
29728  // loop over the outer boundaries
29729  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29730  {
29731  outer_boundary_update_necessary = this->update_polygon_using_face_mesh(
29732  this->Outer_boundary_pt[i_outer], check_only);
29733  // Break the loop if at least one needs updating
29734  if (outer_boundary_update_necessary) break;
29735  }
29736 
29737  // Do not waste time if we already know that it is necessary an update
29738  // on the boundary representation
29739  if (!outer_boundary_update_necessary)
29740  {
29741  // Check if we need to generate a new 1D mesh representation of
29742  // the inner hole boundaries
29743  const unsigned nhole = this->Internal_polygon_pt.size();
29744  Vector<Vector<double>> internal_point_coord(nhole);
29745  inner_boundary_update_necessary =
29746  this->surface_remesh_for_inner_hole_boundaries(internal_point_coord,
29747  check_only);
29748 
29749  // If there was not necessary a change even on the internal closed
29750  // curve then finally check for the open curves as well
29751  if (!inner_boundary_update_necessary)
29752  {
29753  const unsigned n_open_polyline = this->Internal_open_curve_pt.size();
29754  // loop over the open polylines
29755  for (unsigned i = 0; i < n_open_polyline; i++)
29756  {
29757  inner_open_boundary_update_necessary =
29758  this->update_open_curve_using_face_mesh(
29759  this->Internal_open_curve_pt[i], check_only);
29760  // If at least one needs modification then break the for loop
29761  if (inner_open_boundary_update_necessary) break;
29762  }
29763  }
29764  }
29765  }
29766 
29767  // Flag to indicate whether we need to adapt or not (for parallel
29768  // mesh adaptation only)
29769  int adapt_all = 0;
29770  // ------------------------------------------
29771  // DISTRIBUTED MESH: BEGIN
29772  // ------------------------------------------
29773 #ifdef OOMPH_HAS_MPI
29774  // When working in distributed meshes we need to ensure that all the
29775  // processors take part on the adaptation process. If at least one
29776  // of the processors requires adaptation then all processor take
29777  // part on the adaptation process.
29778  int adapt_this_processor = 0;
29779  if (this->is_mesh_distributed())
29780  {
29781  // Do this processor requires adaptation?
29782  if ((Nrefined > 0) || (Nunrefined > max_keep_unrefined()) ||
29783  (min_angle < min_permitted_angle()) ||
29784  (outer_boundary_update_necessary) ||
29785  (inner_boundary_update_necessary) ||
29786  (inner_open_boundary_update_necessary))
29787  {
29788  adapt_this_processor = 1;
29789  }
29790 
29791  // Get the communicator of the mesh
29792  OomphCommunicator* comm_pt = this->communicator_pt();
29793 
29794  // Verify if at least one processor needs mesh adaptation
29795  MPI_Allreduce(&adapt_this_processor,
29796  &adapt_all,
29797  1,
29798  MPI_INT,
29799  MPI_SUM,
29800  comm_pt->mpi_comm());
29801  }
29802 #endif
29803  // ------------------------------------------
29804  // DISTRIBUTED MESH: END
29805  // ------------------------------------------
29806 
29807  // Should we bother to adapt?
29808  if ((Nrefined > 0) || (Nunrefined > max_keep_unrefined()) ||
29809  (min_angle < min_permitted_angle()) ||
29810  (outer_boundary_update_necessary) ||
29811  (inner_boundary_update_necessary) ||
29812  (inner_open_boundary_update_necessary) || (adapt_all))
29813  {
29814  if (!((Nrefined > 0) || (Nunrefined > max_keep_unrefined())))
29815  {
29816  if ((outer_boundary_update_necessary) ||
29817  (inner_boundary_update_necessary) ||
29818  (inner_open_boundary_update_necessary))
29819  {
29820  oomph_info
29821  << "Mesh regeneration triggered by inaccurate interface/surface\n"
29822  << "representation; setting Nrefined to number of elements.\n"
29823  << "outer_boundary_update_necessary : "
29824  << outer_boundary_update_necessary << "\n"
29825  << "inner_boundary_update_necessary : "
29826  << inner_boundary_update_necessary << "\n"
29827  << "inner_open_boundary_update_necessary: "
29828  << inner_open_boundary_update_necessary << "\n";
29829  Nrefined = nelement();
29830  }
29831  else
29832  {
29833  oomph_info << "Mesh regeneration triggered by min angle criterion;\n"
29834  << "setting Nrefined to number of elements.\n";
29835  Nrefined = nelement();
29836  }
29837  }
29838 
29839  // ------------------------------------------
29840  // DISTRIBUTED MESH: BEGIN
29841  // ------------------------------------------
29842 #ifdef OOMPH_HAS_MPI
29843  else if (this->is_mesh_distributed() && adapt_this_processor == 0 &&
29844  adapt_all > 0)
29845  {
29846  oomph_info << "Mesh regeneration triggered by (" << adapt_all
29847  << ") processor(s) "
29848  << "that require(s)\n adaptation\n";
29849  }
29850 #endif
29851  // ------------------------------------------
29852  // DISTRIBUTED MESH: END
29853  // ------------------------------------------
29854 
29855  // ==============================================================
29856  // BEGIN: Updating of boundaries representation (unrefinement and
29857  // refinement of polylines)
29858  // ==============================================================
29859 
29860  // Add the initial and final vertices of the polylines that
29861  // present connections to a list of non-delete-able vertices. The
29862  // vertices where the connections are performed cannot be deleted
29863  add_vertices_for_non_deletion();
29864 
29865  // ------------------------------------------
29866  // DISTRIBUTED MESH: BEGIN
29867  // ------------------------------------------
29868 #ifdef OOMPH_HAS_MPI
29869  // Synchronise connections for shared boundaries among
29870  // processors. This is required since one of the processor may noy
29871  // know that some of its shared boundaries have connections, thus
29872  // the vertices receiving the connections cannot be deleted
29873  if (this->is_mesh_distributed())
29874  {
29875  synchronize_shared_boundary_connections();
29876  }
29877 #endif // #ifdef OOMPH_HAS_MPI
29878  // ------------------------------------------
29879  // DISTRIBUTED MESH: END
29880  // ------------------------------------------
29881 
29882  // Are we allowing automatic insertion of vertices on boundaries?
29883  // If YES then Triangle automatically insert points along
29884  // boundaries, if NOT, then points are inserted along the
29885  // boundaries based on the target areas of boundary elements. When
29886  // the mesh is distributed the automatic insertion of vertices by
29887  // Triangle along the boundaries is not allowed
29888  if (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29889  {
29890  // Generate a new 1D mesh representation of the inner hole boundaries
29891  unsigned nhole = this->Internal_polygon_pt.size();
29892  Vector<Vector<double>> internal_point_coord(nhole);
29893  this->surface_remesh_for_inner_hole_boundaries(internal_point_coord);
29894 
29895  // Update the representation of the outer boundary
29896  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29897  {
29898  this->update_polygon_using_face_mesh(
29899  this->Outer_boundary_pt[i_outer]);
29900  }
29901 
29902  // After updating outer and internal closed boundaries it is also
29903  // necessary to update internal boundaries.
29904  unsigned n_open_polyline = this->Internal_open_curve_pt.size();
29905  for (unsigned i = 0; i < n_open_polyline; i++)
29906  {
29907  this->update_open_curve_using_face_mesh(
29908  this->Internal_open_curve_pt[i]);
29909  }
29910  }
29911  else
29912  {
29913  // Update the representation of the internal boundaries using
29914  // the element's target area
29915 
29916  // Get the number of interal polygons
29917  const unsigned ninternal = this->Internal_polygon_pt.size();
29918  for (unsigned i_internal = 0; i_internal < ninternal; i_internal++)
29919  {
29920  this->update_polygon_using_elements_area(
29921  this->Internal_polygon_pt[i_internal], target_area);
29922  }
29923 
29924  // Update the representation of the outer boundaries using the
29925  // element's target area
29926  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29927  {
29928  this->update_polygon_using_elements_area(
29929  this->Outer_boundary_pt[i_outer], target_area);
29930  }
29931 
29932  // Update the representation of the internal open boundaries
29933  // using the element's target areas
29934  const unsigned n_open_polyline = this->Internal_open_curve_pt.size();
29935  for (unsigned i = 0; i < n_open_polyline; i++)
29936  {
29937  this->update_open_curve_using_elements_area(
29938  this->Internal_open_curve_pt[i], target_area);
29939  }
29940 
29941  // ------------------------------------------
29942  // DISTRIBUTED MESH: BEGIN
29943  // ------------------------------------------
29944 
29945  // When working with a distributed mesh we require to update the
29946  // boundary representation of the shared boundaries, this is
29947  // based on the target areas of the elements adjaced to the
29948  // shared boundaries
29949 #ifdef OOMPH_HAS_MPI
29950  // Update shared boundaries if the mesh is distributed
29951  if (this->is_mesh_distributed())
29952  {
29953  // Get the rank of the current processor
29954  const unsigned my_rank = this->communicator_pt()->my_rank();
29955 
29956  // Get the number of shared curves
29957  const unsigned n_curves = this->nshared_boundary_curves(my_rank);
29958  // Loop over the shared curves in the current processor
29959  for (unsigned nc = 0; nc < n_curves; nc++)
29960  {
29961  // Update the shared polyline
29962  this->update_shared_curve_using_elements_area(
29963  this->Shared_boundary_polyline_pt[my_rank][nc], // shared_curve,
29964  target_area);
29965  }
29966 
29967  } // if (this->is_mesh_distributed())
29968 #endif
29969 
29970  // ------------------------------------------
29971  // DISTRIBUTED MESH: END
29972  // ------------------------------------------
29973 
29974  } // else if
29975  // (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29976 
29977  // ==============================================================
29978  // END: Updating of boundaries representation (unrefinement and
29979  // refinement of polylines)
29980  // ==============================================================
29981 
29982  // ==============================================================
29983  // BEGIN: Reset boundary coordinates for boundaries with no
29984  // associated GeomObject
29985  // ==============================================================
29986 
29987  // If there is not a geometric object associated with the boundary
29988  // then reset the boundary coordinates so that the lengths are
29989  // consistent in the new mesh and the old mesh.
29990  const unsigned n_boundary = this->nboundary();
29991 
29992  const double t_start_first_stage_segments_connectivity =
29993  TimingHelpers::timer();
29994 
29995  // ------------------------------------------
29996  // DISTRIBUTED MESH: BEGIN
29997  // ------------------------------------------
29998 #ifdef OOMPH_HAS_MPI
29999  // Clear storage for assignment of initial zeta values for
30000  // boundaries
30001  if (this->is_mesh_distributed())
30002  {
30003  this->Assigned_segments_initial_zeta_values.clear();
30004  }
30005 #endif // #ifdef OOMPH_HAS_MPI
30006  // ------------------------------------------
30007  // DISTRIBUTED MESH: END
30008  // ------------------------------------------
30009 
30010  // Loop over the boundaries to assign boundary coordinates
30011  for (unsigned b = 0; b < n_boundary; ++b)
30012  {
30013  // ------------------------------------------
30014  // DISTRIBUTED MESH: BEGIN
30015  // ------------------------------------------
30016 #ifdef OOMPH_HAS_MPI
30017  if (this->is_mesh_distributed())
30018  {
30019  // In a distributed mesh, the boundaries may have been split
30020  // across processors during the distribution process, thus we
30021  // need to compute the connectivity among the segments of the
30022  // boundary to correctly assign its boundary coordinates
30023  this->compute_boundary_segments_connectivity_and_initial_zeta_values(
30024  b);
30025  }
30026 #endif
30027  // ------------------------------------------
30028  // DISTRIBUTED MESH: END
30029  // ------------------------------------------
30030 
30031  // Does the boundary has an associated GeomObject
30032  if (this->boundary_geom_object_pt(b) == 0)
30033  {
30034  this->template setup_boundary_coordinates<ELEMENT>(b);
30035  }
30036 
30037  // ------------------------------------------
30038  // DISTRIBUTED MESH: BEGIN
30039  // ------------------------------------------
30040 #ifdef OOMPH_HAS_MPI
30041  if (this->is_mesh_distributed())
30042  {
30043  // Synchronise boundary coordinates for internal open curves,
30044  // also establish the boundary coordinates for the nodes on
30045  // the corners of elements not on the boundary
30046  this->synchronize_boundary_coordinates(b);
30047  }
30048 #endif
30049  // ------------------------------------------
30050  // DISTRIBUTED MESH: END
30051  // ------------------------------------------
30052 
30053  } // for (b<n_boundary)
30054 
30055  const double t_total_first_stage_segments_connectivity =
30056  TimingHelpers::timer() - t_start_first_stage_segments_connectivity;
30057 
30058  // ==============================================================
30059  // END: Reset boundary coordinates for boundaries with no
30060  // associated GeomObject
30061  // ==============================================================
30062 
30063  // ------------------------------------------
30064  // DISTRIBUTED MESH: BEGIN
30065  // ------------------------------------------
30066 #ifdef OOMPH_HAS_MPI
30067  // ==============================================================
30068  // BEGIN: Create the new representation of the domain by joining
30069  // the original boundaries and the shared boundaries.
30070  // ==============================================================
30071 
30072  // Storage for the new temporary polygons "closed" by the shared
30073  // boundaries
30074  Vector<TriangleMeshPolygon*> tmp_outer_polygons_pt;
30075 
30076  // Storage for the new temporary open curves, could be the
30077  // original open curves or "chunks" of the original open curves
30078  // not overlapped by shared boundaries
30079  Vector<TriangleMeshOpenCurve*> tmp_open_curves_pt;
30080 
30081  if (this->is_mesh_distributed())
30082  {
30083  // Create the new polygons and open curves with help of the
30084  // original polylines and shared polylines
30085  this->create_distributed_domain_representation(tmp_outer_polygons_pt,
30086  tmp_open_curves_pt);
30087 
30088  // Create the connections of the temporary domain representations
30089  this->create_temporary_boundary_connections(tmp_outer_polygons_pt,
30090  tmp_open_curves_pt);
30091  }
30092  // ==============================================================
30093  // END: Create the new representation of the domain by joining
30094  // the original boundaries and the shared boundaries.
30095  // ==============================================================
30096 #endif
30097  // ------------------------------------------
30098  // DISTRIBUTED MESH: END
30099  // ------------------------------------------
30100 
30101  // Re-establish polylines' connections. The boundary
30102  // representation has changed (new polylines), therefore we need
30103  // to update the connection information
30104  Vector<TriangleMeshPolyLine*> resume_initial_connection_polyline_pt;
30105  Vector<TriangleMeshPolyLine*> resume_final_connection_polyline_pt;
30106  restore_boundary_connections(resume_initial_connection_polyline_pt,
30107  resume_final_connection_polyline_pt);
30108 
30109  // Update the region information by setting the coordinates from the
30110  // centroid of the first element in each region (which should allow
30111  // automatic updates when the regions deform)
30112  {
30113  unsigned n_region = this->nregion();
30114  if (n_region > 1)
30115  {
30116  for (std::map<unsigned, Vector<double>>::iterator it =
30117  this->Regions_coordinates.begin();
30118  it != this->Regions_coordinates.end();
30119  ++it)
30120  {
30121  // Storage for the approximate centroid
30122  Vector<double> centroid(2, 0.0);
30123 
30124  // Get the region id
30125  unsigned region_id = it->first;
30126 
30127  // Report information
30128  oomph_info << "Region " << region_id << ": " << it->second[0] << " "
30129  << it->second[1] << " ";
30130 
30131  // Check that there is at least one element in the region
30132  unsigned n_region_element = this->nregion_element(region_id);
30133  if (n_region_element > 0)
30134  {
30135  // Cache pointer to the first element
30136  FiniteElement* const elem_pt =
30137  this->region_element_pt(region_id, 0);
30138 
30139  // Loop over the corners of the triangle and average
30140  for (unsigned n = 0; n < 3; n++)
30141  {
30142  Node* const nod_pt = elem_pt->node_pt(n);
30143  for (unsigned i = 0; i < 2; i++)
30144  {
30145  centroid[i] += nod_pt->x(i);
30146  }
30147  }
30148  for (unsigned i = 0; i < 2; i++)
30149  {
30150  centroid[i] /= 3;
30151  }
30152  // Now we have the centroid set it
30153  it->second = centroid;
30154 
30155  oomph_info << " , " << it->second[0] << " " << it->second[1]
30156  << std::endl;
30157  } // end of case when there is at least one element
30158 
30159  } // loop over regions coordinates
30160 
30161  } // if(n_region > 1)
30162 
30163  } // Updating region info.
30164 
30165  // ==============================================================
30166  // BEGIN: Create background mesh
30167  // ==============================================================
30168 
30169  // Are we dealing with a solid mesh?
30170  SolidMesh* solid_mesh_pt = dynamic_cast<SolidMesh*>(this);
30171 
30172  // Build temporary uniform background mesh
30173  //----------------------------------------
30174  // with area set by maximum required area
30175  //---------------------------------------
30176  RefineableTriangleMesh<ELEMENT>* tmp_new_mesh_pt = 0;
30177 
30178  // The storage for the new temporary boundaries representation to
30179  // create the background mesh
30180  Vector<TriangleMeshClosedCurve*> closed_curve_pt;
30181  Vector<TriangleMeshClosedCurve*> hole_pt;
30182  Vector<TriangleMeshOpenCurve*> open_curves_pt;
30183 
30184 #ifdef OOMPH_HAS_MPI
30185  if (!this->is_mesh_distributed())
30186 #endif
30187  {
30188  // Copy the outer boundaries
30189  closed_curve_pt.resize(nouter);
30190  for (unsigned i = 0; i < nouter; i++)
30191  {
30192  closed_curve_pt[i] = this->Outer_boundary_pt[i];
30193  }
30194 
30195  // Copy the internal closed boundaries (may be holes)
30196  const unsigned n_holes = this->Internal_polygon_pt.size();
30197  hole_pt.resize(n_holes);
30198  for (unsigned i = 0; i < n_holes; i++)
30199  {
30200  hole_pt[i] = this->Internal_polygon_pt[i];
30201  }
30202 
30203  // Copy the internal open curves
30204  const unsigned n_open_curves = this->Internal_open_curve_pt.size();
30205  open_curves_pt.resize(n_open_curves);
30206  for (unsigned i = 0; i < n_open_curves; i++)
30207  {
30208  open_curves_pt[i] = this->Internal_open_curve_pt[i];
30209  }
30210  }
30211  // ------------------------------------------
30212  // DISTRIBUTED MESH: BEGIN
30213  // ------------------------------------------
30214 #ifdef OOMPH_HAS_MPI
30215  else
30216  {
30217  // Copy the new representation of the outer/internal closed
30218  // boundaries
30219  const unsigned n_tmp_outer = tmp_outer_polygons_pt.size();
30220  closed_curve_pt.resize(n_tmp_outer);
30221  for (unsigned i = 0; i < n_tmp_outer; i++)
30222  {
30223  closed_curve_pt[i] = tmp_outer_polygons_pt[i];
30224  }
30225 
30226  // Copy the new representation of the internal open curves
30227  const unsigned n_open_curves = tmp_open_curves_pt.size();
30228  open_curves_pt.resize(n_open_curves);
30229  for (unsigned i = 0; i < n_open_curves; i++)
30230  {
30231  open_curves_pt[i] = tmp_open_curves_pt[i];
30232  }
30233  }
30234 #endif
30235  // ------------------------------------------
30236  // DISTRIBUTED MESH: END
30237  // ------------------------------------------
30238 
30239  // ----------------------------------------------------------------
30240  // Gather all the information and use the TriangleMeshParameters
30241  // object which help us on the manage of all TriangleMesh object's
30242  // information
30243 
30244  // Create the TriangleMeshParameters objects with the outer boundary
30245  // as the only one parameter
30246  TriangleMeshParameters triangle_mesh_parameters(closed_curve_pt);
30247 
30248  // Pass information about the holes
30249  triangle_mesh_parameters.internal_closed_curve_pt() = hole_pt;
30250 
30251  // Pass information about the internal open boundaries
30252  triangle_mesh_parameters.internal_open_curves_pt() = open_curves_pt;
30253 
30254  // Set the element area
30255  triangle_mesh_parameters.element_area() = max_area;
30256 
30257  // Pass information about the extra holes (not defined with closed
30258  // boundaries)
30259  triangle_mesh_parameters.extra_holes_coordinates() =
30260  this->Extra_holes_coordinates;
30261 
30262  // Pass information about regions
30263  triangle_mesh_parameters.regions_coordinates() =
30264  this->Regions_coordinates;
30265 
30266  // Pass information about the using of regions
30267  if (this->Use_attributes)
30268  {
30269  triangle_mesh_parameters.enable_use_attributes();
30270  }
30271 
30272  // Pass information about allowing the creation of new points
30273  if (!this->is_automatic_creation_of_vertices_on_boundaries_allowed())
30274  {
30275  triangle_mesh_parameters
30277  }
30278 
30279  // When the mesh is distributed we need to create a distributed
30280  // background mesh
30281 #ifdef OOMPH_HAS_MPI
30282  if (this->is_mesh_distributed())
30283  {
30284  // Mark the mesh to be created as distributed by passing a
30285  // pointer to the communicator
30286  triangle_mesh_parameters.set_communicator_pt(this->communicator_pt());
30287  }
30288 #endif
30289 
30290  // ----------------------------------------------------------
30291  // Build the background mesh using Triangle
30292  // ----------------------------------------------------------
30293  const double t_start_building_background_mesh = TimingHelpers::timer();
30294 
30295  if (solid_mesh_pt != 0)
30296  {
30297  tmp_new_mesh_pt = new RefineableSolidTriangleMesh<ELEMENT>(
30298  triangle_mesh_parameters, this->Time_stepper_pt);
30299  }
30300  else
30301  {
30302  tmp_new_mesh_pt = new RefineableTriangleMesh<ELEMENT>(
30303  triangle_mesh_parameters, this->Time_stepper_pt);
30304  }
30305 
30306  if (Print_timings_level_adaptation > 2)
30307  {
30308  oomph_info << "CPU for building background mesh: "
30309  << TimingHelpers::timer() - t_start_building_background_mesh
30310  << std::endl;
30311  }
30312 
30313  // Pass the info. regarding the maximum and minimum element size
30314  // from the old mesh to the background mesh
30315  const double this_max_element_size = this->max_element_size();
30316  const double this_min_element_size = this->min_element_size();
30317  tmp_new_mesh_pt->max_element_size() = this_max_element_size;
30318  tmp_new_mesh_pt->min_element_size() = this_min_element_size;
30319 
30320  // ... also copy the minimum permitted angle
30321  const double this_min_permitted_angle = this->min_permitted_angle();
30322  tmp_new_mesh_pt->min_permitted_angle() = this_min_permitted_angle;
30323 
30324  // ------------------------------------------
30325  // DISTRIBUTED MESH: BEGIN
30326  // ------------------------------------------
30327 #ifdef OOMPH_HAS_MPI
30328  // If the mesh is distributed we need to pass and set the
30329  // information of internal boundaries overlaped by shared
30330  // boundaries
30331  if (this->is_mesh_distributed())
30332  {
30333  // Check if necessary to fill boundary elements for those
30334  // internal boundaries that overlap shared boundaries
30335  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
30336  {
30337  // Copy the data structures that indicates which shared
30338  // boundaries are part of an internal boundary
30339  tmp_new_mesh_pt->shared_boundary_overlaps_internal_boundary() =
30340  this->shared_boundary_overlaps_internal_boundary();
30341 
30342  // Copy the data structure that indicates which are the shared
30343  // boundaries in each processor
30344  tmp_new_mesh_pt->shared_boundaries_ids() =
30345  this->shared_boundaries_ids();
30346 
30347  // Fill the structures for the boundary elements and face indexes
30348  // of the boundary elements
30349  tmp_new_mesh_pt
30351 
30352  } // if (this->nshared_boundary_overlaps_internal_boundary() > 0)
30353 
30354  } // if (this->is_mesh_distributed())
30355 #endif // #ifdef OOMPH_HAS_MPI
30356  // ------------------------------------------
30357  // DISTRIBUTED MESH: END
30358  // ------------------------------------------
30359 
30360  // Snap to curvilinear boundaries (some code duplication as this
30361  // is repeated below but helper function would take so many
30362  // arguments that it's nearly as messy...
30363 
30364  // Pass the boundary geometric objects to the new mesh
30365  tmp_new_mesh_pt->boundary_geom_object_pt() =
30366  this->boundary_geom_object_pt();
30367 
30368  // Reset the boundary coordinates if there is
30369  // a geometric object associated with the boundary
30370  tmp_new_mesh_pt->boundary_coordinate_limits() =
30371  this->boundary_coordinate_limits();
30372 
30373  const double t_start_second_stage_segments_connectivity =
30374  TimingHelpers::timer();
30375 
30376  for (unsigned b = 0; b < n_boundary; b++)
30377  {
30378  // ------------------------------------------
30379  // DISTRIBUTED MESH: BEGIN
30380  // ------------------------------------------
30381 #ifdef OOMPH_HAS_MPI
30382  if (this->is_mesh_distributed())
30383  {
30384  // Identify the segments of the new mesh with the ones of the
30385  // original mesh
30386  tmp_new_mesh_pt
30388  this);
30389  }
30390 #endif
30391  // ------------------------------------------
30392  // DISTRIBUTED MESH: END
30393  // ------------------------------------------
30394 
30395  // Setup boundary coordinates for boundaries with GeomObject
30396  // associated
30397  if (tmp_new_mesh_pt->boundary_geom_object_pt(b) != 0)
30398  {
30399  tmp_new_mesh_pt->template setup_boundary_coordinates<ELEMENT>(b);
30400  }
30401  }
30402 
30403  const double t_total_second_stage_segments_connectivity =
30404  TimingHelpers::timer() - t_start_second_stage_segments_connectivity;
30405 
30406  const double t_start_snap_nodes_bg_mesh = TimingHelpers::timer();
30407  // Move the nodes on the new boundary onto the old curvilinear
30408  // boundary. If the boundary is straight this will do precisely
30409  // nothing but will be somewhat inefficient
30410  for (unsigned b = 0; b < n_boundary; b++)
30411  {
30412  this->snap_nodes_onto_boundary(tmp_new_mesh_pt, b);
30413  }
30414 
30415  const double t_total_snap_nodes_bg_mesh =
30416  TimingHelpers::timer() - t_start_snap_nodes_bg_mesh;
30417 
30418  if (Print_timings_level_adaptation > 2)
30419  {
30420  oomph_info << "CPU for snapping nodes onto boundaries "
30421  << "(background mesh): " << t_total_snap_nodes_bg_mesh
30422  << std::endl;
30423  }
30424 
30425  // Update mesh further?
30426  if (Mesh_update_fct_pt != 0)
30427  {
30428  Mesh_update_fct_pt(tmp_new_mesh_pt);
30429  }
30430 
30431  // If we have a continuation problem
30432  // any problem in which the timestepper is a "generalisedtimestepper",
30433  // which will have been set by the problem, then ensure
30434  // all data in the new mesh has the appropriate timestepper
30435  /*if(dynamic_cast<GeneralisedTimeStepper*>(this->Time_stepper_pt))
30436  {
30437  tmp_new_mesh_pt->set_nodal_and_elemental_time_stepper(
30438  this->Time_stepper_pt);
30439  tmp_new_mesh_pt->set_mesh_level_time_stepper(this->Time_stepper_pt);
30440  }*/
30441 
30442 
30443  // tmp_new_mesh_pt->output("mesh_nodes_snapped_0.dat");
30444  // this->output("existing_mesh.dat");
30445 
30446  // ==============================================================
30447  // END: Create background mesh
30448  // ==============================================================
30449 
30450  // ==============================================================
30451  // BEGIN: Transferring of target areas and creation of new mesh
30452  // ==============================================================
30453 
30454  // Get the TriangulateIO object associated with that mesh
30455  TriangulateIO tmp_new_triangulateio =
30456  tmp_new_mesh_pt->triangulateio_representation();
30457  RefineableTriangleMesh<ELEMENT>* new_mesh_pt = 0;
30458 
30459  // If the mesh is a solid mesh then do the mapping based on the
30460  // Eulerian coordinates
30461  bool use_eulerian_coords = false;
30462  if (solid_mesh_pt != 0)
30463  {
30464  use_eulerian_coords = true;
30465  }
30466 
30467 
30468 #ifdef OOMPH_HAS_CGAL
30469 
30470  // Make cgal-based bin
30471  CGALSamplePointContainerParameters cgal_params(this);
30472  if (use_eulerian_coords)
30473  {
30474  cgal_params.enable_use_eulerian_coordinates_during_setup();
30475  }
30476  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(&cgal_params);
30477 
30478 #else
30479 
30480  // Make nonrefineable bin
30481  NonRefineableBinArrayParameters params(this);
30482  if (use_eulerian_coords)
30483  {
30484  params.enable_use_eulerian_coordinates_during_setup();
30485  }
30486  Vector<unsigned> bin_dim(2);
30487  bin_dim[0] = Nbin_x_for_area_transfer;
30488  bin_dim[1] = Nbin_y_for_area_transfer;
30489  params.dimensions_of_bin_array() = bin_dim;
30490  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(&params);
30491 
30492 #endif
30493 
30494  // Set up a map from pointer to element to its number
30495  // in the mesh
30496  std::map<GeneralisedElement*, unsigned> element_number;
30497  unsigned nelem = this->nelement();
30498  for (unsigned e = 0; e < nelem; e++)
30499  {
30500  element_number[this->element_pt(e)] = e;
30501  }
30502 
30503 #ifndef OOMPH_HAS_CGAL
30504 
30505  // Create a vector to store the min target area of each bin (at
30506  // this stage the number of bins should not be that large, so it
30507  // should be safe to build a vector for the total number of bins)
30508  Vector<double> bin_min_target_area;
30509 
30510  // Get pointer to sample point container
30511  NonRefineableBinArray* bin_array_pt =
30512  dynamic_cast<NonRefineableBinArray*>(
30513  mesh_geom_obj_pt->sample_point_container_pt());
30514  if (bin_array_pt == 0)
30515  {
30516  throw OomphLibError(
30517  "Sample point container has to be NonRefineableBinArray",
30518  OOMPH_CURRENT_FUNCTION,
30519  OOMPH_EXCEPTION_LOCATION);
30520  }
30521 
30522  {
30523  unsigned n_bin = 0;
30524  unsigned max_n_entry = 0;
30525  unsigned min_n_entry = UINT_MAX;
30526  unsigned tot_n_entry = 0;
30527  unsigned n_empty = 0;
30528  bin_array_pt->get_fill_stats(
30529  n_bin, max_n_entry, min_n_entry, tot_n_entry, n_empty);
30530 
30531  oomph_info << "Before bin diffusion:"
30532  << " nbin:(" << n_bin << ")"
30533  << " nempty:(" << n_empty << ")"
30534  << " min:(" << min_n_entry << ")"
30535  << " max:(" << max_n_entry << ")"
30536  << " average entries:("
30537  << double(tot_n_entry) / double(n_bin) << ")" << std::endl;
30538  }
30539 
30540  // Fill bin by diffusion
30541  double t0_bin_diff = TimingHelpers::timer();
30542  oomph_info << "Going into diffusion bit...\n";
30543  bin_array_pt->fill_bin_by_diffusion();
30544  oomph_info << "Back from diffusion bit...\n";
30545  oomph_info << "Time for bin diffusion: "
30546  << TimingHelpers::timer() - t0_bin_diff << std::endl;
30547 
30548  // Do some stats
30549  {
30550  unsigned n_bin = 0;
30551  unsigned max_n_entry = 0;
30552  unsigned min_n_entry = UINT_MAX;
30553  unsigned tot_n_entry = 0;
30554  unsigned n_empty = 0;
30555  bin_array_pt->get_fill_stats(
30556  n_bin, max_n_entry, min_n_entry, tot_n_entry, n_empty);
30557 
30558  oomph_info << "After bin diffusion:"
30559  << " nbin:(" << n_bin << ")"
30560  << " nempty:(" << n_empty << ")"
30561  << " min:(" << min_n_entry << ")"
30562  << " max:(" << max_n_entry << ")"
30563  << " average entries:("
30564  << double(tot_n_entry) / double(n_bin) << ")" << std::endl;
30565  }
30566 
30567 
30568  // For each bin, compute the minimum of the target areas in the bin
30569 
30570  // Timing for map
30571  double t_total_map = 0.0;
30572 
30573  // Counter for map
30574  unsigned counter_map = 0;
30575 
30576  // Get access to the bins (we need access to the content of the
30577  // bins to compute the minimum of the target areas of the elements
30578  // in each bin)
30579  const std::map<unsigned,
30580  Vector<std::pair<FiniteElement*, Vector<double>>>>*
30581  bins_pt = bin_array_pt->get_all_bins_content();
30582 
30583  // Get the number of bins
30584  const unsigned n_bin = bins_pt->size();
30585 
30586  // Create a vector to store the min target area of each bin (at
30587  // this stage the number of bins should not be that large, so it
30588  // should be safe to build a vector for the total number of bins)
30589  bin_min_target_area.resize(n_bin);
30590  for (unsigned u = 0; u < n_bin; u++)
30591  {
30592  bin_min_target_area[u] = 0.0;
30593  }
30594  // loop over the bins, get their elements and compute the minimum
30595  // target area of all of them
30596  typedef std::map<
30597  unsigned,
30598  Vector<std::pair<FiniteElement*, Vector<double>>>>::const_iterator IT;
30599  for (IT it = bins_pt->begin(); it != bins_pt->end(); it++)
30600  {
30601  // The bin number
30602  unsigned ib = (*it).first;
30603 
30604  // Get the number of elements in the bin
30605  const unsigned n_ele_bin = (*it).second.size();
30606 
30607  // loop over the elements in the bin
30608  for (unsigned ee = 0; ee < n_ele_bin; ee++)
30609  {
30610  // Get ee-th element (in currrent mesh) in ib-th bin
30611  GeneralisedElement* ele_pt = (*it).second[ee].first;
30612  double t_map = TimingHelpers::timer();
30613  const unsigned ele_number = element_number[ele_pt];
30614  t_total_map += TimingHelpers::timer() - t_map;
30615 
30616  // Increase the number of calls to map
30617  counter_map++;
30618 
30619  // Go for smallest target area of any element in this bin to
30620  // force "one level" of refinement (the one-level-ness is
30621  // enforced below by limiting the actual reduction in area
30622  if (bin_min_target_area[ib] != 0)
30623  {
30624  bin_min_target_area[ib] =
30625  std::min(bin_min_target_area[ib], target_area[ele_number]);
30626  }
30627  else
30628  {
30629  bin_min_target_area[ib] = target_area[ele_number];
30630  }
30631 
30632  } // for (ee<n_ele_bin)
30633 
30634  } // for (it!=bins.end())
30635 
30636  oomph_info << "CPU for map[counter=" << counter_map
30637  << "]: " << t_total_map << std::endl;
30638 
30639 
30640  // Optional output for debugging (keep it around!)
30641  const bool output_bins = false;
30642  if (output_bins)
30643  {
30644  unsigned length = bin_min_target_area.size();
30645  for (unsigned u = 0; u < length; u++)
30646  {
30647  oomph_info << "Bin n" << u
30648  << ",target area: " << bin_min_target_area[u] << std::endl;
30649  }
30650  }
30651 
30652 #endif
30653 
30654 
30655  // Now start iterating to refine mesh recursively
30656  //-----------------------------------------------
30657  bool done = false;
30658  unsigned iter = 0;
30659 #ifdef OOMPH_HAS_MPI
30660  // The number of elements that require (un)refinement
30661  unsigned n_ele_need_refinement = 0;
30662 #endif
30663 
30664  // The timing for the third stage of segments connectivity
30665  double t_total_third_stage_segments_connectivity = 0.0;
30666 
30667  // The timing for the transfering target areas
30668  double t_total_transfer_target_areas = 0.0;
30669 
30670  // The timing for the copying of target areas
30671  double t_total_limit_target_areas = 0.0;
30672 
30673  // The timing to create the new mesh
30674  double t_total_create_new_adapted_mesh = 0.0;
30675 
30676  // The timing for the snapping of the nodes on the new meshes
30677  double t_total_snap_nodes = 0.0;
30678 
30679  // The timing to check whether other processors need to adapt
30680  double t_total_wait_other_processors = 0.0;
30681  double t_iter = TimingHelpers::timer();
30682  while (!done)
30683  {
30684  // Accept by default but overwrite if things go wrong below
30685  done = true;
30686 
30687  double t_start_transfer_target_areas = TimingHelpers::timer();
30688  double t0_loop_int_pts = TimingHelpers::timer();
30689 
30690  // Loop over elements in new (tmp) mesh and visit all
30691  // its integration points. Check where it's located in the bin
30692  // structure of the current mesh and pass the target area
30693  // to the new element
30694  nelem = tmp_new_mesh_pt->nelement();
30695 
30696  // Store the target areas for elements in the temporary
30697  // TriangulateIO mesh
30698  Vector<double> new_transferred_target_area(nelem, 0.0);
30699  for (unsigned e = 0; e < nelem; e++)
30700  { // start loop el
30701  ELEMENT* el_pt =
30702  dynamic_cast<ELEMENT*>(tmp_new_mesh_pt->element_pt(e));
30703  unsigned nint = el_pt->integral_pt()->nweight();
30704  for (unsigned ipt = 0; ipt < nint; ipt++)
30705  {
30706  // Get the coordinate of current point
30707  Vector<double> s(2);
30708  for (unsigned i = 0; i < 2; i++)
30709  {
30710  s[i] = el_pt->integral_pt()->knot(ipt, i);
30711  }
30712 
30713  Vector<double> x(2);
30714  el_pt->interpolated_x(s, x);
30715 
30716 #if OOMPH_HAS_CGAL
30717 
30718  // Try the five nearest sample points for Newton search
30719  // then just settle on the nearest one
30720  GeomObject* geom_obj_pt = 0;
30721  unsigned max_sample_points =
30722  Max_sample_points_for_limited_locate_zeta_during_target_area_transfer;
30723  dynamic_cast<CGALSamplePointContainer*>(
30724  mesh_geom_obj_pt->sample_point_container_pt())
30725  ->limited_locate_zeta(x, max_sample_points, geom_obj_pt, s);
30726 #ifdef PARANOID
30727  if (geom_obj_pt == 0)
30728  {
30729  std::stringstream error_message;
30730  error_message << "Limited locate zeta failed for zeta = [ "
30731  << x[0] << " " << x[1] << " ]. Makes no sense!\n";
30732  throw OomphLibError(error_message.str(),
30733  OOMPH_CURRENT_FUNCTION,
30734  OOMPH_EXCEPTION_LOCATION);
30735  }
30736  else
30737  {
30738 #endif
30739  FiniteElement* fe_pt = dynamic_cast<FiniteElement*>(geom_obj_pt);
30740 #ifdef PARANOID
30741  if (fe_pt == 0)
30742  {
30743  std::stringstream error_message;
30744  error_message << "Cast to FE for GeomObject returned by "
30745  "limited locate zeta failed for zeta = [ "
30746  << x[0] << " " << x[1] << " ]. Makes no sense!\n";
30747  throw OomphLibError(error_message.str(),
30748  OOMPH_CURRENT_FUNCTION,
30749  OOMPH_EXCEPTION_LOCATION);
30750  }
30751  else
30752  {
30753 #endif
30754  // What's the target area of the element that contains this
30755  // point
30756  double tg_area = target_area[element_number[fe_pt]];
30757 
30758  // Go for smallest target area over all integration
30759  // points in new element
30760  // to force "one level" of refinement (the one-level-ness
30761  // is enforced below by limiting the actual reduction in
30762  // area
30763  if (new_transferred_target_area[e] != 0)
30764  {
30765  new_transferred_target_area[e] =
30766  std::min(new_transferred_target_area[e], tg_area);
30767  }
30768  else
30769  {
30770  new_transferred_target_area[e] = tg_area;
30771  }
30772 #ifdef PARANOID
30773  }
30774  }
30775 #endif
30776 
30777 #else
30778 
30779  // Find the bin that contains that point and its contents
30780  int bin_number = 0;
30781  bin_array_pt->get_bin(x, bin_number);
30782 
30783  // Did we find it?
30784  if (bin_number < 0)
30785  {
30786  // Not even within bin boundaries... odd
30787  std::stringstream error_message;
30788  error_message << "Very odd -- we're looking for a point[ " << x[0]
30789  << " " << x[1] << " ] that's not even \n"
30790  << "located within the bin boundaries.\n";
30791  throw OomphLibError(error_message.str(),
30792  "RefineableTriangleMesh::adapt()",
30793  OOMPH_EXCEPTION_LOCATION);
30794  } // if (bin_number<0)
30795  else
30796  {
30797  // Go for smallest target area of any element in this bin
30798  // to force "one level" of refinement (the one-level-ness
30799  // is enforced below by limiting the actual reduction in
30800  // area
30801  if (new_transferred_target_area[e] != 0)
30802  {
30803  new_transferred_target_area[e] =
30804  std::min(new_transferred_target_area[e],
30805  bin_min_target_area[bin_number]);
30806  }
30807  else
30808  {
30809  new_transferred_target_area[e] =
30810  bin_min_target_area[bin_number];
30811  }
30812  }
30813 
30814 #endif
30815 
30816  } // for (ipt<nint)
30817 
30818  } // for (e<nelem)
30819 
30820 
30821  // do some output (keep it alive!)
30822  const bool output_target_areas = false;
30823  if (output_target_areas)
30824  {
30825  unsigned length = new_transferred_target_area.size();
30826  for (unsigned u = 0; u < length; u++)
30827  {
30828  oomph_info << "Element" << u
30829  << ",target area: " << new_transferred_target_area[u]
30830  << std::endl;
30831  }
30832  }
30833  oomph_info << "Time for loop over integration points in new mesh: "
30834  << TimingHelpers::timer() - t0_loop_int_pts << std::endl;
30835 
30836 
30837  // {
30838  // tmp.open((Global_string_for_annotation::
30839  // String[0]+"binned_target_areas"+
30840  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
30841 
30842  // Vector<Vector<std::pair<FiniteElement*,Vector<double> > > >
30843  // bin_content=
30844  // mesh_geom_obj_pt->bin_content();
30845  // unsigned nbin=bin_content.size();
30846  // for (unsigned b=0;b<nbin;b++)
30847  // {
30848  // unsigned nentry=bin_content[b].size();
30849  // for (unsigned entry=0;entry<nentry;entry++)
30850  // {
30851  // FiniteElement* el_pt=bin_content[b][entry].first;
30852  // GeneralisedElement* gen_el_pt=bin_content[b][entry].first;
30853  // Vector<double> s=bin_content[b][entry].second;
30854  // Vector<double> x(2);
30855  // el_pt->interpolated_x(s,x);
30856  // unsigned e_current=element_number[gen_el_pt];
30857  // tmp << x[0] << " " << x[1] << " "
30858  // << target_area[e_current] << " "
30859  // << el_pt->size() << " "
30860  // << std::endl;
30861  // }
30862  // }
30863  // tmp.close();
30864  // }
30865 
30866  const double t_sub_total_transfer_target_areas =
30867  TimingHelpers::timer() - t_start_transfer_target_areas;
30868 
30869  if (Print_timings_level_adaptation > 2)
30870  {
30871  // Get the number of elements in the old mesh (this)
30872  const unsigned n_element = this->nelement();
30873  // Get the number of elements in the background mesh
30874  const unsigned n_element_background = tmp_new_mesh_pt->nelement();
30875 
30876  oomph_info << "CPU for transfer of target areas "
30877  << "[n_ele_old_mesh=" << n_element
30878  << ", n_ele_background_mesh=" << n_element_background
30879  << "] (iter " << iter
30880  << "): " << t_sub_total_transfer_target_areas << std::endl;
30881  }
30882 
30883  // Add the timing for tranfer of target areas
30884  t_total_transfer_target_areas += t_sub_total_transfer_target_areas;
30885 
30886  // // Output mesh
30887  // tmp_new_mesh_pt->output(("intermediate_mesh"+
30888  // StringConversion::to_string(iter)+".dat").c_str());
30889 
30890  // tmp.open((Global_string_for_annotation::
30891  // String[0]+"target_areas_intermediate_mesh_iter"+
30892  // StringConversion::to_string(iter)+"_"+
30893  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
30894 
30895  const double t_start_limit_target_areas = TimingHelpers::timer();
30896 
30897  // Now copy into target area for temporary mesh but limit to
30898  // the equivalent of one sub-division per iteration
30899 #ifdef OOMPH_HAS_MPI
30900  unsigned n_ele_need_refinement_iter = 0;
30901 #endif
30902 
30903 
30904  // Don't delete! Keep these around for debugging
30905  // ofstream tmp_mesh_file;
30906  // tmp_mesh_file.open("tmp_mesh_file.dat");
30907  // tmp_new_mesh_pt->output(tmp_mesh_file);
30908  // tmp_mesh_file.close();
30909  // ofstream target_areas_file;
30910  // target_areas_file.open("target_areas_file.dat");
30911 
30912  const unsigned nel_new = tmp_new_mesh_pt->nelement();
30913  Vector<double> new_target_area(nel_new);
30914  for (unsigned e = 0; e < nel_new; e++)
30915  {
30916  // The finite element
30917  FiniteElement* f_ele_pt = tmp_new_mesh_pt->finite_element_pt(e);
30918 
30919  // Transferred target area
30920  const double new_area = new_transferred_target_area[e];
30921  if (new_area <= 0.0)
30922  {
30923  std::ostringstream error_stream;
30924  error_stream
30925  << "This shouldn't happen! Element whose centroid is at "
30926  << (f_ele_pt->node_pt(0)->x(0) + f_ele_pt->node_pt(1)->x(0) +
30927  f_ele_pt->node_pt(2)->x(0)) /
30928  3.0
30929  << " "
30930  << (f_ele_pt->node_pt(0)->x(1) + f_ele_pt->node_pt(1)->x(1) +
30931  f_ele_pt->node_pt(2)->x(1)) /
30932  3.0
30933  << " "
30934  << " has no target area assigned\n";
30935  throw OomphLibError(error_stream.str(),
30936  OOMPH_CURRENT_FUNCTION,
30937  OOMPH_EXCEPTION_LOCATION);
30938  }
30939  else
30940  {
30941  // Limit target area to the equivalent of uniform refinement
30942  // during this stage of the iteration
30943  new_target_area[e] = new_area;
30944  if (new_target_area[e] < f_ele_pt->size() / 3.0)
30945  {
30946  new_target_area[e] = f_ele_pt->size() / 3.0;
30947 
30948  // We'll need to give it another go later
30949  done = false;
30950  }
30951 
30952  // Don't delete! Keep around for debugging
30953  // target_areas_file
30954  // << (f_ele_pt->node_pt(0)->x(0)+
30955  // f_ele_pt->node_pt(1)->x(0)+
30956  // f_ele_pt->node_pt(2)->x(0))/3.0 << " "
30957  // << (f_ele_pt->node_pt(0)->x(1)+
30958  // f_ele_pt->node_pt(1)->x(1)+
30959  // f_ele_pt->node_pt(2)->x(1))/3.0 << " "
30960  // << new_area << " "
30961  // << new_target_area[e] << std::endl;
30962 
30963 
30964 #ifdef OOMPH_HAS_MPI
30965  // Keep track of the elements that require (un)refinement
30966  n_ele_need_refinement_iter++;
30967 #endif
30968 
30969  } // else if (new_area <= 0.0)
30970 
30971  } // for (e < nel_new)
30972 
30973 
30974  // Don't delete! Keep around for debugging
30975  // target_areas_file.close();
30976 
30977  const double t_sub_total_limit_target_areas =
30978  TimingHelpers::timer() - t_start_limit_target_areas;
30979 
30980  // Add the timing for copying target areas
30981  t_total_limit_target_areas += t_sub_total_limit_target_areas;
30982 
30983  if (Print_timings_level_adaptation > 2)
30984  {
30985  // Get the number of elements in the old mesh (this)
30986  const unsigned n_element = this->nelement();
30987  // Get the number of elements in the background mesh
30988  const unsigned n_element_background = tmp_new_mesh_pt->nelement();
30989 
30990  oomph_info << "CPU for limiting target areas "
30991  << "[n_ele_old_mesh=" << n_element
30992  << ", n_ele_background_mesh=" << n_element_background
30993  << "] (iter " << iter
30994  << "): " << t_sub_total_limit_target_areas << std::endl;
30995  }
30996 
30997  if (done)
30998  {
30999  oomph_info
31000  << "All area adjustments accommodated by max. permitted area"
31001  << " reduction \n";
31002  }
31003  else
31004  {
31005  oomph_info << "NOT all area adjustments accommodated by max. "
31006  << "permitted area reduction \n";
31007  }
31008 
31009  // tmp.close();
31010  // pause("doced binned_target_areas.dat and intermediate mesh targets");
31011 
31012  // Now create the new mesh from TriangulateIO structure
31013  //-----------------------------------------------------
31014  // associated with uniform background mesh and the
31015  //------------------------------------------------
31016  // associated target element sizes.
31017  //---------------------------------
31018 
31019  const double t_start_create_new_adapted_mesh = TimingHelpers::timer();
31020 
31021  // Solid mesh?
31022  if (solid_mesh_pt != 0)
31023  {
31024  new_mesh_pt = new RefineableSolidTriangleMesh<ELEMENT>(
31025  new_target_area,
31026  tmp_new_triangulateio,
31027  this->Time_stepper_pt,
31028  this->Use_attributes,
31029  this->Allow_automatic_creation_of_vertices_on_boundaries,
31030  this->communicator_pt());
31031  }
31032  // No solid mesh
31033  else
31034  {
31035  new_mesh_pt = new RefineableTriangleMesh<ELEMENT>(
31036  new_target_area,
31037  tmp_new_triangulateio,
31038  this->Time_stepper_pt,
31039  this->Use_attributes,
31040  this->Allow_automatic_creation_of_vertices_on_boundaries,
31041  this->communicator_pt());
31042  }
31043 
31044  // Sub-total to create new adapted mesh
31045  const double t_sub_total_create_new_adapted_mesh =
31046  TimingHelpers::timer() - t_start_create_new_adapted_mesh;
31047 
31048  // Add the time to the total snap nodes time
31049  t_total_create_new_adapted_mesh += t_sub_total_create_new_adapted_mesh;
31050 
31051  if (Print_timings_level_adaptation > 2)
31052  {
31053  // Get the number of elements of the new adapted mesh
31054  const unsigned n_element_new_adapted_mesh = new_mesh_pt->nelement();
31055 
31056  oomph_info << "CPU for creation of new adapted mesh "
31057  << t_sub_total_create_new_adapted_mesh
31058  << "[nele=" << n_element_new_adapted_mesh << "] (iter "
31059  << iter << "): " << t_sub_total_create_new_adapted_mesh
31060  << std::endl;
31061  }
31062 
31063 #ifdef OOMPH_HAS_MPI
31064  // ------------------------------------------
31065  // DISTRIBUTED MESH: BEGIN
31066  // ------------------------------------------
31067 
31068  // This section is only required if we are dealing with
31069  // distributed meshes, otherwise there are not shared boundaries
31070  // overlapping internal boundaries
31071 
31072  // Check if necessary to fill boundary elements for those internal
31073  // boundaries that overlap shared boundaries
31074  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
31075  {
31076  // Copy the data structures that indicate which shared
31077  // boundaries are part of an internal boundary
31079  this->shared_boundary_overlaps_internal_boundary();
31080 
31081  // Copy the data structure that indicates which are the shared
31082  // boundaries in each processor
31083  new_mesh_pt->shared_boundaries_ids() = this->shared_boundaries_ids();
31084 
31085  // Fill the structures for the boundary elements and face indexes
31086  // of the boundary elements
31087  new_mesh_pt
31089  }
31090  // ------------------------------------------
31091  // DISTRIBUTED MESH: END
31092  // ------------------------------------------
31093 #endif // #ifdef OOMPH_HAS_MPI
31094 
31095  // Snap to curvilinear boundaries (some code duplication as this
31096  // is repeated below but helper function would take so many
31097  // arguments that it's nearly as messy...
31098 
31099  // Pass the boundary geometric objects to the new mesh
31100  new_mesh_pt->boundary_geom_object_pt() =
31101  this->boundary_geom_object_pt();
31102 
31103  // Reset the boundary coordinates if there is
31104  // a geometric object associated with the boundary
31105  new_mesh_pt->boundary_coordinate_limits() =
31106  this->boundary_coordinate_limits();
31107 
31108  const double t_start_third_stage_segments_connectivity =
31109  TimingHelpers::timer();
31110 
31111  for (unsigned b = 0; b < n_boundary; b++)
31112  {
31113  // ------------------------------------------
31114  // DISTRIBUTED MESH: BEGIN
31115  // ------------------------------------------
31116 
31117  // Before setting up boundary coordinates for the new mesh we
31118  // require to identify the segments with the old mesh to
31119  // assign initial zeta values
31120 #ifdef OOMPH_HAS_MPI
31121  if (this->is_mesh_distributed())
31122  {
31123  // Identify the segments of the new mesh with the ones of
31124  // the original mesh
31125  new_mesh_pt
31127  this);
31128  }
31129 #endif
31130  // ------------------------------------------
31131  // DISTRIBUTED MESH: END
31132  // ------------------------------------------
31133 
31134  // Setup boundary coordinates for boundaries with GeomObject
31135  // associated
31136  if (new_mesh_pt->boundary_geom_object_pt(b) != 0)
31137  {
31138  new_mesh_pt->template setup_boundary_coordinates<ELEMENT>(b);
31139  }
31140  }
31141 
31142  t_total_third_stage_segments_connectivity +=
31143  TimingHelpers::timer() - t_start_third_stage_segments_connectivity;
31144 
31145  const double t_start_snap_nodes_new_mesh = TimingHelpers::timer();
31146  // Move the nodes on the new boundary onto the old curvilinear
31147  // boundary. If the boundary is straight this will do precisely
31148  // nothing but will be somewhat inefficient
31149  for (unsigned b = 0; b < n_boundary; b++)
31150  {
31151  this->snap_nodes_onto_boundary(new_mesh_pt, b);
31152  }
31153 
31154  const double t_sub_total_snap_nodes_new_mesh =
31155  TimingHelpers::timer() - t_start_snap_nodes_new_mesh;
31156 
31157  // Add the time to the total snap nodes time
31158  t_total_snap_nodes += t_sub_total_snap_nodes_new_mesh;
31159 
31160  if (Print_timings_level_adaptation > 2)
31161  {
31162  oomph_info << "CPU for snapping nodes onto boundaries (new mesh) "
31163  << "(iter " << iter
31164  << "): " << t_sub_total_snap_nodes_new_mesh << std::endl;
31165  }
31166 
31167  // Update mesh further?
31168  if (Mesh_update_fct_pt != 0)
31169  {
31170  Mesh_update_fct_pt(new_mesh_pt);
31171  }
31172 
31173  // If we have a continuation problem
31174  // any problem in which the timestepper is a "generalisedtimestepper",
31175  // which will have been set by the problem, then ensure
31176  // all data in the new mesh has the appropriate timestepper
31177  if (dynamic_cast<GeneralisedTimeStepper*>(this->Time_stepper_pt))
31178  {
31179  new_mesh_pt->set_nodal_and_elemental_time_stepper(
31180  this->Time_stepper_pt, false);
31181  new_mesh_pt->set_mesh_level_time_stepper(this->Time_stepper_pt,
31182  false);
31183  }
31184 
31185  // Not done: get ready for another iteration
31186  iter++;
31187  delete tmp_new_mesh_pt;
31188 
31189 #ifdef OOMPH_HAS_MPI
31190  // Check whether the number of elements that need (un)refinement
31191  // from the previous iteration is the same, if that is the case
31192  // then we mark this processor as done
31193  if (n_ele_need_refinement_iter == n_ele_need_refinement)
31194  {
31195  done = true;
31196  }
31197  // Update the number of elements that require further
31198  // (un)refinement
31199  n_ele_need_refinement = n_ele_need_refinement_iter;
31200 #endif // #ifdef OOMPH_HAS_MPI
31201 
31202  // ------------------------------------------
31203  // DISTRIBUTED MESH: BEGIN
31204  // ------------------------------------------
31205 
31206  // We can only finish the iteration adaptation process if ALL
31207  // the involved processor are marked as done, otherwise, ALL
31208  // processor need to go for another iteration
31209 #ifdef OOMPH_HAS_MPI
31210  if (this->is_mesh_distributed())
31211  {
31212  // Time to check whether other processors have finish to adapt
31213  const double t_start_wait_other_processors = TimingHelpers::timer();
31214 
31215  // In case that the mesh is distributed it is necessary to
31216  // verify that no processor requires further refinement. If at
31217  // least one processor needs more refinement then all
31218  // processors need to go for another iteration to participate
31219  // in the communications
31220  unsigned this_processor_requires_another_iteration = 1;
31221 
31222  // Is this processor done?
31223  if (done)
31224  {
31225  this_processor_requires_another_iteration = 0;
31226  }
31227  int nproc_not_done = this_processor_requires_another_iteration;
31228  // Get the communicator of the mesh
31229  OomphCommunicator* comm_pt = this->communicator_pt();
31230  // Communicate with all procesoors to check whether we need to
31231  // re-iterate
31232  MPI_Allreduce(&this_processor_requires_another_iteration,
31233  &nproc_not_done,
31234  1,
31235  MPI_UNSIGNED,
31236  MPI_SUM,
31237  comm_pt->mpi_comm());
31238  // Are all processors done?
31239  if (nproc_not_done > 0)
31240  {
31241  oomph_info
31242  << "At least one processors requires further refinement. "
31243  << "Go for another iteration." << std::endl;
31244  done = false;
31245  }
31246 
31247  // Total to check whether other processors have finish to
31248  // adapt
31249  const double t_sub_total_wait_other_processors =
31250  TimingHelpers::timer() - t_start_wait_other_processors;
31251 
31252  // Add to the total timings to check whether other processors
31253  // need to adapt
31254  t_total_wait_other_processors += t_sub_total_wait_other_processors;
31255 
31256  if (Print_timings_level_adaptation > 2)
31257  {
31258  oomph_info << "CPU for waiting other processors "
31259  << "(iter " << iter
31260  << "): " << t_sub_total_wait_other_processors
31261  << std::endl;
31262  }
31263 
31264  } // if (this->is_mesh_distributed())
31265 #endif
31266  // ------------------------------------------
31267  // DISTRIBUTED MESH: END
31268  // ------------------------------------------
31269 
31270  if (!done)
31271  {
31272  oomph_info << "Going for another iteration. Current iteration ("
31273  << iter << ")" << std::endl;
31274 
31275  // Use the new mesh as the tmp mesh
31276  tmp_new_mesh_pt = new_mesh_pt;
31277  tmp_new_triangulateio = new_mesh_pt->triangulateio_representation();
31278  }
31279 
31280  } // end of iteration (while (!done))
31281 
31282  // Delete the temporary geometric object representation of the
31283  // current mesh
31284  delete mesh_geom_obj_pt;
31285 
31286  oomph_info << "CPU for iterative generation of new mesh (TOTAL): "
31287  << TimingHelpers::timer() - t_iter << std::endl;
31288 
31289  if (Print_timings_level_adaptation > 1)
31290  {
31291  oomph_info << "-- CPU for creating new adapted meshes (TOTAL): "
31292  << t_total_create_new_adapted_mesh << std::endl;
31293 
31294  oomph_info << "-- CPU for limiting target areas (TOTAL): "
31295  << t_total_limit_target_areas << std::endl;
31296 
31297  oomph_info << "-- CPU for transferring target areas (TOTAL): "
31298  << t_total_transfer_target_areas << std::endl;
31299 
31300  oomph_info << "-- CPU for waiting other processors (TOTAL): "
31301  << t_total_wait_other_processors << std::endl;
31302  }
31303 
31304  // ==============================================================
31305  // END: Transferring of target areas and creation of new mesh
31306  // ==============================================================
31307 
31308  // ==============================================================
31309  // BEGIN: Project solution from the old to the new mesh
31310  // ==============================================================
31311 
31312  // Check that the projection step is not disabled
31313  if (!Disable_projection)
31314  {
31315  // Take the time for the projection step
31316  double tt_start_projection = TimingHelpers::timer();
31317 
31318  // Print info. for tranfering target areas
31319  if (Print_timings_projection)
31320  {
31321  // Switch timings and stats on
31322  Multi_domain_functions::Doc_timings = true;
31323  Multi_domain_functions::Doc_stats = true;
31324  Multi_domain_functions::Doc_full_stats = true;
31325  }
31326 
31327  double t_proj = TimingHelpers::timer();
31328  oomph_info << "About to begin projection.\n";
31329 
31330  // Project current solution onto new mesh
31331  //---------------------------------------
31332  ProjectionProblem<ELEMENT>* project_problem_pt =
31333  new ProjectionProblem<ELEMENT>;
31334 
31335  // Projection requires to be enabled as distributed if working
31336  // with a distributed mesh
31337 #ifdef OOMPH_HAS_MPI
31338  if (this->is_mesh_distributed())
31339  {
31340  // ------------------------------------------
31341  // DISTRIBUTED MESH: BEGIN
31342  // ------------------------------------------
31343 
31344  // We need to back up the time stepper object since the
31345  // projection class creates a new one
31346  Time* backed_up_time_pt = this->Time_stepper_pt->time_pt();
31347 
31348  // Set the projection problem as distributed
31349  project_problem_pt->enable_problem_distributed();
31350 
31351  // Pass the time stepper to the projection problem (used when
31352  // setting multi_domain_interation)
31353  project_problem_pt->add_time_stepper_pt(this->Time_stepper_pt);
31354 
31355  // Set the mesh used for the projection object
31356  project_problem_pt->mesh_pt() = new_mesh_pt;
31357  // project_problem_pt->disable_suppress_output_during_projection();
31358 
31359  // Use iterative solver for projection? By default, an iterative
31360  // solver is used for the projection stage
31361  if (!this->use_iterative_solver_for_projection())
31362  {
31363  project_problem_pt->disable_use_iterative_solver_for_projection();
31364  }
31365 
31366  // Do the projection
31367  project_problem_pt->project(this);
31368 
31369  // Reset the time stepper object (only affects distributed meshes)
31370  this->Time_stepper_pt->time_pt() = backed_up_time_pt;
31371 
31372  // ------------------------------------------
31373  // DISTRIBUTED MESH: END
31374  // ------------------------------------------
31375 
31376  } // if (this->is_mesh_distributed())
31377  else
31378 #endif // #ifdef OOMPH_HAS_MPI
31379  {
31380  // Set the mesh used for the projection object
31381  project_problem_pt->mesh_pt() = new_mesh_pt;
31382 
31383  // project_problem_pt->disable_suppress_output_during_projection();
31384 
31385  // Use iterative solver for projection? By default, an iterative
31386  // solver is used for the projection stage
31387  if (!this->use_iterative_solver_for_projection())
31388  {
31389  project_problem_pt->disable_use_iterative_solver_for_projection();
31390  }
31391 
31392  // Do the projection
31393  project_problem_pt->project(this);
31394  }
31395 
31396  // Reset printing info. for projection
31397  if (Print_timings_projection)
31398  {
31399  // Switch timings and stats off
31400  Multi_domain_functions::Doc_timings = false;
31401  Multi_domain_functions::Doc_stats = false;
31402  Multi_domain_functions::Doc_full_stats = false;
31403  }
31404 
31405  // Get the total time for projection
31406  const double tt_projection =
31407  TimingHelpers::timer() - tt_start_projection;
31408 
31409  if (Print_timings_level_adaptation > 1)
31410  {
31411  // Get the number of elements in the old mesh (this)
31412  const unsigned n_element = this->nelement();
31413  // Get the number of elements in the new mesh
31414  const unsigned n_element_new = new_mesh_pt->nelement();
31415  oomph_info << "CPU for projection (in mesh adaptation) "
31416  << "[n_ele_old_mesh=" << n_element
31417  << ", n_ele_new_mesh=" << n_element_new
31418  << "]: " << tt_projection << std::endl;
31419 
31420  // ------------------------------------------
31421  // DISTRIBUTED MESH: BEGIN
31422  // ------------------------------------------
31423 #ifdef OOMPH_HAS_MPI
31424  if (this->is_mesh_distributed())
31425  {
31426  // The maximum number of elements in the mesh (over all
31427  // processors)
31428  unsigned n_this_element_new = n_element_new;
31429  unsigned n_max_element_new_global = 0;
31430  // Get the maximum number of elements over all processors
31431  MPI_Reduce(&n_this_element_new,
31432  &n_max_element_new_global,
31433  1,
31434  MPI_UNSIGNED,
31435  MPI_MAX,
31436  0,
31437  this->communicator_pt()->mpi_comm());
31438 
31439  // The time for projection for this processor
31440  double tt_this_projection = tt_projection;
31441  double tt_global_min_projection = 0.0;
31442  double tt_global_max_projection = 0.0;
31443 
31444  // Get the minimum and maximum time for projection
31445  MPI_Reduce(&tt_this_projection,
31446  &tt_global_min_projection,
31447  1,
31448  MPI_DOUBLE,
31449  MPI_MIN,
31450  0,
31451  this->communicator_pt()->mpi_comm());
31452  MPI_Reduce(&tt_this_projection,
31453  &tt_global_max_projection,
31454  1,
31455  MPI_DOUBLE,
31456  MPI_MAX,
31457  0,
31458  this->communicator_pt()->mpi_comm());
31459 
31460  if (this->communicator_pt()->my_rank() == 0)
31461  {
31462  oomph_info << "CPU for projection global (MIN): "
31463  << tt_global_min_projection << std::endl;
31464  oomph_info << "CPU for projection global (MAX) "
31465  << "[n_max_ele_new_global=" << n_max_element_new_global
31466  << "]: " << tt_global_max_projection << std::endl;
31467 
31468  std::cerr << "CPU for projection global (MIN): "
31469  << tt_global_min_projection << std::endl;
31470  std::cerr << "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  }
31475 #endif // #ifdef OOMPH_HAS_MPI
31476  // ------------------------------------------
31477  // DISTRIBUTED MESH: END
31478  // ------------------------------------------
31479 
31480  } // if (Print_timings_level_adaptation>1)
31481 
31482  oomph_info << "CPU for projection of solution onto new mesh: "
31483  << TimingHelpers::timer() - t_proj << std::endl;
31484 
31485  // Delete the projection problem
31486  delete project_problem_pt;
31487 
31488  } // if (!Disable_projection)
31489  else
31490  {
31491  oomph_info << "Projection disabled! The new mesh will contain zeros"
31492  << std::endl;
31493  }
31494 
31495  // ==============================================================
31496  // END: Project solution from the old to the new mesh
31497  // ==============================================================
31498 
31499  double t_rest = TimingHelpers::timer();
31500 
31501  // Flush the old mesh
31502  unsigned nnod = nnode();
31503  for (unsigned j = nnod; j > 0; j--)
31504  {
31505  delete Node_pt[j - 1];
31506  Node_pt[j - 1] = 0;
31507  }
31508  unsigned nel = nelement();
31509  for (unsigned e = nel; e > 0; e--)
31510  {
31511  delete Element_pt[e - 1];
31512  Element_pt[e - 1] = 0;
31513  }
31514 
31515  // Now copy back to current mesh
31516  //------------------------------
31517  nnod = new_mesh_pt->nnode();
31518  Node_pt.resize(nnod);
31519  nel = new_mesh_pt->nelement();
31520  Element_pt.resize(nel);
31521  for (unsigned j = 0; j < nnod; j++)
31522  {
31523  Node_pt[j] = new_mesh_pt->node_pt(j);
31524  }
31525  for (unsigned e = 0; e < nel; e++)
31526  {
31527  Element_pt[e] = new_mesh_pt->element_pt(e);
31528  }
31529 
31530  // Copy the boundary elements information from the new mesh to the
31531  // original mesh
31532  unsigned nbound = 0;
31533 
31534 #ifdef OOMPH_HAS_MPI
31535  // If working with a distributed mesh we need to change the number
31536  // of boundaries so that shared boundaries information is also
31537  // copied from the old to the new mesh
31538  if (this->is_mesh_distributed())
31539  {
31540  // The boundaries to be copied include those new ones in the new
31541  // mesh (shared boundaries). This info. is required to
31542  // re-establish the halo/haloed scheme
31543  nbound = new_mesh_pt->nboundary();
31544  // After halo and haloed scheme has been re-established the
31545  // number of boundaries is changed to the original number of
31546  // boundaries
31547  }
31548  else
31549 #endif
31550  {
31551  // The original number of boundaries
31552  nbound = n_boundary;
31553  }
31554 
31555  Boundary_element_pt.resize(nbound);
31556  Face_index_at_boundary.resize(nbound);
31557  Boundary_node_pt.resize(nbound);
31558  for (unsigned b = 0; b < nbound; b++)
31559  {
31560  unsigned nel = new_mesh_pt->nboundary_element(b);
31561  Boundary_element_pt[b].resize(nel);
31562  Face_index_at_boundary[b].resize(nel);
31563  for (unsigned e = 0; e < nel; e++)
31564  {
31565  Boundary_element_pt[b][e] = new_mesh_pt->boundary_element_pt(b, e);
31566  Face_index_at_boundary[b][e] =
31567  new_mesh_pt->face_index_at_boundary(b, e);
31568  }
31569  unsigned nnod = new_mesh_pt->nboundary_node(b);
31570  Boundary_node_pt[b].resize(nnod);
31571  for (unsigned j = 0; j < nnod; j++)
31572  {
31573  Boundary_node_pt[b][j] = new_mesh_pt->boundary_node_pt(b, j);
31574  }
31575  }
31576 
31577  // Also copy over the new boundary and region information
31578  unsigned n_region = new_mesh_pt->nregion();
31579  // Only bother if we have regions
31580  if (n_region > 1)
31581  {
31582  // Deal with the region information first
31583  this->Region_attribute.resize(n_region);
31584  for (unsigned r = 0; r < n_region; r++)
31585  {
31586  this->Region_attribute[r] = new_mesh_pt->region_attribute(r);
31587  // Get the region id
31588  unsigned r_id = static_cast<unsigned>(this->Region_attribute[r]);
31589  // Find the number of elements in the region
31590  unsigned n_region_element = new_mesh_pt->nregion_element(r_id);
31591  this->Region_element_pt[r_id].resize(n_region_element);
31592  for (unsigned e = 0; e < n_region_element; e++)
31593  {
31594  this->Region_element_pt[r_id][e] =
31595  new_mesh_pt->region_element_pt(r_id, e);
31596  }
31597  }
31598 
31599  // Now the boundary region information
31600  this->Boundary_region_element_pt.resize(nbound);
31601  this->Face_index_region_at_boundary.resize(nbound);
31602 
31603  // Now loop over the boundaries
31604  for (unsigned b = 0; b < nbound; ++b)
31605  {
31606  for (unsigned rr = 0; rr < n_region; rr++)
31607  {
31608  // The region id
31609  unsigned r = static_cast<unsigned>(this->Region_attribute[rr]);
31610 
31611  unsigned n_boundary_el_in_region =
31612  new_mesh_pt->nboundary_element_in_region(b, r);
31613 
31614  if (n_boundary_el_in_region > 0)
31615  {
31616  // Allocate storage in the map
31617  this->Boundary_region_element_pt[b][r].resize(
31618  n_boundary_el_in_region);
31619  this->Face_index_region_at_boundary[b][r].resize(
31620  n_boundary_el_in_region);
31621 
31622  // Copy over the information
31623  for (unsigned e = 0; e < n_boundary_el_in_region; ++e)
31624  {
31625  this->Boundary_region_element_pt[b][r][e] =
31626  new_mesh_pt->boundary_element_in_region_pt(b, r, e);
31627  this->Face_index_region_at_boundary[b][r][e] =
31628  new_mesh_pt->face_index_at_boundary_in_region(b, r, e);
31629  }
31630  }
31631  }
31632  } // End of loop over boundaries
31633 
31634  } // End of case when more than one region
31635 
31636  // ------------------------------------------
31637  // DISTRIBUTED MESH: BEGIN
31638  // ------------------------------------------
31639 
31640  // Re-generate halo(ed) information (only for distributed meshes)
31641 #ifdef OOMPH_HAS_MPI
31642  if (this->is_mesh_distributed())
31643  {
31644  // Delete halo(ed) information in the original mesh, the new
31645  // halo(ed) information is generated usign the info. of the new
31646  // mesh
31647  if (this->is_mesh_distributed())
31648  {
31649  this->Halo_node_pt.clear();
31650  this->Root_halo_element_pt.clear();
31651 
31652  this->Haloed_node_pt.clear();
31653  this->Root_haloed_element_pt.clear();
31654 
31655  this->External_halo_node_pt.clear();
31656  this->External_halo_element_pt.clear();
31657 
31658  this->External_haloed_node_pt.clear();
31659  this->External_haloed_element_pt.clear();
31660  }
31661 
31662  // Re-establish the shared boundary elements and nodes scheme
31663  // before re-establish halo(ed) information
31664  this->reset_shared_boundary_elements_and_nodes();
31665 
31666  // -------------------------------------------------------------
31667  // Remove shared boundary elements and nodes from original
31668  // boundary elements and boundary nodes containers. Shared
31669  // boundary elements and nodes are stored in a special
31670  // container.
31671 
31672  // Get the shared boundaries in this processor with any other
31673  // processor
31674  Vector<unsigned> my_rank_shared_boundaries_ids;
31675  this->shared_boundaries_in_this_processor(
31676  my_rank_shared_boundaries_ids);
31677 
31678  // Get the number of shared boundaries
31679  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
31680  // Loop over the shared boundaries marked as original boundaries
31681  // in tmp_new_mesh
31682  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
31683  {
31684  // Get the boundary id
31685  const unsigned shd_bnd_id = my_rank_shared_boundaries_ids[i];
31686  // Flush any previous relation of shared boundary elements
31687  // marked as original boundary elements in tmp_new_mesh
31688  this->Boundary_element_pt[shd_bnd_id].clear();
31689 
31690  // Get the number of nodes associated with the original
31691  // boundary in tmp_new_mesh that is a shared boundary
31692  const unsigned tmp_nnodes = this->nshared_boundary_node(shd_bnd_id);
31693  for (unsigned n = 0; n < tmp_nnodes; n++)
31694  {
31695  Node* tmp_node_pt = this->boundary_node_pt(shd_bnd_id, n);
31696  tmp_node_pt->remove_from_boundary(shd_bnd_id);
31697  } // for (n < nnodes)
31698 
31699  } // for (shd_bnd_id < nmy_rank_shd_bnd)
31700 
31701  // Re-set the number of boundaries to the original one
31702  this->set_nboundary(n_boundary);
31703 
31704  // Sort the nodes on the boundaries so that they have the same
31705  // order on all the boundaries
31706  this->sort_nodes_on_shared_boundaries();
31707 
31708  // Re-set the halo(ed) scheme
31709  this->reset_halo_haloed_scheme();
31710 
31711  // Set the correct number of segments for the boundaries with
31712  // geom objects associated
31713  for (unsigned b = 0; b < n_boundary; b++)
31714  {
31715  if (this->boundary_geom_object_pt(b) != 0)
31716  {
31717  const unsigned nsegments = new_mesh_pt->nboundary_segment(b);
31718  this->set_nboundary_segment_node(b, nsegments);
31719  }
31720  }
31721 
31722  // Resume the connections in boundaries were it was suspended
31723  resume_boundary_connections(resume_initial_connection_polyline_pt,
31724  resume_final_connection_polyline_pt);
31725 
31726  } // if (this->is_mesh_distributed())
31727 
31728 #endif // #ifdef OOMPH_HAS_MPI
31729 
31730  // ------------------------------------------
31731  // DISTRIBUTED MESH: END
31732  // ------------------------------------------
31733 
31734  // Snap the newly created nodes onto any geometric objects
31735  this->snap_nodes_onto_geometric_objects();
31736 
31737  // Copy the IDs of the vertex nodes
31738  this->Oomph_vertex_nodes_id = new_mesh_pt->oomph_vertex_nodes_id();
31739 
31740  // Copy TriangulateIO representation
31741  TriangleHelper::clear_triangulateio(this->Triangulateio);
31742  bool quiet = true;
31743  this->Triangulateio =
31744  TriangleHelper::deep_copy_of_triangulateio_representation(
31745  new_mesh_pt->triangulateio_representation(), quiet);
31746 
31747  // Flush the mesh
31748  new_mesh_pt->flush_element_and_node_storage();
31749 
31750  // Delete the mesh
31751  delete new_mesh_pt;
31752 
31753  // Resume of timings
31754  if (Print_timings_level_adaptation > 2)
31755  {
31756  // Report timings related with setting boundary coordinates of
31757  // nodes on segments
31758  oomph_info << "CPU for segments connectivity (first stage) [sec]: "
31759  << t_total_first_stage_segments_connectivity << std::endl;
31760  oomph_info << "CPU for segments connectivity (second stage) [sec]: "
31761  << t_total_second_stage_segments_connectivity << std::endl;
31762  oomph_info << "CPU for segments connectivity (third stage) [sec]: "
31763  << t_total_third_stage_segments_connectivity << std::endl;
31764  }
31765 
31766  if (Print_timings_level_adaptation > 1)
31767  {
31768  const double t_total_segments_connectivity =
31769  t_total_first_stage_segments_connectivity +
31770  t_total_second_stage_segments_connectivity +
31771  t_total_third_stage_segments_connectivity;
31772 
31773  oomph_info << "CPU for segments connectivity (TOTAL) [sec]: "
31774  << t_total_segments_connectivity << std::endl;
31775 
31776  if (Print_timings_level_adaptation > 2)
31777  {
31778  // Report timings for snapping of nodes onto boundaries
31779  oomph_info << "CPU for snapping nodes onto boundaries "
31780  << "(new mesh): " << t_total_snap_nodes << std::endl;
31781  }
31782 
31783  t_total_snap_nodes += t_total_snap_nodes_bg_mesh;
31784  oomph_info << "CPU for snapping nodes onto boundaries (TOTAL): "
31785  << t_total_snap_nodes << std::endl;
31786  }
31787 
31788  double max_area = 0.0;
31789  double min_area = 0.0;
31790 
31791  this->max_and_min_element_size(max_area, min_area);
31792  oomph_info << "Max/min element size in adapted mesh: " << max_area << " "
31793  << min_area << std::endl;
31794 
31795  oomph_info << "CPU time for final bits [sec]: "
31796  << TimingHelpers::timer() - t_rest << std::endl;
31797  }
31798  else
31799  {
31800  oomph_info << "Not enough benefit in adaptation.\n";
31801  Nrefined = 0;
31802  Nunrefined = 0;
31803  }
31804 
31805  double CPU_for_adaptation = TimingHelpers::timer() - t_start_overall;
31806  oomph_info << "CPU time for adaptation [sec]: " << CPU_for_adaptation
31807  << std::endl;
31808 
31809  // ------------------------------------------
31810  // DISTRIBUTED MESH: BEGIN
31811  // ------------------------------------------
31812 #ifdef OOMPH_HAS_MPI
31813  if (this->is_mesh_distributed())
31814  {
31815  // Get the communicator
31816  OomphCommunicator* comm_pt = this->communicator_pt();
31817  // Get the total number of processors to compute the average
31818  const unsigned n_proc = comm_pt->nproc();
31819  if (Print_timings_level_adaptation > 1 && n_proc > 1)
31820  {
31821  double global_min_CPU_for_adaptation = 0.0;
31822  double global_max_CPU_for_adaptation = 0.0;
31823  double global_average_CPU_for_adaptation = 0.0;
31824 
31825  // Get the maximum and minimum of the adaptation times
31826  MPI_Reduce(&CPU_for_adaptation,
31827  &global_min_CPU_for_adaptation,
31828  1,
31829  MPI_DOUBLE,
31830  MPI_MIN,
31831  0,
31832  comm_pt->mpi_comm());
31833  MPI_Reduce(&CPU_for_adaptation,
31834  &global_max_CPU_for_adaptation,
31835  1,
31836  MPI_DOUBLE,
31837  MPI_MAX,
31838  0,
31839  comm_pt->mpi_comm());
31840  MPI_Reduce(&CPU_for_adaptation,
31841  &global_average_CPU_for_adaptation,
31842  1,
31843  MPI_DOUBLE,
31844  MPI_SUM,
31845  0,
31846  comm_pt->mpi_comm());
31847 
31848  // Get the rank of the processor
31849  const unsigned my_rank = comm_pt->my_rank();
31850  if (my_rank == 0)
31851  {
31852  oomph_info << "CPU for adaptation (MIN): "
31853  << global_min_CPU_for_adaptation << std::endl;
31854  oomph_info << "CPU for adaptation (MAX): "
31855  << global_max_CPU_for_adaptation << std::endl;
31856  oomph_info << "CPU for adaptation (AVERAGE): "
31857  << global_average_CPU_for_adaptation / n_proc << std::endl;
31858  } // if (my_rank==0)
31859 
31860  } // if (Print_timings_level_adaptation>1&&n_proc>1)
31861 
31862  } // if (this->is_mesh_distributed())
31863 
31864  // ------------------------------------------
31865  // DISTRIBUTED MESH: END
31866  // ------------------------------------------
31867 
31868 #endif // #ifdef OOMPH_HAS_MPI
31869  }
31870 
31871  //=========================================================================
31872  /// Mark the vertices that are not allowed for deletion by
31873  /// the unrefienment/refinement polyline methods. In charge of
31874  /// filling the Boundary_connections_pt structure
31875  //=========================================================================
31876  template<class ELEMENT>
31878  {
31879  // Clear any previous information
31880  // Boundary_chunk_connections_pt.clear();
31881  Boundary_connections_pt.clear();
31882 
31883  // Loop over the boundaries in the domain (outer, internal -- closed
31884  // and open ---, and shared) and get the boundaries ids with
31885  // connections (have or receive)
31886 
31887  // Store the boundaries ids that have or receive connection
31888  std::set<unsigned> boundary_id_with_connections;
31889 
31890  // ------------------------------------------------------------------
31891  // Outer boundaries
31892  // ------------------------------------------------------------------
31893 
31894  // Get the number of outer boundaries (closed boundaries)
31895  const unsigned n_outer_boundaries = this->Outer_boundary_pt.size();
31896 
31897  // Loop over the outer boundaries
31898  for (unsigned i = 0; i < n_outer_boundaries; i++)
31899  {
31900  // Get a temporary polygon representation
31901  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
31902  // Get the number of polylines associated to the current outer
31903  // boundary
31904  const unsigned n_polyline = tmp_polygon_pt->npolyline();
31905  // Loop over the polylines
31906  for (unsigned p = 0; p < n_polyline; p++)
31907  {
31908  // Get a temporary representation of the polyline
31909  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
31910 
31911  // Is the initial vertex connected?
31912  if (tmp_polyline_pt->is_initial_vertex_connected())
31913  {
31914  // Get the boundary id of the current polyline
31915  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31916 
31917  // Include the boundary id to the set of boundaries with
31918  // connections
31919  boundary_id_with_connections.insert(bnd_id);
31920 
31921  // Boundary id to which the curve is connecte
31922  const unsigned dst_bnd_id =
31923  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31924 
31925  // Include the destination boundary id to the set of
31926  // boundaries with connections
31927  boundary_id_with_connections.insert(dst_bnd_id);
31928 
31929  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31930 
31931  // Is the final vertex connected?
31932  if (tmp_polyline_pt->is_final_vertex_connected())
31933  {
31934  // Get the boundary id of the current polyline
31935  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31936 
31937  // Include the boundary id to the set of boundaries with
31938  // connections
31939  boundary_id_with_connections.insert(bnd_id);
31940 
31941  // Boundary id to which the curve is connected
31942  const unsigned dst_bnd_id =
31943  tmp_polyline_pt->final_vertex_connected_bnd_id();
31944 
31945  // Include the destination boundary id to the set of
31946  // boundaries with connections
31947  boundary_id_with_connections.insert(dst_bnd_id);
31948 
31949  } // if (tmp_polyline_pt->is_final_vertex_connected())
31950 
31951  } // for (p < n_polyline)
31952 
31953  } // for (i < n_outer_boundaries)
31954 
31955  // ------------------------------------------------------------------
31956  // Internal boundaries
31957  // ------------------------------------------------------------------
31958 
31959  // Get the number of internal boundaries (closed boundaries)
31960  const unsigned n_internal_boundaries = this->Internal_polygon_pt.size();
31961 
31962  // Loop over the internal boundaries
31963  for (unsigned i = 0; i < n_internal_boundaries; i++)
31964  {
31965  // Get a temporary polygon representation
31966  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
31967  // Get the number of polylines associated to the current internal
31968  // boundary
31969  const unsigned n_polyline = tmp_polygon_pt->npolyline();
31970  // Loop over the polylines
31971  for (unsigned p = 0; p < n_polyline; p++)
31972  {
31973  // Get a temporary representation of the polyline
31974  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
31975 
31976  // Is the initial vertex connected?
31977  if (tmp_polyline_pt->is_initial_vertex_connected())
31978  {
31979  // Get the boundary id of the current polyline
31980  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31981 
31982  // Include the boundary id to the set of boundaries with
31983  // connections
31984  boundary_id_with_connections.insert(bnd_id);
31985 
31986  // Boundary id to which the curve is connecte
31987  const unsigned dst_bnd_id =
31988  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31989 
31990  // Include the destination boundary id to the set of
31991  // boundaries with connections
31992  boundary_id_with_connections.insert(dst_bnd_id);
31993 
31994  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31995 
31996  // Is the final vertex connected?
31997  if (tmp_polyline_pt->is_final_vertex_connected())
31998  {
31999  // Get the boundary id of the current polyline
32000  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32001 
32002  // Include the boundary id to the set of boundaries with
32003  // connections
32004  boundary_id_with_connections.insert(bnd_id);
32005 
32006  // Boundary id to which the curve is connected
32007  const unsigned dst_bnd_id =
32008  tmp_polyline_pt->final_vertex_connected_bnd_id();
32009 
32010  // Include the destination boundary id to the set of
32011  // boundaries with connections
32012  boundary_id_with_connections.insert(dst_bnd_id);
32013 
32014  } // if (tmp_polyline_pt->is_final_vertex_connected())
32015 
32016  } // for (p < n_polyline)
32017 
32018  } // for (i < n_internal_boundaries)
32019 
32020  // ------------------------------------------------------------------
32021  // Open boundaries (nonclosed internal boundaries)
32022  // ------------------------------------------------------------------
32023 
32024  // Get the number of internal boundaries (open boundaries)
32025  const unsigned n_open_boundaries = this->Internal_open_curve_pt.size();
32026 
32027  // Loop over the internal open boundaries
32028  for (unsigned i = 0; i < n_open_boundaries; i++)
32029  {
32030  // Get a temporary representation for the open curve
32031  TriangleMeshOpenCurve* tmp_open_curve_pt =
32032  this->Internal_open_curve_pt[i];
32033 
32034  // Get the number of curve sections associated to the current
32035  // internal open boundary
32036  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
32037 
32038  // Loop over the curve section
32039  for (unsigned p = 0; p < n_curve_section; p++)
32040  {
32041  // Get a temporary representation of the curve section
32042  // (polyline)
32043  TriangleMeshPolyLine* tmp_polyline_pt =
32044  tmp_open_curve_pt->polyline_pt(p);
32045 
32046  // Is the initial vertex connected?
32047  if (tmp_polyline_pt->is_initial_vertex_connected())
32048  {
32049  // Get the boundary id of the current polyline
32050  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32051 
32052  // Include the boundary id to the set of boundaries with
32053  // connections
32054  boundary_id_with_connections.insert(bnd_id);
32055 
32056  // Boundary id to which the curve is connecte
32057  const unsigned dst_bnd_id =
32058  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32059 
32060  // Include the destination boundary id to the set of
32061  // boundaries with connections
32062  boundary_id_with_connections.insert(dst_bnd_id);
32063 
32064  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32065 
32066  // Is the final vertex connected?
32067  if (tmp_polyline_pt->is_final_vertex_connected())
32068  {
32069  // Get the boundary id of the current polyline
32070  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32071 
32072  // Include the boundary id to the set of boundaries with
32073  // connections
32074  boundary_id_with_connections.insert(bnd_id);
32075 
32076  // Boundary id to which the curve is connected
32077  const unsigned dst_bnd_id =
32078  tmp_polyline_pt->final_vertex_connected_bnd_id();
32079 
32080  // Include the destination boundary id to the set of
32081  // boundaries with connections
32082  boundary_id_with_connections.insert(dst_bnd_id);
32083 
32084  } // if (tmp_polyline_pt->is_final_vertex_connected())
32085 
32086  } // for (p < n_curve_section)
32087 
32088  } // for (i < n_open_boundaries)
32089 
32090 #ifdef OOMPH_HAS_MPI
32091  // ------------------------------------------------------------------
32092  // Shared boundaries (only for distributed meshes)
32093  // ------------------------------------------------------------------
32094 
32095  // Check if we need to include any information associated with
32096  // shared boundaries
32097  if (this->is_mesh_distributed())
32098  {
32099  // Get the rank of the current processor
32100  const unsigned my_rank = this->communicator_pt()->my_rank();
32101 
32102  // Get the number of shared curves in the current processor
32103  const unsigned n_shared_curves = this->nshared_boundary_curves(my_rank);
32104 
32105  // Loop over the shared curves
32106  for (unsigned i = 0; i < n_shared_curves; i++)
32107  {
32108  // Get the number of polylines associated to the current shared
32109  // curve
32110  const unsigned n_polyline = this->nshared_boundary_polyline(my_rank, i);
32111 
32112  // Loop over the polylines associated to the current shared
32113  // curve
32114  for (unsigned p = 0; p < n_polyline; p++)
32115  {
32116  // Get a temporary representation of the shared polyline
32117  TriangleMeshPolyLine* tmp_polyline_pt =
32118  this->shared_boundary_polyline_pt(my_rank, i, p);
32119 
32120  // Is the initial vertex connected?
32121  if (tmp_polyline_pt->is_initial_vertex_connected())
32122  {
32123  // Get the boundary id of the current polyline
32124  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32125 
32126  // Include the boundary id to the set of boundaries with
32127  // connections
32128  boundary_id_with_connections.insert(bnd_id);
32129 
32130  // Boundary id to which the curve is connecte
32131  const unsigned dst_bnd_id =
32132  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32133 
32134  // Include the destination boundary id to the set of
32135  // boundaries with connections
32136  boundary_id_with_connections.insert(dst_bnd_id);
32137 
32138  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32139 
32140  // Is the final vertex connected?
32141  if (tmp_polyline_pt->is_final_vertex_connected())
32142  {
32143  // Get the boundary id of the current polyline
32144  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32145 
32146  // Include the boundary id to the set of boundaries with
32147  // connections
32148  boundary_id_with_connections.insert(bnd_id);
32149 
32150  // Boundary id to which the curve is connected
32151  const unsigned dst_bnd_id =
32152  tmp_polyline_pt->final_vertex_connected_bnd_id();
32153 
32154  // Include the destination boundary id to the set of
32155  // boundaries with connections
32156  boundary_id_with_connections.insert(dst_bnd_id);
32157 
32158  } // if (tmp_polyline_pt->is_final_vertex_connected())
32159 
32160  } // for (p < n_polyline)
32161 
32162  } // for (i < n_shared_curves)
32163 
32164  } // if (this->is_mesh_distributed())
32165 
32166 #endif // #ifdef OOMPH_HAS_MPI
32167 
32168  // ---------------------------------------------------------------
32169  // Get the nodes sorted by segments of the boundaries with
32170  // connections
32171 
32172  // Store the sorted nodes by segments of the boundaries with
32173  // connections
32174  std::map<unsigned, Vector<Vector<Node*>>> bnd_sorted_segment_node_pt;
32175 
32176  // Loop over the boundaries with connections
32177  for (std::set<unsigned>::iterator it = boundary_id_with_connections.begin();
32178  it != boundary_id_with_connections.end();
32179  it++)
32180  {
32181  // Get the boundary id
32182  const unsigned bnd_id = (*it);
32183 #ifdef OOMPH_HAS_MPI
32184  // Working with a distributed mesh
32185  if (this->is_mesh_distributed())
32186  {
32187  // Get the initial shared boundary id
32188  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
32189  // Is an original or shared boundary
32190  if (bnd_id >= init_shd_bnd_id)
32191  {
32192  // Is a shared boundary
32193 
32194  // Temporary storage for the nodes on the shared boundary
32195  Vector<Vector<Node*>> tmp_shared_nodes_pt;
32196 
32197  // Get the nodes associated to the shared boundary
32198  get_shared_boundary_segment_nodes_helper(bnd_id, tmp_shared_nodes_pt);
32199 
32200  // Store the nodes associated to the shared boundary
32201  bnd_sorted_segment_node_pt[bnd_id] = tmp_shared_nodes_pt;
32202 
32203  } // if (bnd_id >= init_shd_bnd_id)
32204  else
32205  {
32206  // Is an original boundary
32207 
32208  // Temporary storage for the nodes on the original boundary
32209  Vector<Vector<Node*>> tmp_boundary_nodes_pt;
32210 
32211  // Get the nodes associated to the shared boundary
32212  get_boundary_segment_nodes_helper(bnd_id, tmp_boundary_nodes_pt);
32213 
32214  // Store the nodes associated to the shared boundary
32215  bnd_sorted_segment_node_pt[bnd_id] = tmp_boundary_nodes_pt;
32216 
32217  } // if (bnd_id >= init_shd_bnd_id)
32218 
32219  } // if (this->is_mesh_distributed())
32220  else
32221 #endif // #ifdef OOMPH_HAS_MPI
32222  {
32223  // Is an original boundary
32224 
32225  // Temporary storage for the nodes on the original boundary
32226  Vector<Vector<Node*>> tmp_boundary_nodes_pt;
32227 
32228  // Get the nodes associated to the shared boundary
32229  get_boundary_segment_nodes_helper(bnd_id, tmp_boundary_nodes_pt);
32230 
32231  // Store the nodes associated to the shared boundary
32232  bnd_sorted_segment_node_pt[bnd_id] = tmp_boundary_nodes_pt;
32233 
32234  } // if (this->is_mesh_distributed())
32235 
32236  } // Loop over boundaries with connections
32237 
32238  // -----------------------------------------------------------------
32239  // Loop again over the boundaries (original and shared) and search
32240  // for the repeated nodes in those boundaries with connections
32241 
32242  // ------------------------------------------------------------------
32243  // Outer boundaries
32244  // ------------------------------------------------------------------
32245  // Loop over the outer boundaries
32246  for (unsigned i = 0; i < n_outer_boundaries; i++)
32247  {
32248  // Get a temporary polygon representation
32249  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
32250  // Get the number of polylines associated to the current outer
32251  // boundary
32252  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32253  // Loop over the polylines
32254  for (unsigned p = 0; p < n_polyline; p++)
32255  {
32256  // Get a temporary representation of the polyline
32257  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
32258 
32259  // Is the initial vertex connected?
32260  if (tmp_polyline_pt->is_initial_vertex_connected())
32261  {
32262  // Get the boundary id of the current polyline
32263  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32264 
32265  // Boundary id to which the curve is connected
32266  const unsigned dst_bnd_id =
32267  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32268 
32269  // Boundary chunk to which the curve is connected
32270  const unsigned dst_chunk =
32271  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32272 
32273  // Get the nodes representation of the current boundary
32274  Vector<Vector<Node*>> src_bnd_node_pt =
32275  bnd_sorted_segment_node_pt[bnd_id];
32276 
32277  // Get the nodes representation of the boundary to connect
32278  Vector<Vector<Node*>> dst_bnd_node_pt =
32279  bnd_sorted_segment_node_pt[dst_bnd_id];
32280 
32281  // Add the repeated node to the list of non delete-able
32282  // vertices
32283  add_non_delete_vertices_from_boundary_helper(
32284  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32285 
32286  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32287 
32288  // Is the final vertex connected?
32289  if (tmp_polyline_pt->is_final_vertex_connected())
32290  {
32291  // Get the boundary id of the current polyline
32292  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32293 
32294  // Boundary id to which the curve is connected
32295  const unsigned dst_bnd_id =
32296  tmp_polyline_pt->final_vertex_connected_bnd_id();
32297 
32298  // Boundary chunk to which the curve is connected
32299  const unsigned dst_chunk =
32300  tmp_polyline_pt->final_vertex_connected_n_chunk();
32301 
32302  // Get the nodes representation of the current boundary
32303  Vector<Vector<Node*>> src_bnd_node_pt =
32304  bnd_sorted_segment_node_pt[bnd_id];
32305 
32306  // Get the nodes representation of the boundary to connect
32307  Vector<Vector<Node*>> dst_bnd_node_pt =
32308  bnd_sorted_segment_node_pt[dst_bnd_id];
32309 
32310  // Add the repeated node to the list of non delete-able
32311  // vertices
32312  add_non_delete_vertices_from_boundary_helper(
32313  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32314 
32315  } // if (tmp_polyline_pt->is_final_vertex_connected())
32316 
32317  } // for (p < n_polyline)
32318 
32319  } // for (i < n_outer_boundaries)
32320 
32321  // ------------------------------------------------------------------
32322  // Internal boundaries
32323  // ------------------------------------------------------------------
32324  // Loop over the internal boundaries
32325  for (unsigned i = 0; i < n_internal_boundaries; i++)
32326  {
32327  // Get a temporary polygon representation
32328  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
32329  // Get the number of polylines associated to the current internal
32330  // boundary
32331  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32332  // Loop over the polylines
32333  for (unsigned p = 0; p < n_polyline; p++)
32334  {
32335  // Get a temporary representation of the polyline
32336  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
32337 
32338  // Is the initial vertex connected?
32339  if (tmp_polyline_pt->is_initial_vertex_connected())
32340  {
32341  // Get the boundary id of the current polyline
32342  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32343 
32344  // Boundary id to which the curve is connected
32345  const unsigned dst_bnd_id =
32346  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32347 
32348  // Boundary chunk to which the curve is connected
32349  const unsigned dst_chunk =
32350  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32351 
32352  // Get the nodes representation of the current boundary
32353  Vector<Vector<Node*>> src_bnd_node_pt =
32354  bnd_sorted_segment_node_pt[bnd_id];
32355 
32356  // Get the nodes representation of the boundary to connect
32357  Vector<Vector<Node*>> dst_bnd_node_pt =
32358  bnd_sorted_segment_node_pt[dst_bnd_id];
32359 
32360  // Add the repeated node to the list of non delete-able
32361  // vertices
32362  add_non_delete_vertices_from_boundary_helper(
32363  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32364 
32365  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32366 
32367  // Is the final vertex connected?
32368  if (tmp_polyline_pt->is_final_vertex_connected())
32369  {
32370  // Get the boundary id of the current polyline
32371  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32372 
32373  // Boundary id to which the curve is connected
32374  const unsigned dst_bnd_id =
32375  tmp_polyline_pt->final_vertex_connected_bnd_id();
32376 
32377  // Boundary chunk to which the curve is connected
32378  const unsigned dst_chunk =
32379  tmp_polyline_pt->final_vertex_connected_n_chunk();
32380 
32381  // Get the nodes representation of the current boundary
32382  Vector<Vector<Node*>> src_bnd_node_pt =
32383  bnd_sorted_segment_node_pt[bnd_id];
32384 
32385  // Get the nodes representation of the boundary to connect
32386  Vector<Vector<Node*>> dst_bnd_node_pt =
32387  bnd_sorted_segment_node_pt[dst_bnd_id];
32388 
32389  // Add the repeated node to the list of non delete-able
32390  // vertices
32391  add_non_delete_vertices_from_boundary_helper(
32392  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32393 
32394  } // if (tmp_polyline_pt->is_final_vertex_connected())
32395 
32396  } // for (p < n_polyline)
32397 
32398  } // for (i < n_internal_boundaries)
32399 
32400  // ------------------------------------------------------------------
32401  // Open boundaries (nonclosed internal boundaries)
32402  // ------------------------------------------------------------------
32403  // Loop over the internal open boundaries
32404  for (unsigned i = 0; i < n_open_boundaries; i++)
32405  {
32406  // Get a temporary representation for the open curve
32407  TriangleMeshOpenCurve* tmp_open_curve_pt =
32408  this->Internal_open_curve_pt[i];
32409 
32410  // Get the number of curve sections associated to the current
32411  // internal open boundary
32412  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
32413 
32414  // Loop over the curve section
32415  for (unsigned p = 0; p < n_curve_section; p++)
32416  {
32417  // Get a temporary representation of the curve section
32418  // (polyline)
32419  TriangleMeshPolyLine* tmp_polyline_pt =
32420  tmp_open_curve_pt->polyline_pt(p);
32421 
32422  // Is the initial vertex connected?
32423  if (tmp_polyline_pt->is_initial_vertex_connected())
32424  {
32425  // Get the boundary id of the current polyline
32426  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32427 
32428  // Boundary id to which the curve is connected
32429  const unsigned dst_bnd_id =
32430  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32431 
32432  // Boundary chunk to which the curve is connected
32433  const unsigned dst_chunk =
32434  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32435 
32436  // Get the nodes representation of the current boundary
32437  Vector<Vector<Node*>> src_bnd_node_pt =
32438  bnd_sorted_segment_node_pt[bnd_id];
32439 
32440  // Get the nodes representation of the boundary to connect
32441  Vector<Vector<Node*>> dst_bnd_node_pt =
32442  bnd_sorted_segment_node_pt[dst_bnd_id];
32443 
32444  // Add the repeated node to the list of non delete-able
32445  // vertices
32446  add_non_delete_vertices_from_boundary_helper(
32447  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32448 
32449  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32450 
32451  // Is the final vertex connected?
32452  if (tmp_polyline_pt->is_final_vertex_connected())
32453  {
32454  // Get the boundary id of the current polyline
32455  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32456 
32457  // Boundary id to which the curve is connected
32458  const unsigned dst_bnd_id =
32459  tmp_polyline_pt->final_vertex_connected_bnd_id();
32460 
32461  // Boundary chunk to which the curve is connected
32462  const unsigned dst_chunk =
32463  tmp_polyline_pt->final_vertex_connected_n_chunk();
32464 
32465  // Get the nodes representation of the current boundary
32466  Vector<Vector<Node*>> src_bnd_node_pt =
32467  bnd_sorted_segment_node_pt[bnd_id];
32468 
32469  // Get the nodes representation of the boundary to connect
32470  Vector<Vector<Node*>> dst_bnd_node_pt =
32471  bnd_sorted_segment_node_pt[dst_bnd_id];
32472 
32473  // Add the repeated node to the list of non delete-able
32474  // vertices
32475  add_non_delete_vertices_from_boundary_helper(
32476  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32477 
32478  } // if (tmp_polyline_pt->is_final_vertex_connected())
32479 
32480  } // for (p < n_curve_section)
32481 
32482  } // for (i < n_open_boundaries)
32483 
32484 #ifdef OOMPH_HAS_MPI
32485  // ------------------------------------------------------------------
32486  // Shared boundaries (only for distributed meshes)
32487  // ------------------------------------------------------------------
32488 
32489  // Check if we need to include any information associated with
32490  // shared boundaries
32491  if (this->is_mesh_distributed())
32492  {
32493  // Get the rank of the current processor
32494  const unsigned my_rank = this->communicator_pt()->my_rank();
32495 
32496  // Get the number of shared curves in the current processor
32497  const unsigned n_shared_curves = this->nshared_boundary_curves(my_rank);
32498 
32499  // Loop over the shared curves
32500  for (unsigned i = 0; i < n_shared_curves; i++)
32501  {
32502  // Get the number of polylines associated to the current shared
32503  // curve
32504  const unsigned n_polyline = this->nshared_boundary_polyline(my_rank, i);
32505 
32506  // Loop over the polylines associated to the current shared
32507  // curve
32508  for (unsigned p = 0; p < n_polyline; p++)
32509  {
32510  // Get a temporary representation of the shared polyline
32511  TriangleMeshPolyLine* tmp_polyline_pt =
32512  this->shared_boundary_polyline_pt(my_rank, i, p);
32513 
32514  // Is the initial vertex connected?
32515  if (tmp_polyline_pt->is_initial_vertex_connected())
32516  {
32517  // Get the boundary id of the current polyline
32518  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32519 
32520  // Boundary id to which the curve is connected
32521  const unsigned dst_bnd_id =
32522  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32523 
32524  // Boundary chunk to which the curve is connected
32525  const unsigned dst_chunk =
32526  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32527 
32528  // Get the nodes representation of the current boundary
32529  Vector<Vector<Node*>> src_bnd_node_pt =
32530  bnd_sorted_segment_node_pt[bnd_id];
32531 
32532  // Get the nodes representation of the boundary to connect
32533  Vector<Vector<Node*>> dst_bnd_node_pt =
32534  bnd_sorted_segment_node_pt[dst_bnd_id];
32535 
32536  // Add the repeated node to the list of non delete-able
32537  // vertices
32538  add_non_delete_vertices_from_boundary_helper(
32539  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32540 
32541  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32542 
32543  // Is the final vertex connected?
32544  if (tmp_polyline_pt->is_final_vertex_connected())
32545  {
32546  // Get the boundary id of the current polyline
32547  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32548 
32549  // Boundary id to which the curve is connected
32550  const unsigned dst_bnd_id =
32551  tmp_polyline_pt->final_vertex_connected_bnd_id();
32552 
32553  // Boundary chunk to which the curve is connected
32554  const unsigned dst_chunk =
32555  tmp_polyline_pt->final_vertex_connected_n_chunk();
32556 
32557  // Get the nodes representation of the current boundary
32558  Vector<Vector<Node*>> src_bnd_node_pt =
32559  bnd_sorted_segment_node_pt[bnd_id];
32560 
32561  // Get the nodes representation of the boundary to connect
32562  Vector<Vector<Node*>> dst_bnd_node_pt =
32563  bnd_sorted_segment_node_pt[dst_bnd_id];
32564 
32565  // Add the repeated node to the list of non delete-able
32566  // vertices
32567  add_non_delete_vertices_from_boundary_helper(
32568  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32569 
32570  } // if (tmp_polyline_pt->is_final_vertex_connected())
32571 
32572  } // for (p < n_polyline)
32573 
32574  } // for (i < n_shared_curves)
32575 
32576  } // if (this->is_mesh_distributed())
32577 
32578 #endif // #ifdef OOMPH_HAS_MPI
32579  }
32580 
32581  //=========================================================================
32582  /// Adds the vertices from the sources boundary that are
32583  /// repeated in the destination boundary to the list of non
32584  /// delete-able vertices in the destination boundary
32585  //=========================================================================
32586  template<class ELEMENT>
32589  Vector<Vector<Node*>> src_bound_segment_node_pt,
32590  Vector<Vector<Node*>> dst_bound_segment_node_pt,
32591  const unsigned& dst_bnd_id,
32592  const unsigned& dst_bnd_chunk)
32593  {
32594  // Get the number of segments in the source boundary
32595  const unsigned n_seg = src_bound_segment_node_pt.size();
32596  // Loop over the segments in the source boundary
32597  for (unsigned iseg = 0; iseg < n_seg; iseg++)
32598  {
32599  // Get the number of nodes in the current segment
32600  const unsigned nnode = src_bound_segment_node_pt[iseg].size();
32601  // Get the left and right node of the current segment
32602  Node* left_node_pt = src_bound_segment_node_pt[iseg][0];
32603  Node* right_node_pt = src_bound_segment_node_pt[iseg][nnode - 1];
32604 
32605  // Get the number of segments in the destination boundary
32606  const unsigned n_dst_seg = dst_bound_segment_node_pt.size();
32607  // Loop over the segments in the destination boundary
32608  for (unsigned jseg = 0; jseg < n_dst_seg; jseg++)
32609  {
32610  // Get the number of nodes on the current destination segment
32611  const unsigned n_dst_node = dst_bound_segment_node_pt[jseg].size();
32612  // Loop over the nodes until the node has been found or we have
32613  // visited all the nodes
32614  for (unsigned jnode = 0; jnode < n_dst_node; jnode++)
32615  {
32616  // Get a pointer to the jnode in the destination segment
32617  // boundary
32618  Node* tmp_node_pt = dst_bound_segment_node_pt[jseg][jnode];
32619  // Is the node the same as the left or right node if
32620  // the source segment boundary
32621  if (tmp_node_pt == left_node_pt)
32622  {
32623  // We have foud the node to connect, get the vertex of the node
32624  Vector<double> vertex(2);
32625  vertex[0] = tmp_node_pt->x(0);
32626  vertex[1] = tmp_node_pt->x(1);
32627 
32628  // Establish the vertex coordinate as untouchable in the
32629  // destination boundary during the adaptation process. It
32630  // means that unrefinement can not take off the vertices
32631  // that receive connections in the destination boundary
32632  Boundary_connections_pt[dst_bnd_id].insert(vertex);
32633  // Boundary_chunk_connections_pt[dst_bnd_id][dst_bnd_chunk].
32634  // insert(vertex);
32635 
32636  // return
32637  return;
32638 
32639  } // if (tmp_node_pt == left_node_pt)
32640  else if (tmp_node_pt == right_node_pt)
32641  {
32642  // We have foud the node to connect, get the vertex of the node
32643  Vector<double> vertex(2);
32644  vertex[0] = tmp_node_pt->x(0);
32645  vertex[1] = tmp_node_pt->x(1);
32646 
32647  // Establish the vertex coordinate as untouchable in the
32648  // destination boundary during the adaptation process. It
32649  // means that unrefinement can not take off the vertices
32650  // that receive connections in the destination boundary
32651  // Boundary_chunk_connections_pt[dst_bnd_id][dst_bnd_chunk].
32652  // insert(vertex);
32653  Boundary_connections_pt[dst_bnd_id].insert(vertex);
32654 
32655  // return
32656  return;
32657 
32658  } // else if (tmp_node_pt == right_node_pt)
32659 
32660  } // for (jnode < n_dst_node)
32661 
32662  } // for (jseg < n_dst_seg)
32663 
32664  } // for (iseg < n_seg)
32665  }
32666 
32667 #ifdef OOMPH_HAS_MPI
32668  //=========================================================================
32669  /// Synchronise the vertices that are marked for non deletion
32670  // on the shared boundaries. Unrefinement of shared boundaries is
32671  // performed only if the candidate node is not marked for non deletion
32672  //=========================================================================
32673  template<class ELEMENT>
32674  const void RefineableTriangleMesh<
32675  ELEMENT>::synchronize_shared_boundary_connections()
32676  {
32677  // Get the number of processors
32678  const unsigned nproc = this->communicator_pt()->nproc();
32679  // Get my rank
32680  const unsigned my_rank = this->communicator_pt()->my_rank();
32681 
32682  // loop over the processors
32683  for (unsigned jproc = 0; jproc < nproc; jproc++)
32684  {
32685  // The number of boundaries shared with the current processor
32686  // (if jproc==my_rank then there are no shared boundaries
32687  // between them)
32688  const unsigned n_shd_bnd_jproc = this->nshared_boundaries(my_rank, jproc);
32689 
32690  // Are there shared boundaries with the jproc processor?
32691  // There are no info. with myself
32692  if (jproc != my_rank && n_shd_bnd_jproc > 0)
32693  {
32694  // Storage for the boundaries ids with vertices for non
32695  // deletion
32696  Vector<unsigned> shd_bnd_id_for_non_deletion;
32697 
32698  // Storage for chunk numbers of boundaries with vertices
32699  // for non deletion
32700  Vector<unsigned> chunk_for_non_deletion;
32701 
32702  // The number of vertices for nondeletion in the shared
32703  // boundaries
32704  Vector<unsigned> number_vertices_non_deletion;
32705 
32706  // Vertices marked for nondeletion in shared boundaries
32707  Vector<Vector<Vector<double>>> vertices_for_non_deletion;
32708 
32709  // Get the boundary ids of the shared boundaries with jproc
32710  // processor
32711  Vector<unsigned> shd_bnd_ids =
32712  this->shared_boundaries_ids(my_rank, jproc);
32713 
32714  // Get the number of shared boundaries with jproc
32715  const unsigned n_shd_bnd_jproc = shd_bnd_ids.size();
32716  // loop over the shared boundaries with jproc
32717  for (unsigned ishd_bnd = 0; ishd_bnd < n_shd_bnd_jproc; ishd_bnd++)
32718  {
32719  // Get the shared boudary id
32720  const unsigned shd_bnd_id = shd_bnd_ids[ishd_bnd];
32721  // Get the associated polyline
32722  TriangleMeshPolyLine* shd_polyline_pt =
32723  this->boundary_polyline_pt(shd_bnd_id);
32724  // Get the chunk number
32725  const unsigned chunk = shd_polyline_pt->boundary_chunk();
32726 
32727  // Store the vertices not allowed for deletion
32728  std::set<Vector<double>> no_delete_vertex;
32729 
32730  // Does the boundary has vertives for nondeleteion?
32731  const bool boundary_receive_connections =
32732  this->boundary_connections(shd_bnd_id, chunk, no_delete_vertex);
32733 
32734  // Get the number of vertices for nondeletion
32735  const unsigned n_non_delete_vertex = no_delete_vertex.size();
32736 
32737  // Are there vertices for nondeletion?
32738  if (boundary_receive_connections && n_non_delete_vertex > 0)
32739  {
32740  // Add the shared boundary id
32741  shd_bnd_id_for_non_deletion.push_back(shd_bnd_id);
32742  // Add the chunk number
32743  chunk_for_non_deletion.push_back(chunk);
32744  // Add the number of vertices for non deletion
32745  number_vertices_non_deletion.push_back(n_non_delete_vertex);
32746 
32747  // The list of vertices to add
32748  Vector<Vector<double>> tmp_vertices;
32749 
32750  // Add the vertices for non deletion
32751  for (std::set<Vector<double>>::iterator it =
32752  no_delete_vertex.begin();
32753  it != no_delete_vertex.end();
32754  it++)
32755  {
32756  // Get the vertex coordinate
32757  Vector<double> vertex = (*it);
32758  tmp_vertices.push_back(vertex);
32759  }
32760 
32761  // Add the vertices coordinates to a vector storage
32762  vertices_for_non_deletion.push_back(tmp_vertices);
32763 
32764  } // if (boundary_receive_connections && n_non_delete_vertex > 0)
32765 
32766  } // for (ishd_bnd<n_shd_bnd_jproc)
32767 
32768  // ----------------------------------------------------------
32769  // ----------------------------------------------------------
32770  // ----------------------------------------------------------
32771  // Now send the info. to the other processor (jproc)
32772  // ----------------------------------------------------------
32773  // ----------------------------------------------------------
32774  // ----------------------------------------------------------
32775  // Get the communicator of the mesh
32776  OomphCommunicator* comm_pt = this->communicator_pt();
32777 
32778  // Set MPI info
32779  MPI_Status status;
32780  MPI_Request request;
32781 
32782  // -----------------------------------------------------------
32783  // Prepare the data
32784  // Get the number of shared boundaires with vertices marked
32785  // for non deletion
32786  const unsigned n_shd_bnd_with_non_delete_vertices =
32787  shd_bnd_id_for_non_deletion.size();
32788 
32789  // Size of the package
32790  const unsigned size_package = 3;
32791  // Ndata to send
32792  const unsigned n_unsigned_data_to_send =
32793  n_shd_bnd_with_non_delete_vertices * size_package;
32794  // The flat package to send the info.
32795  Vector<unsigned> flat_package_unsigned_send(n_unsigned_data_to_send);
32796  Vector<double> flat_package_double_send;
32797 
32798  Vector<unsigned> flat_package_unsigned_recv;
32799  Vector<double> flat_package_double_recv;
32800 
32801  // Prepare the data to be sent
32802  unsigned j = 0;
32803  for (unsigned i = 0; i < n_shd_bnd_with_non_delete_vertices; i++)
32804  {
32805  // The shared boundary id
32806  flat_package_unsigned_send[j++] = shd_bnd_id_for_non_deletion[i];
32807  // The chunk number
32808  flat_package_unsigned_send[j++] = chunk_for_non_deletion[i];
32809  // The number of vertices for nondeletion
32810  flat_package_unsigned_send[j++] = number_vertices_non_deletion[i];
32811  // Also package the vertices
32812  const unsigned n_vertices_non_deletion =
32813  number_vertices_non_deletion[i];
32814  // Loop over the vertices and store them in the flat
32815  // package to be sent
32816  for (unsigned h = 0; h < n_vertices_non_deletion; h++)
32817  {
32818  flat_package_double_send.push_back(
32819  vertices_for_non_deletion[i][h][0]);
32820  flat_package_double_send.push_back(
32821  vertices_for_non_deletion[i][h][1]);
32822  } // for (h<n_vertices_non_deletion)
32823 
32824  } // for (i<n_shd_bnd_with_non_delete_vertices)
32825 
32826  // ----------------------------------------------------------
32827  int send_proc = jproc;
32828  int recv_proc = jproc;
32829  unsigned send_count_unsigned_values = n_unsigned_data_to_send;
32830  unsigned send_count_double_values = flat_package_double_send.size();
32831  //-----------------------------------------------------------
32832  // Do the transfering of info.
32833  //-----------------------------------------------------------
32834  // Start with UNSIGNED info.
32835  MPI_Isend(&send_count_unsigned_values,
32836  1,
32837  MPI_UNSIGNED,
32838  send_proc,
32839  1,
32840  comm_pt->mpi_comm(),
32841  &request);
32842 
32843  unsigned receive_count_unsigned_values = 0;
32844  MPI_Recv(&receive_count_unsigned_values,
32845  1,
32846  MPI_UNSIGNED,
32847  recv_proc,
32848  1,
32849  comm_pt->mpi_comm(),
32850  &status);
32851 
32852  MPI_Wait(&request, MPI_STATUS_IGNORE);
32853 
32854  // Send the actual data
32855  if (send_count_unsigned_values != 0)
32856  {
32857  MPI_Isend(&flat_package_unsigned_send[0],
32858  send_count_unsigned_values,
32859  MPI_UNSIGNED,
32860  send_proc,
32861  2,
32862  comm_pt->mpi_comm(),
32863  &request);
32864  }
32865 
32866  // Receive the actual data
32867  if (receive_count_unsigned_values != 0)
32868  {
32869  flat_package_unsigned_recv.resize(receive_count_unsigned_values);
32870  MPI_Recv(&flat_package_unsigned_recv[0],
32871  receive_count_unsigned_values,
32872  MPI_UNSIGNED,
32873  recv_proc,
32874  2,
32875  comm_pt->mpi_comm(),
32876  &status);
32877  }
32878 
32879  // Wait for sending the data and the other processor
32880  // receives
32881  if (send_count_unsigned_values != 0)
32882  {
32883  MPI_Wait(&request, MPI_STATUS_IGNORE);
32884  }
32885 
32886  //-----------------------------------------------------------
32887  // Then continue with DOUBLE info.
32888  MPI_Isend(&send_count_double_values,
32889  1,
32890  MPI_UNSIGNED,
32891  send_proc,
32892  1,
32893  comm_pt->mpi_comm(),
32894  &request);
32895 
32896  unsigned receive_count_double_values = 0;
32897  MPI_Recv(&receive_count_double_values,
32898  1,
32899  MPI_UNSIGNED,
32900  recv_proc,
32901  1,
32902  comm_pt->mpi_comm(),
32903  &status);
32904 
32905  MPI_Wait(&request, MPI_STATUS_IGNORE);
32906 
32907  // Send the actual data
32908  if (send_count_double_values != 0)
32909  {
32910  MPI_Isend(&flat_package_double_send[0],
32911  send_count_double_values,
32912  MPI_DOUBLE,
32913  send_proc,
32914  2,
32915  comm_pt->mpi_comm(),
32916  &request);
32917  }
32918 
32919  // Receive the actual data
32920  if (receive_count_double_values != 0)
32921  {
32922  flat_package_double_recv.resize(receive_count_double_values);
32923  MPI_Recv(&flat_package_double_recv[0],
32924  receive_count_double_values,
32925  MPI_DOUBLE,
32926  recv_proc,
32927  2,
32928  comm_pt->mpi_comm(),
32929  &status);
32930  }
32931 
32932  // Wait for sending the data and the other processor
32933  // receives
32934  if (send_count_double_values != 0)
32935  {
32936  MPI_Wait(&request, MPI_STATUS_IGNORE);
32937  }
32938 
32939  // ------------------------------------------------------------
32940  // ------------------------------------------------------------
32941  // ------------------------------------------------------------
32942  // Now unpackage the data
32943  // ------------------------------------------------------------
32944  // ------------------------------------------------------------
32945  // ------------------------------------------------------------
32946 
32947  // Storage for the boundaries ids with vertices for non
32948  // deletion
32949  Vector<unsigned> recv_shd_bnd_id_for_non_deletion;
32950 
32951  // Storage for chunk numbers of boundaries with vertices
32952  // for non deletion
32953  Vector<unsigned> recv_chunk_for_non_deletion;
32954 
32955  // The number of vertices for nondeletion in the shared
32956  // boundaries
32957  Vector<unsigned> recv_number_vertices_non_deletion;
32958 
32959  // Vertices marked for nondeletion in shared boundaries
32960  Vector<Vector<Vector<double>>> recv_vertices_for_non_deletion;
32961 
32962  // Counter
32963  j = 0;
32964  for (unsigned i = 0; i < receive_count_unsigned_values; i += 3)
32965  {
32966  // Get the shared boundary id
32967  const unsigned recv_shd_bnd_id = flat_package_unsigned_recv[i];
32968  recv_shd_bnd_id_for_non_deletion.push_back(recv_shd_bnd_id);
32969  // Get the chunk number
32970  const unsigned recv_chunk = flat_package_unsigned_recv[i + 1];
32971  recv_chunk_for_non_deletion.push_back(recv_chunk);
32972  // Get the number of vertices for non deletion
32973  const unsigned recv_num_vertices = flat_package_unsigned_recv[i + 2];
32974  recv_number_vertices_non_deletion.push_back(recv_num_vertices);
32975 
32976  // Create a temporal storage
32977  Vector<Vector<double>> temp_recv_vertices;
32978  // Now get the vertices
32979  for (unsigned h = 0; h < recv_num_vertices; h++)
32980  {
32981  Vector<double> tmp_vertex(2);
32982  tmp_vertex[0] = flat_package_double_recv[j++];
32983  tmp_vertex[1] = flat_package_double_recv[j++];
32984  // Add the vertex to the vector of vertices
32985  temp_recv_vertices.push_back(tmp_vertex);
32986  } // for (h<recv_num_vertices)
32987 
32988  // Add the vertices to the vector of vertices
32989  recv_vertices_for_non_deletion.push_back(temp_recv_vertices);
32990 
32991  } // for(i<receive_count_unsigned_values)
32992 
32993  // ---------------------------------------------------------
32994  // ---------------------------------------------------------
32995  // ---------------------------------------------------------
32996  // Now add the vertices to the data structures to mark them
32997  // as non delete-able
32998  // ---------------------------------------------------------
32999  // ---------------------------------------------------------
33000  // ---------------------------------------------------------
33001 
33002  // Get the number of shd boundaries that have vertices
33003  // marked for non deletion
33004  const unsigned n_recv_shd_bnd_id_for_non_deletion =
33005  recv_shd_bnd_id_for_non_deletion.size();
33006  // loop over the shared boundaries and add the data for non
33007  // deletion
33008  for (unsigned i = 0; i < n_recv_shd_bnd_id_for_non_deletion; i++)
33009  {
33010  // Get the shared boundary id.
33011  const unsigned shd_bnd_id = recv_shd_bnd_id_for_non_deletion[i];
33012  // Get the chunk number
33013  unsigned chunk = recv_chunk_for_non_deletion[i];
33014  // Increase and decrease the chunk number to avoid the
33015  // warning when compiling without PARANOID
33016  chunk++;
33017  chunk--;
33018 
33019  // Get the number of vertices marked for non deletion
33020  const unsigned n_vertices = recv_number_vertices_non_deletion[i];
33021  // Add all the vertices
33022  for (unsigned h = 0; h < n_vertices; h++)
33023  {
33024  // Get the vertex
33025  Vector<double> vertex(2);
33026  vertex[0] = recv_vertices_for_non_deletion[i][h][0];
33027  vertex[1] = recv_vertices_for_non_deletion[i][h][1];
33028  // Add the vertex to the data structure for non
33029  // deletion
33030  // Boundary_chunk_connections_pt[shd_bnd_id][chunk].
33031  // insert(vertex);
33032  Boundary_connections_pt[shd_bnd_id].insert(vertex);
33033 
33034  } // for (h<n_vertices)
33035 
33036  } // for (i<n_recv_shd_bnd_id_for_non_deletion)
33037 
33038  } // if (jproc != my_rank && n_shd_bnd_jproc > 0)
33039 
33040  } // for (jproc < nproc)
33041  }
33042 #endif // #ifdef OOMPH_HAS_MPI
33043 
33044  //=========================================================================
33045  /// After unrefinement and refinement has taken place compute
33046  /// the new vertices numbers of the temporary representation of the
33047  // boundaries to connect.
33048  //=========================================================================
33049  template<class ELEMENT>
33051  Vector<TriangleMeshPolygon*>& tmp_outer_polygons_pt,
33052  Vector<TriangleMeshOpenCurve*>& tmp_open_curves_pt)
33053  {
33054  // Dummy storages
33055  Vector<TriangleMeshPolyLine*> dummy_resume_initial_connection_polyline_pt;
33056  Vector<TriangleMeshPolyLine*> dummy_resume_final_connection_polyline_pt;
33057 
33058  // Clear the storage
33059  dummy_resume_initial_connection_polyline_pt.clear();
33060  dummy_resume_final_connection_polyline_pt.clear();
33061 
33062  // Get the initial shared boundary id (to check whether the
33063  // polylines represent original or shared boundaries)
33064  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
33065 
33066  // ------------------------------------------------------------------
33067  // This seems unnecesary since the outer polygons does not create
33068  // connections with other boundaries (the original ones)
33069  // ------------------------------------------------------------------
33070  // Unnecessary?
33071  // ------------------------------------------------------------------
33072 
33073  // Loop over the temporary outer polygons create the connection
33074  // information of those boundaries marked to be connected at their
33075  // ends
33076 
33077  // ------------------------------------------------------------------
33078  // Temporary outer polygons
33079  // ------------------------------------------------------------------
33080 
33081  // Get the number of outer boundaries (closed boundaries)
33082  const unsigned n_outer_boundaries = tmp_outer_polygons_pt.size();
33083 
33084  // Loop over the outer boundaries
33085  for (unsigned i = 0; i < n_outer_boundaries; i++)
33086  {
33087  // Get a temporary polygon representation
33088  TriangleMeshPolygon* tmp_polygon_pt = tmp_outer_polygons_pt[i];
33089  // Get the number of polylines associated to the current outer
33090  // boundary
33091  const unsigned n_polyline = tmp_polygon_pt->npolyline();
33092  // Loop over the polylines
33093  for (unsigned p = 0; p < n_polyline; p++)
33094  {
33095  // Get a temporary representation of the polyline
33096  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
33097 
33098  // Get the boundary id
33099  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
33100 
33101  // Is the boundary to connect a shared boundary
33102  if (bnd_id < init_shd_bnd_id)
33103  {
33104  // Restore the connections of the current polyline
33105  restore_polyline_connections_helper(
33106  tmp_polyline_pt,
33107  dummy_resume_initial_connection_polyline_pt,
33108  dummy_resume_final_connection_polyline_pt);
33109 
33110  } // if (bnd_id < init_shd_bnd_id)
33111 
33112  } // for (p < n_polyline)
33113 
33114  } // for (i < n_outer_boundaries)
33115 
33116  // ------------------------------------------------------------------
33117  // Unnecessary?
33118  // ------------------------------------------------------------------
33119 
33120  // ------------------------------------------------------------------
33121  // Temporary open boundaries (nonclosed internal boundaries)
33122  // ------------------------------------------------------------------
33123 
33124  // Get the number of internal boundaries (open boundaries)
33125  const unsigned n_open_boundaries = tmp_open_curves_pt.size();
33126 
33127  // Loop over the internal open boundaries
33128  for (unsigned i = 0; i < n_open_boundaries; i++)
33129  {
33130  // Get a temporary representation for the open curve
33131  TriangleMeshOpenCurve* tmp_open_curve_pt = tmp_open_curves_pt[i];
33132 
33133  // Get the number of curve sections associated to the current
33134  // internal open boundary
33135  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
33136 
33137  // Loop over the curve section
33138  for (unsigned p = 0; p < n_curve_section; p++)
33139  {
33140  // Get a temporary representation of the curve section
33141  // (polyline)
33142  TriangleMeshPolyLine* tmp_polyline_pt =
33143  tmp_open_curve_pt->polyline_pt(p);
33144 
33145  // Get the boundary id
33146  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
33147 
33148  // Is the boundary to connect a shared boundary
33149  if (bnd_id < init_shd_bnd_id)
33150  {
33151  // Restore the connections of the current polyline
33152  restore_polyline_connections_helper(
33153  tmp_polyline_pt,
33154  dummy_resume_initial_connection_polyline_pt,
33155  dummy_resume_final_connection_polyline_pt);
33156 
33157  } // if (bnd_id < init_shd_bnd_id)
33158 
33159  } // for (p < n_curve_section)
33160 
33161  } // for (i < n_open_boundaries)
33162  }
33163 
33164  //=========================================================================
33165  /// After unrefinement and refinement has taken place compute
33166  /// the new vertices numbers of the boundaries to connect (in a
33167  /// distributed scheme it may be possible that the destination
33168  /// boundary does no longer exist, therefore the connection is
33169  /// suspended. It is not permanently deleted because if load balance
33170  /// takes place it may be possible that the boundary to connect be
33171  /// part of the new domain representation, so the connection would
33172  /// exist)
33173  //=========================================================================
33174  template<class ELEMENT>
33176  Vector<TriangleMeshPolyLine*>& resume_initial_connection_polyline_pt,
33177  Vector<TriangleMeshPolyLine*>& resume_final_connection_polyline_pt)
33178  {
33179  // Clear the storage
33180  resume_initial_connection_polyline_pt.clear();
33181  resume_final_connection_polyline_pt.clear();
33182 
33183  // Loop over the boundaries in the domain (outer, internal -- closed
33184  // and open) and restore the connection information of those
33185  // boundaries marked to be connected at their ends
33186 
33187  // ------------------------------------------------------------------
33188  // Outer boundaries
33189  // ------------------------------------------------------------------
33190 
33191  // Get the number of outer boundaries (closed boundaries)
33192  const unsigned n_outer_boundaries = this->Outer_boundary_pt.size();
33193 
33194  // Loop over the outer boundaries
33195  for (unsigned i = 0; i < n_outer_boundaries; i++)
33196  {
33197  // Get a temporary polygon representation
33198  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
33199  // Get the number of polylines associated to the current outer
33200  // boundary
33201  const unsigned n_polyline = tmp_polygon_pt->npolyline();
33202  // Loop over the polylines
33203  for (unsigned p = 0; p < n_polyline; p++)
33204  {
33205  // Get a temporary representation of the polyline
33206  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
33207 
33208  // Restore the connections of the current polyline
33209  restore_polyline_connections_helper(
33210  tmp_polyline_pt,
33211  resume_initial_connection_polyline_pt,
33212  resume_final_connection_polyline_pt);
33213 
33214  } // for (p < n_polyline)
33215 
33216  } // for (i < n_outer_boundaries)
33217 
33218  // ------------------------------------------------------------------
33219  // Internal boundaries
33220  // ------------------------------------------------------------------
33221 
33222  // Get the number of internal boundaries (closed boundaries)
33223  const unsigned n_internal_boundaries = this->Internal_polygon_pt.size();
33224 
33225  // Loop over the internal boundaries
33226  for (unsigned i = 0; i < n_internal_boundaries; i++)
33227  {
33228  // Get a temporary polygon representation
33229  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
33230  // Get the number of polylines associated to the current internal
33231  // boundary
33232  const unsigned n_polyline = tmp_polygon_pt->npolyline();
33233  // Loop over the polylines
33234  for (unsigned p = 0; p < n_polyline; p++)
33235  {
33236  // Get a temporary representation of the polyline
33237  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
33238 
33239  // Restore the connections of the current polyline
33240  restore_polyline_connections_helper(
33241  tmp_polyline_pt,
33242  resume_initial_connection_polyline_pt,
33243  resume_final_connection_polyline_pt);
33244 
33245  } // for (p < n_polyline)
33246 
33247  } // for (i < n_internal_boundaries)
33248 
33249  // ------------------------------------------------------------------
33250  // Open boundaries (nonclosed internal boundaries)
33251  // ------------------------------------------------------------------
33252 
33253  // Get the number of internal boundaries (open boundaries)
33254  const unsigned n_open_boundaries = this->Internal_open_curve_pt.size();
33255 
33256  // Loop over the internal open boundaries
33257  for (unsigned i = 0; i < n_open_boundaries; i++)
33258  {
33259  // Get a temporary representation for the open curve
33260  TriangleMeshOpenCurve* tmp_open_curve_pt =
33261  this->Internal_open_curve_pt[i];
33262 
33263  // Get the number of curve sections associated to the current
33264  // internal open boundary
33265  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
33266 
33267  // Loop over the curve section
33268  for (unsigned p = 0; p < n_curve_section; p++)
33269  {
33270  // Get a temporary representation of the curve section
33271  // (polyline)
33272  TriangleMeshPolyLine* tmp_polyline_pt =
33273  tmp_open_curve_pt->polyline_pt(p);
33274 
33275  // Restore the connections of the current polyline
33276  restore_polyline_connections_helper(
33277  tmp_polyline_pt,
33278  resume_initial_connection_polyline_pt,
33279  resume_final_connection_polyline_pt);
33280 
33281  } // for (p < n_curve_section)
33282 
33283  } // for (i < n_open_boundaries)
33284  }
33285 
33286  //=========================================================================
33287  /// Restore the connections of the specific polyline
33288  /// The vertices numbering on the destination boundaries may have
33289  /// change because of (un)refinement in the destination boundaries.
33290  /// Also deals with connection that do not longer exist because the
33291  /// destination boundary does no longer exist because of the distribution
33292  /// process
33293  //=========================================================================
33294  template<class ELEMENT>
33296  TriangleMeshPolyLine* polyline_pt,
33297  Vector<TriangleMeshPolyLine*>& resume_initial_connection_polyline_pt,
33298  Vector<TriangleMeshPolyLine*>& resume_final_connection_polyline_pt)
33299  {
33300  // If the polyline is connected at any of its ends compute the new
33301  // vertex number on the destination boundary
33302 
33303  // ------------------------------------------------------------------
33304  // Is the initial vertex connected?
33305  if (polyline_pt->is_initial_vertex_connected())
33306  {
33307  // The pointer to the boundary to connect
33308  TriangleMeshPolyLine* poly_to_connect_pt = 0;
33309 
33310  // Get the boundary id of the destination/connected boundary
33311  const unsigned dst_bnd_id_initial =
33312  polyline_pt->initial_vertex_connected_bnd_id();
33313 
33314  // Get the initial vertex on the current boundary
33315  Vector<double> src_vertex_coordinates_initial =
33316  polyline_pt->vertex_coordinate(0);
33317 
33318 #ifdef PARANOID
33319  // Is the mesh distributed?
33320 #ifdef OOMPH_HAS_MPI
33321  if (this->is_mesh_distributed())
33322  {
33323  // Get the initial shared boundary id
33324  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
33325  // Is the boundary to connect a shared boundary
33326  if (dst_bnd_id_initial >= init_shd_bnd_id)
33327  {
33328  // Get the current polyline original boundary id
33329  const unsigned bnd_id = polyline_pt->boundary_id();
33330  std::ostringstream error_message;
33331  error_message
33332  << "INITIAL VERTEX CONNECTION\n"
33333  << "The current original boundary is trying to connect to a\n"
33334  << "shared boundary, this is not allowed. In this case the\n"
33335  << "shared boundary should be the one that connects with the\n"
33336  << "original boundary\n"
33337  << "The current original boundary (" << bnd_id << ") is marked\n"
33338  << "to have a connection at the\nINITIAL vertex ("
33339  << src_vertex_coordinates_initial[0] << ","
33340  << src_vertex_coordinates_initial[1] << ")\n"
33341  << "with the shared boundary (" << dst_bnd_id_initial << ")\n"
33342  << "This is the list of vertices on the shared destination "
33343  "boundary\n";
33344  // Get the pointer to the associated polyline by using the
33345  // boundary id
33346  TriangleMeshPolyLine* dst_polyline =
33347  this->boundary_polyline_pt(dst_bnd_id_initial);
33348  // The number of vertices on the destination boundary
33349  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33350  // Loop over the vertices print them
33351  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33352  {
33353  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33354  error_message << "Vertex#(i): (" << current_vertex[0] << ", "
33355  << current_vertex[1] << ")\n";
33356  }
33357  throw OomphLibError(
33358  error_message.str(),
33359  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33360  OOMPH_EXCEPTION_LOCATION);
33361  } // if (dst_bnd_id_initial >= init_shd_bnd_id)
33362 
33363  } // if (this->is_mesh_distributed())
33364 #endif // #ifdef OOMPH_HAS_MPI
33365 
33366 #endif // #ifdef PARANOID
33367 
33368  // Flag to indicate if the vertex was found on the destination
33369  // boundary
33370  bool found_vertex_on_dst_boundary_initial = false;
33371 
33372  // Flag that stores the chunk number to connect (only used in
33373  // distributed meshes)
33374  unsigned sub_poly_to_connect = 0;
33375 
33376  // Store the vertex number on the destination boundary
33377  unsigned n_vertex_connection_initial = 0;
33378 
33379  // Flags only used in a distributed mesh
33380  // ----------------------------------------
33381  // Flag to indicate we are trying to connect to an split boundary
33382  bool connecting_to_an_split_boundary = false;
33383 
33384  // Flag to indicate we are trying to connecto to an internal
33385  // boundary that is overlaped by a shared boundary)
33386  bool connecting_to_an_overlaped_boundary = false;
33387 
33388 #ifdef OOMPH_HAS_MPI
33389  if (this->is_mesh_distributed())
33390  {
33391  // We can only connect to an original boundary, check if the
33392  // boundary was splitted during the distribution process to
33393  // consider all the chunks (sub-polylines) of the boundary
33394  if (this->boundary_was_splitted(dst_bnd_id_initial))
33395  {
33396  connecting_to_an_split_boundary = true;
33397  } // if (this->boundary_was_splitted(dst_bnd_id_initial))
33398 
33399  // Check if the destination boundary, or any of its chunks is
33400  // marked to be overlapped by a shared boundary, if that is the
33401  // case we can only connect to the chunks that are not
33402  // overlapped by shared boundaries (the shared boundaries are in
33403  // charge of generating the connections with original boundaries
33404  // and with themselves)
33405  if (connecting_to_an_split_boundary)
33406  {
33407  // Get the number of chucks that represent the destination
33408  // boundary
33409  const unsigned n_sub_poly =
33410  this->nboundary_subpolylines(dst_bnd_id_initial);
33411  // Now loop over the chunks of the destination boundary and if
33412  // any of them is marked to be overlaped by a shared boundary
33413  // then set the flag and break the loop
33414  for (unsigned ii = 0; ii < n_sub_poly; ii++)
33415  {
33416  if (this->boundary_marked_as_shared_boundary(dst_bnd_id_initial,
33417  ii))
33418  {
33419  // Mark the boundary as being overlaped by a shared
33420  // boundary
33421  connecting_to_an_overlaped_boundary = true;
33422  // Break, no need to look for more overlapings
33423  break;
33424  } // if (boundary_marked_as_shared_boundary(...))
33425  } // for (ii < n_sub_poly)
33426  } // if (connecting_to_an_split_boundary)
33427  else
33428  {
33429  // If not connecting to an split boundary then check if the
33430  // whole destination boundary is overlaped by an internal
33431  // boundary
33432  if (this->boundary_marked_as_shared_boundary(dst_bnd_id_initial, 0))
33433  {
33434  // Mark the boundary as being overlaped by a shared boundary
33435  connecting_to_an_overlaped_boundary = true;
33436  } // if (boundary_marked_as_shared_boundary(...))
33437  } // else if (connecting_to_an_split_boundary)
33438 
33439  } // if (this->is_mesh_distributed())
33440 
33441 #endif // #ifdef OOMPH_HAS_MPI
33442 
33443  // If we are connecting neither to an split boundary nor an
33444  // overlaped boundary then get the pointer to the original
33445  // boundary
33446  if (!(connecting_to_an_split_boundary ||
33447  connecting_to_an_overlaped_boundary))
33448  {
33449  // Get the polyline pointer representing the destination
33450  // boundary
33451  poly_to_connect_pt = this->boundary_polyline_pt(dst_bnd_id_initial);
33452  } // else if (NOT split, NOT overlaped)
33453 
33454  // Now look for the vertex number on the destination boundary(ies)
33455  // -- in case that the boundary was split ---
33456 
33457  // Do not check for same orientation, that was previously worked
33458  // by interchanging the connections boundaries (if necessary)
33459 
33460  // If the boundary was not split then ...
33461  if (!connecting_to_an_split_boundary)
33462  {
33463  // ... check if the boundary is marked to be overlaped by
33464  // a shared boundary
33465  if (!connecting_to_an_overlaped_boundary)
33466  {
33467  // If that is not the case then we can safely look for the
33468  // vertex number on the destination boundary
33469  found_vertex_on_dst_boundary_initial =
33470  this->get_connected_vertex_number_on_destination_polyline(
33471  poly_to_connect_pt,
33472  src_vertex_coordinates_initial,
33473  n_vertex_connection_initial);
33474 
33475  } // if (!connecting_to_an_overlaped_boundary)
33476  else
33477  {
33478  // If the whole boundary is marked to be overlaped by a shared
33479  // boundary then do nothing, the shared boundaries are already
33480  // in charge of performing the connection (it will be required
33481  // to disabled the connection) with the original boundary
33482 
33483  } // else if (!connecting_to_an_overlaped_boundary)
33484 
33485  } // if (!connecting_to_an_split_boundary)
33486 #ifdef OOMPH_HAS_MPI
33487  else
33488  {
33489  // If the boundary was split then we need to look for the vertex
33490  // in the sub-polylines
33491 
33492  // Get the sub-polylines vector
33493  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
33494  this->boundary_subpolylines(dst_bnd_id_initial);
33495 
33496  // Get the number of sub-polylines
33497  const unsigned nsub_poly = tmp_vector_subpolylines.size();
33498 #ifdef PARANOID
33499  if (nsub_poly <= 1)
33500  {
33501  std::ostringstream error_message;
33502  error_message << "The boundary (" << dst_bnd_id_initial << ") was "
33503  << "marked to be splitted but\n"
33504  << "there are only (" << nsub_poly << ") polylines to "
33505  << "represent it.\n";
33506  throw OomphLibError(
33507  error_message.str(),
33508  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33509  OOMPH_EXCEPTION_LOCATION);
33510  } // if (nsub_poly <= 1)
33511 #endif
33512  // We need to check if the boundary is marked to be overlaped by
33513  // a shared boundary, if that is the case we need to check for
33514  // each indivual subpolyline, and for those overlaped by a
33515  // shared polyline do nothing, the shared polylines have already
33516  // deal with these connections
33517 
33518  // ... check if the boundary is marked to be overlaped by
33519  // a shared boundary
33520  if (!connecting_to_an_overlaped_boundary)
33521  {
33522  // The boundary is not overlapped by shared boundaries, we can
33523  // work without checking the subpolylines individually (non of
33524  // them are overlapped by a shared boundary)
33525 
33526  // Look for the vertex number to connect on each of the
33527  // subpolyines
33528  for (unsigned isub = 0; isub < nsub_poly; isub++)
33529  {
33530  // Assign the pointer to the sub-polyline
33531  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33532  // Search for the vertex in the current sub-polyline
33533  found_vertex_on_dst_boundary_initial =
33534  this->get_connected_vertex_number_on_destination_polyline(
33535  poly_to_connect_pt,
33536  src_vertex_coordinates_initial,
33537  n_vertex_connection_initial);
33538 
33539  // If we have found the vertex to connect then break the
33540  // loop
33541  if (found_vertex_on_dst_boundary_initial)
33542  {
33543  // But first save the subpoly number (chunk), that will be
33544  // used to perform the connection
33545  sub_poly_to_connect = isub;
33546  break;
33547  } // if (found_vertex_on_dst_boundary_initial)
33548 
33549  } // for (isub < nsub_poly)
33550 
33551  } // if (!connecting_to_an_overlaped_boundary)
33552  else
33553  {
33554  // If connecting to an overlapped boundary then we ignore the
33555  // subpolylines overlapped by shared boundaries and only look
33556  // on the sub-polylines that are not marked as being overlaped
33557  // by shared boundaries
33558 
33559  // Look for the vertex number to connect on each of the
33560  // subpolyines
33561  for (unsigned isub = 0; isub < nsub_poly; isub++)
33562  {
33563  // Only work with those sub-polylines that are not overlaped
33564  // by shared boundaries
33565  if (!this->boundary_marked_as_shared_boundary(dst_bnd_id_initial,
33566  isub))
33567  {
33568  // Assign the pointer to the sub-polyline
33569  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33570 
33571  // Search for the vertex in the current sub-polyline
33572  found_vertex_on_dst_boundary_initial =
33573  this->get_connected_vertex_number_on_destination_polyline(
33574  poly_to_connect_pt,
33575  src_vertex_coordinates_initial,
33576  n_vertex_connection_initial);
33577 
33578  // Was the vertex found?
33579  if (found_vertex_on_dst_boundary_initial)
33580  {
33581  // But first save the subpoly number (chunk), that will
33582  // be used to perform the connection
33583  sub_poly_to_connect = isub;
33584  break;
33585  } // if (found_vertex_on_dst_boundary_initial)
33586 
33587  } // if (not overlaped by shared boundary)
33588 
33589  } // for (isub < nsub_poly)
33590 
33591  } // else if (!connecting_to_an_overlaped_boundary)
33592 
33593  } // else if (!connecting_to_an_split_boundary)
33594 #endif // #ifdef OOMPH_HAS_MPI
33595 
33596  // If not found it may be that the connection information is
33597  // inverted
33598  if (!found_vertex_on_dst_boundary_initial)
33599  {
33600  // Is the mesh distributed?
33601 #ifdef OOMPH_HAS_MPI
33602  if (this->is_mesh_distributed())
33603  {
33604  // If the mesh is distributed and the vertex number was not
33605  // found, that means that the boundary (or vertex) to connect
33606  // in the destination boundary is not in the current
33607  // processor. In that case suspend the connection
33608  polyline_pt->suspend_initial_vertex_connected();
33609  // Add the polyline to the vector of polylines whose
33610  // connection will be resumed at the end of the adaptation
33611  // process
33612  resume_initial_connection_polyline_pt.push_back(polyline_pt);
33613  // The shared boundaries are marked to connect to the initial
33614  // vertex of the polyline (remember that a shared boundary
33615  // stops adding nodes when it finds a node on an original
33616  // boundary) -- The initial vertex is now a base node
33617  }
33618  else
33619 #endif // #ifdef OOMPH_HAS_MPI
33620  {
33621 #ifdef PARANOID
33622  // If not found then there is a problem with the vertices
33623  // Get the associated boundary id of the current polyline
33624  const unsigned bnd_id = polyline_pt->boundary_id();
33625  std::ostringstream error_message;
33626  error_message
33627  << "INITIAL VERTEX CONNECTION\n"
33628  << "It was not possible to find the associated "
33629  << "vertex number on the destination boundary\n"
33630  << "The current boundary (" << bnd_id << ") is marked to have"
33631  << "a connection at the\nINITIAL vertex ("
33632  << src_vertex_coordinates_initial[0] << ","
33633  << src_vertex_coordinates_initial[1] << ")\n"
33634  << "with boundary (" << dst_bnd_id_initial << ")\n"
33635  << "This is the list of vertices on the destination boundary\n";
33636  // Get the pointer to the associated polyline by using the
33637  // boundary id
33638  TriangleMeshPolyLine* dst_polyline =
33639  this->boundary_polyline_pt(dst_bnd_id_initial);
33640  // The number of vertices on the destination boundary
33641  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33642  // Loop over the vertices print them
33643  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33644  {
33645  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33646  error_message << "Vertex#(i): (" << current_vertex[0] << ", "
33647  << current_vertex[1] << ")\n";
33648  }
33649  throw OomphLibError(
33650  error_message.str(),
33651  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33652  OOMPH_EXCEPTION_LOCATION);
33653 #endif
33654 
33655  } // else if (this->is_mesh_distributed())
33656 
33657  } // if (!found_vertex_on_dst_boundary_initial)
33658  else
33659  {
33660  // Set the vertex number on the destination boundary
33661  polyline_pt->initial_vertex_connected_n_vertex() =
33662  n_vertex_connection_initial;
33663 
33664  // Set the chunk number on the destination boundary
33665  polyline_pt->initial_vertex_connected_n_chunk() = sub_poly_to_connect;
33666 
33667  } // else if (!found_vertex_on_dst_boundary_initial)
33668 
33669  } // if (polyline_pt->is_initial_vertex_connected())
33670 
33671  // ------------------------------------------------------------------
33672  // Is the final vertex connected?
33673  if (polyline_pt->is_final_vertex_connected())
33674  {
33675  // The pointer to the boundary to connect
33676  TriangleMeshPolyLine* poly_to_connect_pt = 0;
33677 
33678  // Get the boundary id of the destination/connected boundary
33679  const unsigned dst_bnd_id_final =
33680  polyline_pt->final_vertex_connected_bnd_id();
33681 
33682  // Get the final vertex on the current boundary
33683  const unsigned tmp_n_vertices = polyline_pt->nvertex();
33684  Vector<double> src_vertex_coordinates_final =
33685  polyline_pt->vertex_coordinate(tmp_n_vertices - 1);
33686 
33687 
33688 #ifdef PARANOID
33689  // Is the mesh distributed?
33690 #ifdef OOMPH_HAS_MPI
33691  if (this->is_mesh_distributed())
33692  {
33693  // Get the initial shared boundary id
33694  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
33695  // Is the boundary to connect a shared boundary
33696  if (dst_bnd_id_final >= init_shd_bnd_id)
33697  {
33698  // Get the current polyline original boundary id
33699  const unsigned bnd_id = polyline_pt->boundary_id();
33700  std::ostringstream error_message;
33701  error_message
33702  << "FINAL VERTEX CONNECTION\n"
33703  << "The current original boundary is trying to connect to a\n"
33704  << "shared boundary, this is not allowed. In this case the\n"
33705  << "shared boundary should be the one that connects with the\n"
33706  << "original boundary\n"
33707  << "The current boundary (" << bnd_id << ") is marked to have "
33708  << "a connection at the\nFINAL vertex ("
33709  << src_vertex_coordinates_final[0] << ","
33710  << src_vertex_coordinates_final[1] << ")\n"
33711  << "with boundary (" << dst_bnd_id_final << ")\n"
33712  << "This is the list of vertices on the destination boundary\n";
33713  // Get the pointer to the associated polyline by using the
33714  // boundary id
33715  TriangleMeshPolyLine* dst_polyline =
33716  this->boundary_polyline_pt(dst_bnd_id_final);
33717  // The number of vertices on the destination boundary
33718  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33719  // Loop over the vertices print them
33720  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33721  {
33722  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33723  error_message << "Vertex#(" << i << "): (" << current_vertex[0]
33724  << ", " << current_vertex[1] << ")\n";
33725  }
33726  throw OomphLibError(
33727  error_message.str(),
33728  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33729  OOMPH_EXCEPTION_LOCATION);
33730  } // if (dst_bnd_id_initial >= init_shd_bnd_id)
33731 
33732  } // if (this->is_mesh_distributed())
33733 #endif // #ifdef OOMPH_HAS_MPI
33734 
33735 #endif // #ifdef PARANOID
33736 
33737  // Flag to indicate if the vertex was found on the destination
33738  // boundary
33739  bool found_vertex_on_dst_boundary_final = false;
33740 
33741  // Flag that stores the chunk number to connect (only used in
33742  // distributed meshes)
33743  unsigned sub_poly_to_connect = 0;
33744 
33745  // Store the vertex number on the destination boundary
33746  unsigned n_vertex_connection_final = 0;
33747 
33748  // Flags only used in a distributed mesh
33749  // ----------------------------------------
33750  // Flag to indicate we are trying to connect to an split boundary
33751  bool connecting_to_an_split_boundary = false;
33752 
33753  // Flag to indicate we are trying to connecto to an internal
33754  // boundary that is overlaped by a shared boundary)
33755  bool connecting_to_an_overlaped_boundary = false;
33756 
33757 #ifdef OOMPH_HAS_MPI
33758  if (this->is_mesh_distributed())
33759  {
33760  // We can only connect to an original boundary, check if the
33761  // boundary was splitted during the distribution process to
33762  // consider all the chunks (sub-polylines) of the boundary
33763  if (this->boundary_was_splitted(dst_bnd_id_final))
33764  {
33765  connecting_to_an_split_boundary = true;
33766  } // if (this->boundary_was_splitted(dst_bnd_id_final))
33767 
33768  // Check if the destination boundary, or any of its chunks is
33769  // marked to be overlapped by a shared boundary, if that is the
33770  // case we can only connect to the chunks that are not
33771  // overlapped by shared boundaries (the shared boundaries are in
33772  // charge of generating the connections with original boundaries
33773  // and with themselves)
33774  if (connecting_to_an_split_boundary)
33775  {
33776  // Get the number of chucks that represent the destination
33777  // boundary
33778  const unsigned n_sub_poly =
33779  this->nboundary_subpolylines(dst_bnd_id_final);
33780  // Now loop over the chunks of the destination boundary and if
33781  // any of them is marked to be overlaped by a shared boundary
33782  // then set the flag and break the loop
33783  for (unsigned ii = 0; ii < n_sub_poly; ii++)
33784  {
33785  if (this->boundary_marked_as_shared_boundary(dst_bnd_id_final, ii))
33786  {
33787  // Mark the boundary as being overlaped by a shared
33788  // boundary
33789  connecting_to_an_overlaped_boundary = true;
33790  // Break, no need to look for more overlapings
33791  break;
33792  } // if (boundary_marked_as_shared_boundary(...))
33793  } // for (ii < n_sub_poly)
33794  } // if (connecting_to_an_split_boundary)
33795  else
33796  {
33797  // If not connecting to an split boundary then check if the
33798  // whole destination boundary is overlaped by an internal
33799  // boundary
33800  if (this->boundary_marked_as_shared_boundary(dst_bnd_id_final, 0))
33801  {
33802  // Mark the boundary as being overlaped by a shared boundary
33803  connecting_to_an_overlaped_boundary = true;
33804  } // if (boundary_marked_as_shared_boundary(...))
33805  } // else if (connecting_to_an_split_boundary)
33806 
33807  } // if (this->is_mesh_distributed())
33808 
33809 #endif // #ifdef OOMPH_HAS_MPI
33810 
33811  // If we are connecting neither to an split boundary nor an
33812  // overlaped boundary then get the pointer to the original
33813  // boundary
33814  if (!(connecting_to_an_split_boundary ||
33815  connecting_to_an_overlaped_boundary))
33816  {
33817  // Get the polyline pointer representing the destination
33818  // boundary
33819  poly_to_connect_pt = this->boundary_polyline_pt(dst_bnd_id_final);
33820  } // else if (NOT split, NOT overlaped)
33821 
33822  // Now look for the vertex number on the destination boundary(ies)
33823  // -- in case that the boundary was split ---
33824 
33825  // Do not check for same orientation, that was previously worked
33826  // by interchanging the connections boundaries (if necessary)
33827 
33828  // If the boundary was not split then ...
33829  if (!connecting_to_an_split_boundary)
33830  {
33831  // ... check if the boundary is marked to be overlaped by
33832  // a shared boundary
33833  if (!connecting_to_an_overlaped_boundary)
33834  {
33835  // If that is not the case then we can safely look for the
33836  // vertex number on the destination boundary
33837  found_vertex_on_dst_boundary_final =
33838  this->get_connected_vertex_number_on_destination_polyline(
33839  poly_to_connect_pt,
33840  src_vertex_coordinates_final,
33841  n_vertex_connection_final);
33842 
33843  } // if (!connecting_to_an_overlaped_boundary)
33844  else
33845  {
33846  // If the whole boundary is marked to be overlaped by a shared
33847  // boundary then do nothing, the shared boundaries are already
33848  // in charge of performing the connection (it will be required
33849  // to disabled the connection) with the original boundary
33850 
33851  } // else if (!connecting_to_an_overlaped_boundary)
33852 
33853  } // if (!connecting_to_an_split_boundary)
33854 #ifdef OOMPH_HAS_MPI
33855  else
33856  {
33857  // If the boundary was split then we need to look for the vertex
33858  // in the sub-polylines
33859 
33860  // Get the sub-polylines vector
33861  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
33862  this->boundary_subpolylines(dst_bnd_id_final);
33863 
33864  // Get the number of sub-polylines
33865  const unsigned nsub_poly = tmp_vector_subpolylines.size();
33866 #ifdef PARANOID
33867  if (nsub_poly <= 1)
33868  {
33869  std::ostringstream error_message;
33870  error_message << "The boundary (" << dst_bnd_id_final << ") was "
33871  << "marked to be splitted but\n"
33872  << "there are only (" << nsub_poly << ") polylines to "
33873  << "represent it.\n";
33874  throw OomphLibError(
33875  error_message.str(),
33876  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33877  OOMPH_EXCEPTION_LOCATION);
33878  } // if (nsub_poly <= 1)
33879 #endif
33880  // We need to check if the boundary is marked to be overlaped by
33881  // a shared boundary, if that is the case we need to check for
33882  // each indivual subpolyline, and for those overlaped by a
33883  // shared polyline do nothing, the shared polylines have already
33884  // deal with these connections
33885 
33886  // ... check if the boundary is marked to be overlaped by
33887  // a shared boundary
33888  if (!connecting_to_an_overlaped_boundary)
33889  {
33890  // The boundary is not overlapped by shared boundaries, we can
33891  // work without checking the subpolylines individually (non of
33892  // them are overlapped by a shared boundary)
33893 
33894  // Look for the vertex number to connect on each of the
33895  // subpolyines
33896  for (unsigned isub = 0; isub < nsub_poly; isub++)
33897  {
33898  // Assign the pointer to the sub-polyline
33899  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33900  // Search for the vertex in the current sub-polyline
33901  found_vertex_on_dst_boundary_final =
33902  this->get_connected_vertex_number_on_destination_polyline(
33903  poly_to_connect_pt,
33904  src_vertex_coordinates_final,
33905  n_vertex_connection_final);
33906 
33907  // If we have found the vertex to connect then break the
33908  // loop
33909  if (found_vertex_on_dst_boundary_final)
33910  {
33911  // But first save the subpoly number (chunk), that will be
33912  // used to perform the connection
33913  sub_poly_to_connect = isub;
33914  break;
33915  } // if (found_vertex_on_dst_boundary_initial)
33916 
33917  } // for (isub < nsub_poly)
33918 
33919  } // if (!connecting_to_an_overlaped_boundary)
33920  else
33921  {
33922  // If connecting to an overlapped boundary then we ignore the
33923  // subpolylines overlapped by shared boundaries and only look
33924  // on the sub-polylines that are not marked as being overlaped
33925  // by shared boundaries
33926 
33927  // Look for the vertex number to connect on each of the
33928  // subpolyines
33929  for (unsigned isub = 0; isub < nsub_poly; isub++)
33930  {
33931  // Only work with those sub-polylines that are not overlaped
33932  // by shared boundaries
33933  if (!this->boundary_marked_as_shared_boundary(dst_bnd_id_final,
33934  isub))
33935  {
33936  // Assign the pointer to the sub-polyline
33937  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33938 
33939  // Search for the vertex in the current sub-polyline
33940  found_vertex_on_dst_boundary_final =
33941  this->get_connected_vertex_number_on_destination_polyline(
33942  poly_to_connect_pt,
33943  src_vertex_coordinates_final,
33944  n_vertex_connection_final);
33945 
33946  // Was the vertex found?
33947  if (found_vertex_on_dst_boundary_final)
33948  {
33949  // But first save the subpoly number (chunk), that will
33950  // be used to perform the connection
33951  sub_poly_to_connect = isub;
33952  break;
33953  } // if (found_vertex_on_dst_boundary_final)
33954 
33955  } // if (not overlaped by shared boundary)
33956 
33957  } // for (isub < nsub_poly)
33958 
33959  } // else if (!connecting_to_an_overlaped_boundary)
33960 
33961  } // else if (!connecting_to_an_split_boundary)
33962 #endif // #ifdef OOMPH_HAS_MPI
33963 
33964  // If not found it may be that the connection information is
33965  // inverted
33966  if (!found_vertex_on_dst_boundary_final)
33967  {
33968  // Is the mesh distributed?
33969 #ifdef OOMPH_HAS_MPI
33970  if (this->is_mesh_distributed())
33971  {
33972  // If the mesh is distributed and the vertex number was not
33973  // found, that means that the boundary (or vertex) to connect
33974  // in the destination boundary is not in the current
33975  // processor. In that suspend the connection
33976  polyline_pt->suspend_final_vertex_connected();
33977  // Add the polyline to the vector of polylines whose
33978  // connection will be resumed at the end of the adaptation
33979  // process
33980  resume_final_connection_polyline_pt.push_back(polyline_pt);
33981  // The shared boundaries are marked to connect to the final
33982  // vertex of the polyline (remember that a shared boundary
33983  // stops adding nodes when it finds a node on an original
33984  // boundary) -- The final vertex is now a base node
33985  } // if (this->is_mesh_distributed())
33986  else
33987 #endif // #ifdef OOMPH_HAS_MPI
33988  {
33989 #ifdef PARANOID
33990  // If not found then there is a problem with the vertices
33991  // Get the associated boundary id of the current polyline
33992  const unsigned bnd_id = polyline_pt->boundary_id();
33993  std::ostringstream error_message;
33994  error_message
33995  << "FINAL VERTEX CONNECTION\n"
33996  << "It was not possible to find the associated "
33997  << "vertex number on the destination boundary\n"
33998  << "The current boundary (" << bnd_id << ") is marked to have "
33999  << "a connection at the\nFINAL vertex ("
34000  << src_vertex_coordinates_final[0] << ","
34001  << src_vertex_coordinates_final[1] << ")\n"
34002  << "with boundary (" << dst_bnd_id_final << ")\n"
34003  << "This is the list of vertices on the destination boundary\n";
34004  // Get the pointer to the associated polyline by using the
34005  // boundary id
34006  TriangleMeshPolyLine* dst_polyline =
34007  this->boundary_polyline_pt(dst_bnd_id_final);
34008  // The number of vertices on the destination boundary
34009  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
34010  // Loop over the vertices print them
34011  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
34012  {
34013  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
34014  error_message << "Vertex#(" << i << "): (" << current_vertex[0]
34015  << ", " << current_vertex[1] << ")\n";
34016  }
34017  throw OomphLibError(
34018  error_message.str(),
34019  "RefineableTriangleMesh::restore_polyline_connections_helper()",
34020  OOMPH_EXCEPTION_LOCATION);
34021 #endif
34022  } // else if (this->is_mesh_distributed())
34023 
34024  } // if (!found_vertex_on_dst_boundary_final)
34025  else
34026  {
34027  // Set the vertex number on the destination boundary
34028  polyline_pt->final_vertex_connected_n_vertex() =
34029  n_vertex_connection_final;
34030 
34031  // Set the chunk number on the destination boundary
34032  polyline_pt->final_vertex_connected_n_chunk() = sub_poly_to_connect;
34033 
34034  } // else if (!found_vertex_on_dst_boundary_final)
34035 
34036  } // if (polyline_pt->is_final_vertex_connected())
34037  }
34038 
34039  //=========================================================================
34040  /// Resume the boundary connections that may have been
34041  /// suspended because the destination boundary is no part of the
34042  /// domain. The connections are no permanently suspended because if
34043  /// load balance takes place the destination boundary may be part of
34044  /// the new domain representation therefore the connection would
34045  /// exist
34046  //=========================================================================
34047  template<class ELEMENT>
34049  Vector<TriangleMeshPolyLine*>& resume_initial_connection_polyline_pt,
34050  Vector<TriangleMeshPolyLine*>& resume_final_connection_polyline_pt)
34051  {
34052  // Get the number of polylines that require to resume the connection
34053  // at the initial vertex
34054  const unsigned n_initial_poly =
34055  resume_initial_connection_polyline_pt.size();
34056  // Loop over the polylines that require to resume the connection
34057  // at the initial vertex
34058  for (unsigned p = 0; p < n_initial_poly; p++)
34059  {
34060  // Get the polyline
34061  TriangleMeshPolyLine* tmp_poly_pt =
34062  resume_initial_connection_polyline_pt[p];
34063  // Resume the connection with the initial vertex
34064  tmp_poly_pt->resume_initial_vertex_connected();
34065  } // for (p < n_initial_poly)
34066 
34067  // Get the number of polylines that require to resume the connection
34068  // at the final vertex
34069  const unsigned n_final_poly = resume_final_connection_polyline_pt.size();
34070  // Loop over the polylines that require to resume the connection at
34071  // the final vertex
34072  for (unsigned p = 0; p < n_final_poly; p++)
34073  {
34074  // Get the polyline
34075  TriangleMeshPolyLine* tmp_poly_pt =
34076  resume_final_connection_polyline_pt[p];
34077  // Resume the connection with the final vertex
34078  tmp_poly_pt->resume_final_vertex_connected();
34079  } // for (p < n_final_poly)
34080 
34081  // Clear the storage
34082  resume_initial_connection_polyline_pt.clear();
34083  resume_final_connection_polyline_pt.clear();
34084  }
34085 
34086  //=========================================================================
34087  /// Gets the associated vertex number according to the vertex
34088  /// coordinates on the destination boundary
34089  //=========================================================================
34090  template<class ELEMENT>
34093  Vector<double>& vertex_coordinates,
34094  const unsigned& dst_bnd_id,
34095  unsigned& vertex_number)
34096  {
34097  bool found_associated_vertex_number = false;
34098 
34099  // Get the pointer to the associated polyline by using the boundary id
34100  TriangleMeshPolyLine* dst_polyline = this->boundary_polyline_pt(dst_bnd_id);
34101 
34102  const unsigned n_vertices = dst_polyline->nvertex();
34103 
34104  // Loop over the vertices and return the closest vertex
34105  // to the given vertex coordinates
34106  for (unsigned i = 0; i < n_vertices; i++)
34107  {
34108  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
34109 
34110  double error = (vertex_coordinates[0] - current_vertex[0]) *
34111  (vertex_coordinates[0] - current_vertex[0]) +
34112  (vertex_coordinates[1] - current_vertex[1]) *
34113  (vertex_coordinates[1] - current_vertex[1]);
34114 
34115  error = sqrt(error);
34116 
34117  if (error < ToleranceForVertexMismatchInPolygons::Tolerable_error)
34118  {
34119  vertex_number = i;
34120  found_associated_vertex_number = true;
34121  break;
34122  }
34123  }
34124 
34125  return found_associated_vertex_number;
34126  }
34127 
34128  //=========================================================================
34129  /// Helper function that updates the input polygon's PSLG
34130  /// by using the end-points of elements from FaceMesh(es) that are
34131  /// constructed for the boundaries associated with the segments of the
34132  /// polygon. Optional boolean is used to run it as test only (if
34133  /// true is specified as input) in which case polygon isn't actually
34134  /// modified. Returned boolean indicates if polygon was (or would have
34135  /// been -- if called with check_only=false) changed.
34136  //=========================================================================
34137  template<class ELEMENT>
34139  TriangleMeshPolygon* polygon_pt, const bool& check_only)
34140  {
34141 #ifdef PARANOID
34142  // If the mesh is marked as distributed this method can not be
34143  // called since there is no guarantee of creating (distributed)
34144  // meshes that match in the number and position of nodes at their
34145  // shared boundaries. The only exececption is when called with
34146  // check_only=true, since no boundary updating is performed
34147  if (this->is_mesh_distributed() && !check_only)
34148  {
34149  std::stringstream error_message;
34150  error_message
34151  << "The updating of polygons of a distributed mesh can ONLY be\n"
34152  << "performed using the element's area associated to the halo(ed)\n"
34153  << "elements.\n"
34154  << "1) Make sure you have enabled the parallel mesh adaptation\n"
34155  << "option if you are working with a distributed mesh, OR\n"
34156  << "2) Make sure to call the update_..._using_elements_area() methods\n"
34157  << "if the mesh is marked as distributed\n\n";
34158  throw OomphLibError(
34159  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
34160  } // if (this->is_mesh_distributed())
34161 #endif
34162 
34163  // Boolean that indicates whether an actual update of the polygon
34164  // was performed or not
34165  bool unrefinement_was_performed = false;
34166  bool refinement_was_performed = false;
34167  bool max_length_applied = false;
34168 
34169  // Loop over the number of polylines
34170  const unsigned n_polyline = polygon_pt->npolyline();
34171 
34172  // Get face mesh representation of all polylines, possibly
34173  // with segments re-distributed to maintain an approximately
34174  // even sub-division of the polygon
34175  Vector<Mesh*> face_mesh_pt;
34176  get_face_mesh_representation(polygon_pt, face_mesh_pt);
34177 
34178  // Create vertices for the polylines by using the vertices
34179  // of the FaceElements
34180  Vector<double> vertex_coord(3); // zeta,x,y
34181  Vector<double> bound_left(1);
34182  Vector<double> bound_right(1);
34183 
34184  for (unsigned p = 0; p < n_polyline; p++)
34185  {
34186  // Set of coordinates that will be placed on the boundary
34187  // Set entries are ordered on first entry in vector which stores
34188  // the boundary coordinate so the vertices come out in order!
34189  std::set<Vector<double>> vertex_nodes;
34190 
34191  // Get the boundary id
34192  const unsigned bound = polygon_pt->curve_section_pt(p)->boundary_id();
34193 
34194  // Get the chunk number
34195  const unsigned chunk = polygon_pt->curve_section_pt(p)->boundary_chunk();
34196 
34197  // Loop over the face elements (ordered) and add their vertices
34198  unsigned n_face_element = face_mesh_pt[p]->nelement();
34199  for (unsigned e = 0; e < n_face_element; ++e)
34200  {
34201  FiniteElement* el_pt = face_mesh_pt[p]->finite_element_pt(e);
34202 
34203 #ifdef OOMPH_HAS_MPI
34204  // Only work with non-halo elements if the mesh is distributed
34205  if (this->is_mesh_distributed() && el_pt->is_halo())
34206  {
34207  continue;
34208  }
34209 #endif
34210 
34211  unsigned n_node = el_pt->nnode();
34212 
34213  // Add the left-hand node to the set:
34214 
34215  // Boundary coordinate
34216  el_pt->node_pt(0)->get_coordinates_on_boundary(bound, bound_left);
34217  vertex_coord[0] = bound_left[0];
34218 
34219  // Actual coordinates
34220  for (unsigned i = 0; i < 2; i++)
34221  {
34222  vertex_coord[i + 1] = el_pt->node_pt(0)->x(i);
34223  }
34224  vertex_nodes.insert(vertex_coord);
34225 
34226  // Add the right-hand nodes to the set:
34227 
34228  // Boundary coordinate
34229  el_pt->node_pt(n_node - 1)
34230  ->get_coordinates_on_boundary(bound, bound_right);
34231  vertex_coord[0] = bound_right[0];
34232 
34233  // Actual coordinates
34234  for (unsigned i = 0; i < 2; i++)
34235  {
34236  vertex_coord[i + 1] = el_pt->node_pt(n_node - 1)->x(i);
34237  }
34238  vertex_nodes.insert(vertex_coord);
34239  }
34240 
34241  // Now turn into vector for ease of handling...
34242  unsigned n_poly_vertex = vertex_nodes.size();
34243  Vector<Vector<double>> tmp_vector_vertex_node(n_poly_vertex);
34244  unsigned count = 0;
34245  for (std::set<Vector<double>>::iterator it = vertex_nodes.begin();
34246  it != vertex_nodes.end();
34247  ++it)
34248  {
34249  tmp_vector_vertex_node[count].resize(3);
34250  tmp_vector_vertex_node[count][0] = (*it)[0];
34251  tmp_vector_vertex_node[count][1] = (*it)[1];
34252  tmp_vector_vertex_node[count][2] = (*it)[2];
34253  ++count;
34254  }
34255 
34256  // Size of the vector
34257  unsigned n_vertex = tmp_vector_vertex_node.size();
34258 
34259  // Tolerance below which the middle point can be deleted
34260  // (ratio of deflection to element length)
34261  double unrefinement_tolerance =
34262  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
34263 
34264  //------------------------------------------------------
34265  // Unrefinement
34266  //------------------------------------------------------
34267  if (unrefinement_tolerance > 0.0 && n_vertex >= 3)
34268  {
34269  unrefinement_was_performed = unrefine_boundary(bound,
34270  chunk,
34271  tmp_vector_vertex_node,
34272  unrefinement_tolerance,
34273  check_only);
34274 
34275  // In this case the "unrefinement_was_performed" variable
34276  // tell us if the update had been performed when calling
34277  // with check_oly=false
34278  if (check_only && unrefinement_was_performed)
34279  {
34280  // Cleanup (but only the elements -- the nodes still exist in
34281  // the bulk mesh!
34282  for (unsigned p = 0; p < n_polyline; p++)
34283  {
34284  face_mesh_pt[p]->flush_node_storage();
34285  delete face_mesh_pt[p];
34286  }
34287  return true;
34288  }
34289 
34290  } // end of unrefinement
34291 
34292  // Do not perform refinement if there are no more than two vertices
34293  // New size of the vector
34294  n_vertex = tmp_vector_vertex_node.size();
34295 
34296  //------------------------------------------------
34297  // Refinement
34298  //------------------------------------------------
34299  double refinement_tolerance =
34300  polygon_pt->polyline_pt(p)->refinement_tolerance();
34301  if (refinement_tolerance > 0.0 && n_vertex >= 2)
34302  {
34303  refinement_was_performed = refine_boundary(face_mesh_pt[p],
34304  tmp_vector_vertex_node,
34305  refinement_tolerance,
34306  check_only);
34307 
34308  // In this case the "refinement_was_performed" variable
34309  // tell us if the update had been performed when calling
34310  // with check_only=false
34311  if (check_only && refinement_was_performed)
34312  {
34313  // Cleanup (but only the elements -- the nodes still exist in
34314  // the bulk mesh!
34315  for (unsigned p = 0; p < n_polyline; p++)
34316  {
34317  face_mesh_pt[p]->flush_node_storage();
34318  delete face_mesh_pt[p];
34319  }
34320  return true;
34321  }
34322 
34323  } // end refinement
34324 
34325  // Do not perform maximum length constraint if there are no more than
34326  // two vertices
34327  // New size of the vector
34328  n_vertex = tmp_vector_vertex_node.size();
34329 
34330  //------------------------------------------------
34331  // Maximum length constrait
34332  //-----------------------------------------------
34333  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
34334  if (maximum_length > 0.0 && n_vertex >= 2)
34335  {
34336  max_length_applied = apply_max_length_constraint(
34337  face_mesh_pt[p], tmp_vector_vertex_node, maximum_length);
34338 
34339  // In this case the max length criteria was applied, check if
34340  // check_only=false
34341  if (check_only && max_length_applied)
34342  {
34343  // Cleanup (but only the elements -- the nodes still exist in
34344  // the bulk mesh!
34345  for (unsigned p = 0; p < n_polyline; p++)
34346  {
34347  face_mesh_pt[p]->flush_node_storage();
34348  delete face_mesh_pt[p];
34349  }
34350  return true;
34351  }
34352  }
34353 
34354  // For further processing the three-dimensional vector
34355  // has to be reduced to a two-dimensional vector
34356  n_vertex = tmp_vector_vertex_node.size();
34357  Vector<Vector<double>> vector_vertex_node(n_vertex);
34358 
34359  for (unsigned i = 0; i < n_vertex; i++)
34360  {
34361  vector_vertex_node[i].resize(2);
34362  vector_vertex_node[i][0] = tmp_vector_vertex_node[i][1];
34363  vector_vertex_node[i][1] = tmp_vector_vertex_node[i][2];
34364  }
34365 
34366 #ifdef OOMPH_HAS_MPI
34367  // Only perform this checking if the mesh is not distributed. When
34368  // the mesh is distributed the polylines continuity is addressed in
34369  // the sort_polylines_helper() method
34370  if (!this->is_mesh_distributed())
34371 #endif
34372  {
34373  if ((p > 0) && !check_only)
34374  {
34375  // Final end point of previous line
34376  Vector<double> final_vertex_of_previous_segment;
34377  unsigned n_prev_vertex =
34378  polygon_pt->curve_section_pt(p - 1)->nvertex();
34379  final_vertex_of_previous_segment =
34380  polygon_pt->polyline_pt(p - 1)->vertex_coordinate(n_prev_vertex -
34381  1);
34382 
34383  unsigned prev_seg_boundary_id =
34384  polygon_pt->curve_section_pt(p - 1)->boundary_id();
34385 
34386  // Find the error between the final vertex of the previous
34387  // line and the first vertex of the current line
34388  double error = 0.0;
34389  for (unsigned i = 0; i < 2; i++)
34390  {
34391  const double dist = final_vertex_of_previous_segment[i] -
34392  (*vector_vertex_node.begin())[i];
34393  error += dist * dist;
34394  }
34395  error = sqrt(error);
34396 
34397  // If the error is bigger than the tolerance then
34398  // we probably need to reverse, but better check
34399  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
34400  {
34401  // Find the error between the final vertex of the previous
34402  // line and the last vertex of the current line
34403  double rev_error = 0.0;
34404  for (unsigned i = 0; i < 2; i++)
34405  {
34406  const double dist = final_vertex_of_previous_segment[i] -
34407  (*--vector_vertex_node.end())[i];
34408  rev_error += dist * dist;
34409  }
34410  rev_error = sqrt(rev_error);
34411 
34412  if (rev_error >
34413  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34414  {
34415  // It could be possible that the first segment be reversed and we
34416  // did not notice it because this check does not apply for the
34417  // first segment. We can verify if the first segment is reversed
34418  // by using the vertex number 1
34419  if (p == 1)
34420  {
34421  // Initial end point of previous line
34422  Vector<double> initial_vertex_of_previous_segment;
34423 
34424  initial_vertex_of_previous_segment =
34425  polygon_pt->polyline_pt(p - 1)->vertex_coordinate(0);
34426 
34427  unsigned prev_seg_boundary_id =
34428  polygon_pt->curve_section_pt(p - 1)->boundary_id();
34429 
34430  // Find the error between the initial vertex of the previous
34431  // line and the first vertex of the current line
34432  double error = 0.0;
34433  for (unsigned i = 0; i < 2; i++)
34434  {
34435  const double dist = initial_vertex_of_previous_segment[i] -
34436  (*vector_vertex_node.begin())[i];
34437  error += dist * dist;
34438  }
34439  error = sqrt(error); // Reversed only the previous one
34440 
34441  // If the error is bigger than the tolerance then
34442  // we probably need to reverse, but better check
34443  if (error >
34444  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34445  {
34446  // Find the error between the final vertex of the previous
34447  // line and the last vertex of the current line
34448  double rev_error = 0.0;
34449  for (unsigned i = 0; i < 2; i++)
34450  {
34451  const double dist = initial_vertex_of_previous_segment[i] -
34452  (*--vector_vertex_node.end())[i];
34453  rev_error += dist * dist;
34454  }
34455  rev_error =
34456  sqrt(rev_error); // Reversed both the current one and
34457  // the previous one
34458 
34459  if (rev_error >
34460  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34461  {
34462  std::ostringstream error_stream;
34463  error_stream
34464  << "The distance between the first node of the current\n"
34465  << "line segment (boundary " << bound
34466  << ") and either end of "
34467  << "the previous line segment\n"
34468  << "(boundary " << prev_seg_boundary_id
34469  << ") is bigger than "
34470  << "the desired tolerance "
34471  << ToleranceForVertexMismatchInPolygons::Tolerable_error
34472  << ".\n"
34473  << "This suggests that the polylines defining the "
34474  "polygonal\n"
34475  << "representation are not properly ordered.\n"
34476  << "Fail on last vertex of polyline: ("
34477  << prev_seg_boundary_id
34478  << ") and\nfirst vertex of polyline (" << bound
34479  << ").\nThis should have failed when first trying to "
34480  << "construct the\npolygon.\n";
34481  throw OomphLibError(error_stream.str(),
34482  OOMPH_CURRENT_FUNCTION,
34483  OOMPH_EXCEPTION_LOCATION);
34484  }
34485  else
34486  {
34487  // Reverse both
34488  // Reverse the current vector to line up with the previous
34489  // one
34490  std::reverse(vector_vertex_node.begin(),
34491  vector_vertex_node.end());
34492 
34493  polygon_pt->polyline_pt(p - 1)->reverse();
34494  }
34495  }
34496  else
34497  {
34498  // Reverse the previous one
34499  polygon_pt->polyline_pt(p - 1)->reverse();
34500  }
34501 
34502  } // if p == 1
34503  else
34504  {
34505  std::ostringstream error_stream;
34506  error_stream
34507  << "The distance between the first node of the current\n"
34508  << "line segment (boundary " << bound
34509  << ") and either end of "
34510  << "the previous line segment\n"
34511  << "(boundary " << prev_seg_boundary_id
34512  << ") is bigger than the "
34513  << "desired tolerance "
34514  << ToleranceForVertexMismatchInPolygons::Tolerable_error
34515  << ".\n"
34516  << "This suggests that the polylines defining the polygonal\n"
34517  << "representation are not properly ordered.\n"
34518  << "Fail on last vertex of polyline: ("
34519  << prev_seg_boundary_id << ") and\nfirst vertex of polyline ("
34520  << bound << ").\n"
34521  << "This should have failed when first trying to construct "
34522  "the\n"
34523  << "polygon.\n";
34524  throw OomphLibError(error_stream.str(),
34525  OOMPH_CURRENT_FUNCTION,
34526  OOMPH_EXCEPTION_LOCATION);
34527  }
34528  }
34529  else
34530  {
34531  // Reverse the current vector to line up with the previous one
34532  std::reverse(vector_vertex_node.begin(),
34533  vector_vertex_node.end());
34534  }
34535 
34536  } // first error
34537  } // p > 0
34538  } // is mesh not distributed?
34539 
34540  if (!check_only)
34541  {
34542  // Now update the polyline according to the new vertices
34543  // The new one representation
34544  TriangleMeshPolyLine* tmp_polyline_pt =
34545  new TriangleMeshPolyLine(vector_vertex_node, bound);
34546 
34547  // Create a temporal "curve section" version of the recently created
34548  // polyline
34549  TriangleMeshCurveSection* tmp_curve_section_pt = tmp_polyline_pt;
34550 
34551  // Establish refinement and unrefinement tolerance
34552  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
34553  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
34554 
34555  // Establish the maximum length constraint
34556  tmp_polyline_pt->set_maximum_length(maximum_length);
34557 
34558  // We pass the connection information from the old polyline to
34559  // the new one
34560  this->copy_connection_information(polygon_pt->polyline_pt(p),
34561  tmp_curve_section_pt);
34562 
34563  // Now update the polyline according to the new vertices but
34564  // first check if the object is allowed to delete the representation
34565  // or if it should be done by other object
34566  bool delete_it_on_destructor = false;
34567 
34568  std::set<TriangleMeshCurveSection*>::iterator it =
34569  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
34570 
34571  if (it != this->Free_curve_section_pt.end())
34572  {
34573  this->Free_curve_section_pt.erase(it);
34574  delete polygon_pt->curve_section_pt(p);
34575  delete_it_on_destructor = true;
34576  }
34577 
34578  // ------------------------------------------------------------
34579  // Copying the new representation
34580  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
34581 
34582  // Update the Boundary - Polyline map
34583  this->Boundary_curve_section_pt[bound] =
34584  polygon_pt->curve_section_pt(p);
34585 
34586  // The new curve always needs to be added to the free section
34587  // because we created it internally
34588  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
34589 
34590  } // if(!check_only)
34591 
34592  } // for (p < n_polyline)
34593 
34594  // Cleanup (but only the elements -- the nodes still exist in
34595  // the bulk mesh!
34596  for (unsigned p = 0; p < n_polyline; p++)
34597  {
34598  face_mesh_pt[p]->flush_node_storage();
34599  delete face_mesh_pt[p];
34600  }
34601 
34602  if (check_only)
34603  {
34604  // if we end up all the way down here, no update of the internal
34605  // boundaries is necessary (in case we only check)
34606  return false;
34607  }
34608  else
34609  {
34610  // if we not only check, but actually perform the update and end up
34611  // all the way down here then we indicate whether an update was performed
34612  // or not
34613  return (unrefinement_was_performed || refinement_was_performed ||
34614  max_length_applied);
34615  }
34616  }
34617 
34618  //=========================================================================
34619  /// Helper function that updates the input open curve by using
34620  /// end-points of elements from FaceMesh(es) that are constructed for the
34621  /// boundaries associated with the polylines. Optional boolean is used to
34622  /// run it as test only (if true is specified as input) in which case the
34623  /// polylines are not actually modified. Returned boolean indicates if
34624  /// polylines were (or would have been -- if called with check_only=false)
34625  /// changed.
34626  //=========================================================================
34627  template<class ELEMENT>
34629  TriangleMeshOpenCurve* open_polyline_pt, const bool& check_only)
34630  {
34631 #ifdef PARANOID
34632  // If the mesh is marked as distributed this method can not be
34633  // called since there is no guarantee of creating (distributed)
34634  // meshes that match in the number and position of nodes at their
34635  // shared boundaries. The only exececption is when called with
34636  // check_only=true, since no boundary updating is performed
34637  if (this->is_mesh_distributed() && !check_only)
34638  {
34639  std::stringstream error_message;
34640  error_message
34641  << "The updating of open curves of a distributed mesh can ONLY be\n"
34642  << "performed using the element's area associated to the halo(ed)\n"
34643  << "elements.\n"
34644  << "1) Make sure you have enabled the parallel mesh adaptation\n"
34645  << "option if you are working with a distributed mesh, OR\n"
34646  << "2) Make sure to call the update_..._using_elements_area() methods\n"
34647  << "if the mesh is marked as distributed\n\n";
34648  throw OomphLibError(
34649  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
34650  } // if (this->is_mesh_distributed())
34651 #endif
34652 
34653  // Boolean that indicates whether an actual update of the polylines
34654  // were performed or not
34655  bool unrefinement_was_performed = false;
34656  bool refinement_was_performed = false;
34657  bool max_length_applied = false;
34658 
34659  // Loop over the number of polylines
34660  const unsigned n_polyline = open_polyline_pt->ncurve_section();
34661 
34662  // Get face mesh representation of all polylines, possibly
34663  // with segments re-distributed to maintain an approximately
34664  // even sub-division of the polygon
34665  Vector<Mesh*> face_mesh_pt;
34666  get_face_mesh_representation(open_polyline_pt, face_mesh_pt);
34667 
34668  // Create vertices for the polylines by using the vertices
34669  // of the FaceElements
34670  Vector<double> vertex_coord(3); // zeta,x,y
34671  Vector<double> bound_left(1);
34672  Vector<double> bound_right(1);
34673 
34674  for (unsigned p = 0; p < n_polyline; p++)
34675  {
34676  // Set of coordinates that will be placed on the boundary
34677  // Set entries are ordered on first entry in vector which stores
34678  // the boundary coordinate so the vertices come out in order!
34679  std::set<Vector<double>> vertex_nodes;
34680 
34681  // Get the boundary id
34682  const unsigned bound =
34683  open_polyline_pt->curve_section_pt(p)->boundary_id();
34684 
34685  // Get the chunk number
34686  const unsigned chunk =
34687  open_polyline_pt->curve_section_pt(p)->boundary_chunk();
34688 
34689  // Loop over the face elements (ordered) and add their vertices
34690  unsigned n_face_element = face_mesh_pt[p]->nelement();
34691 
34692  // n_count = 0;
34693  for (unsigned e = 0; e < n_face_element; ++e)
34694  {
34695  FiniteElement* el_pt = face_mesh_pt[p]->finite_element_pt(e);
34696  unsigned n_node = el_pt->nnode();
34697 
34698  // Add the left-hand node to the set:
34699 
34700  // Boundary coordinate
34701  el_pt->node_pt(0)->get_coordinates_on_boundary(bound, bound_left);
34702  vertex_coord[0] = bound_left[0];
34703 
34704  // Actual coordinates
34705  for (unsigned i = 0; i < 2; i++)
34706  {
34707  vertex_coord[i + 1] = el_pt->node_pt(0)->x(i);
34708  }
34709  vertex_nodes.insert(vertex_coord);
34710 
34711  // Add the right-hand nodes to the set:
34712 
34713  // Boundary coordinate
34714  el_pt->node_pt(n_node - 1)
34715  ->get_coordinates_on_boundary(bound, bound_right);
34716  vertex_coord[0] = bound_right[0];
34717 
34718  // Actual coordinates
34719  for (unsigned i = 0; i < 2; i++)
34720  {
34721  vertex_coord[i + 1] = el_pt->node_pt(n_node - 1)->x(i);
34722  }
34723  vertex_nodes.insert(vertex_coord);
34724  }
34725 
34726  // Now turn into vector for ease of handling...
34727  unsigned n_poly_vertex = vertex_nodes.size();
34728  Vector<Vector<double>> tmp_vector_vertex_node(n_poly_vertex);
34729  unsigned count = 0;
34730  for (std::set<Vector<double>>::iterator it = vertex_nodes.begin();
34731  it != vertex_nodes.end();
34732  ++it)
34733  {
34734  tmp_vector_vertex_node[count].resize(3);
34735  tmp_vector_vertex_node[count][0] = (*it)[0];
34736  tmp_vector_vertex_node[count][1] = (*it)[1];
34737  tmp_vector_vertex_node[count][2] = (*it)[2];
34738  ++count;
34739  }
34740 
34741  // Size of the vector
34742  unsigned n_vertex = tmp_vector_vertex_node.size();
34743 
34744  // Tolerance below which the middle point can be deleted
34745  // (ratio of deflection to element length)
34746  double unrefinement_tolerance =
34747  open_polyline_pt->polyline_pt(p)->unrefinement_tolerance();
34748 
34749  //------------------------------------------------------
34750  // Unrefinement
34751  //------------------------------------------------------
34752  if (unrefinement_tolerance > 0.0 && n_vertex >= 3)
34753  {
34754  unrefinement_was_performed = unrefine_boundary(bound,
34755  chunk,
34756  tmp_vector_vertex_node,
34757  unrefinement_tolerance,
34758  check_only);
34759 
34760  // In this case the unrefinement_was_performed variable actually
34761  // tell us if the update had been performed when calling
34762  // with check_only=false
34763  if (check_only && unrefinement_was_performed)
34764  {
34765  // Cleanup (but only the elements -- the nodes still exist in
34766  // the bulk mesh!
34767  for (unsigned p = 0; p < n_polyline; p++)
34768  {
34769  face_mesh_pt[p]->flush_node_storage();
34770  delete face_mesh_pt[p];
34771  }
34772  return true;
34773  }
34774 
34775  } // end of unrefinement
34776 
34777  // Do not perform refinement if there are no more than two vertices
34778  // (open curve version)
34779  // New size of the vector
34780  n_vertex = tmp_vector_vertex_node.size();
34781 
34782  //------------------------------------------------
34783  /// Refinement
34784  //------------------------------------------------
34785  double refinement_tolerance =
34786  open_polyline_pt->polyline_pt(p)->refinement_tolerance();
34787  if (refinement_tolerance > 0.0 && n_vertex >= 2)
34788  {
34789  refinement_was_performed = refine_boundary(face_mesh_pt[p],
34790  tmp_vector_vertex_node,
34791  refinement_tolerance,
34792  check_only);
34793 
34794  // In this case the unrefinement_was_performed variable actually
34795  // tell us if the update had been performed when calling
34796  // with check_only=false
34797  if (check_only && refinement_was_performed)
34798  {
34799  // Cleanup (but only the elements -- the nodes still exist in
34800  // the bulk mesh!
34801  for (unsigned p = 0; p < n_polyline; p++)
34802  {
34803  face_mesh_pt[p]->flush_node_storage();
34804  delete face_mesh_pt[p];
34805  }
34806  return true;
34807  }
34808 
34809  } // end refinement
34810 
34811  // Do not perform maximum length constraint if there are no more than
34812  // two vertices
34813  // New size of the vector
34814  n_vertex = tmp_vector_vertex_node.size();
34815 
34816  //------------------------------------------------
34817  // Maximum length constraint
34818  //-----------------------------------------------
34819  double maximum_length =
34820  open_polyline_pt->polyline_pt(p)->maximum_length();
34821  if (maximum_length > 0.0 && n_vertex >= 2)
34822  {
34823  bool max_length_applied = false;
34824  max_length_applied = apply_max_length_constraint(
34825  face_mesh_pt[p], tmp_vector_vertex_node, maximum_length);
34826 
34827  // In this case the max length criteria was applied, check if
34828  // check_only=false
34829  if (check_only && max_length_applied)
34830  {
34831  // Cleanup (but only the elements -- the nodes still exist in
34832  // the bulk mesh!
34833  for (unsigned p = 0; p < n_polyline; p++)
34834  {
34835  face_mesh_pt[p]->flush_node_storage();
34836  delete face_mesh_pt[p];
34837  }
34838  return true;
34839  }
34840  }
34841 
34842  // For further processing the three-dimensional vector
34843  // has to be reduced to a two-dimensional vector
34844  n_vertex = tmp_vector_vertex_node.size();
34845  Vector<Vector<double>> vector_vertex_node(n_vertex);
34846 
34847  for (unsigned i = 0; i < n_vertex; i++)
34848  {
34849  vector_vertex_node[i].resize(2);
34850  vector_vertex_node[i][0] = tmp_vector_vertex_node[i][1];
34851  vector_vertex_node[i][1] = tmp_vector_vertex_node[i][2];
34852  }
34853 
34854 #ifdef OOMPH_HAS_MPI
34855  // Only perform this checking if the mesh is not distributed. When
34856  // the mesh is distributed the polylines continuity is addressed
34857  // in the sort_polylines_helper() method
34858  if (!this->is_mesh_distributed())
34859 #endif
34860  {
34861  // Check whether the segments are continguous (first vertex of this
34862  // segment is equal to last vertex of previous segment).
34863  // If not, we should reverse the order of the current segment.
34864  // This check only applies for segments other than the first.
34865  // We only bother with this check, if we actually perform an update
34866  // of the polyline, i.e. if it's not only a check
34867  if ((p > 0) && !check_only)
34868  {
34869  // Final end point of previous line
34870  Vector<double> final_vertex_of_previous_segment;
34871  open_polyline_pt->polyline_pt(p - 1)->final_vertex_coordinate(
34872  final_vertex_of_previous_segment);
34873 
34874  unsigned prev_seg_boundary_id =
34875  open_polyline_pt->curve_section_pt(p - 1)->boundary_id();
34876 
34877  // Find the error between the final vertex of the previous
34878  // line and the first vertex of the current line
34879  double error = 0.0;
34880  for (unsigned i = 0; i < 2; i++)
34881  {
34882  const double dist = final_vertex_of_previous_segment[i] -
34883  (*vector_vertex_node.begin())[i];
34884  error += dist * dist;
34885  }
34886  error = sqrt(error);
34887 
34888  // If the error is bigger than the tolerance then
34889  // we probably need to reverse, but better check
34890  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
34891  {
34892  // Find the error between the final vertex of the previous
34893  // line and the first vertex of the current line
34894  error = 0.0;
34895  for (unsigned i = 0; i < 2; i++)
34896  {
34897  const double dist = final_vertex_of_previous_segment[i] -
34898  (*--vector_vertex_node.end())[i];
34899  error += dist * dist;
34900  }
34901  error = sqrt(error);
34902 
34903  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
34904  {
34905  // It could be possible that the first segment be reversed
34906  // and we did not notice it because this check does not
34907  // apply for the first segment. We can verify if the first
34908  // segment is reversed by using the vertex number 1
34909  if (p == 1)
34910  {
34911  // If no found it is possible that the previous polyline
34912  // be reversed Check for that case Initial point of
34913  // previous line
34914  Vector<double> initial_vertex_of_previous_segment;
34915  open_polyline_pt->polyline_pt(p - 1)->initial_vertex_coordinate(
34916  initial_vertex_of_previous_segment);
34917 
34918  // Find the error between the initial vertex of the previous
34919  // line and the first vertex of the current line
34920  error = 0.0;
34921  for (unsigned i = 0; i < 2; i++)
34922  {
34923  const double dist = initial_vertex_of_previous_segment[i] -
34924  (*vector_vertex_node.begin())[i];
34925  error += dist * dist;
34926  }
34927  error = sqrt(error);
34928 
34929  // If the error is bigger than the tolerance then
34930  // we probably need to reverse, but better check
34931  if (error >
34932  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34933  {
34934  // Find the error between the final vertex of the previous
34935  // line and the first vertex of the current line
34936  error = 0.0;
34937  for (unsigned i = 0; i < 2; i++)
34938  {
34939  const double dist = initial_vertex_of_previous_segment[i] -
34940  (*--vector_vertex_node.end())[i];
34941  error += dist * dist;
34942  }
34943  error = sqrt(error);
34944 
34945  if (error >
34946  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34947  {
34948  std::ostringstream error_stream;
34949  error_stream
34950  << "The distance between the first node of the current\n"
34951  << "line segment (boundary " << bound
34952  << ") and either end of the previous line segment\n"
34953  << "(boundary " << prev_seg_boundary_id
34954  << ") is bigger than "
34955  << "the desired tolerance "
34956  << ToleranceForVertexMismatchInPolygons::Tolerable_error
34957  << ".\n"
34958  << "This suggests that the polylines defining the open "
34959  << "curve\n"
34960  << "representation are not properly ordered.\n"
34961  << "Fail on last vertex of polyline: ("
34962  << prev_seg_boundary_id
34963  << ") and\nfirst vertex of polyline (" << bound << ").\n"
34964  << "This should have failed when first trying to "
34965  "construct\n"
34966  << "the open curve.\n";
34967  throw OomphLibError(error_stream.str(),
34968  OOMPH_CURRENT_FUNCTION,
34969  OOMPH_EXCEPTION_LOCATION);
34970  }
34971  else // We have to reverse both
34972  {
34973  // First reverse the previous polyline
34974  open_polyline_pt->polyline_pt(p - 1)->reverse();
34975  // Then reverse the current polyline
34976  std::reverse(vector_vertex_node.begin(),
34977  vector_vertex_node.end());
34978  }
34979  }
34980  else
34981  {
34982  // Reverse the previous polyline only
34983  open_polyline_pt->polyline_pt(p - 1)->reverse();
34984  }
34985  } // if (p == 1)
34986  else
34987  {
34988  std::ostringstream error_stream;
34989  error_stream
34990  << "The distance between the first node of the current\n"
34991  << "line segment (boundary " << bound
34992  << ") and either end of "
34993  << "the previous line segment\n"
34994  << "(boundary " << prev_seg_boundary_id
34995  << ") is bigger than the "
34996  << "desired tolerance "
34997  << ToleranceForVertexMismatchInPolygons::Tolerable_error
34998  << ".\n"
34999  << "This suggests that the polylines defining the polygonal\n"
35000  << "representation are not properly ordered.\n"
35001  << "Fail on last vertex of polyline: ("
35002  << prev_seg_boundary_id << ") and\nfirst vertex of polyline ("
35003  << bound << ").\n"
35004  << "This should have failed when first trying to construct "
35005  "the\n"
35006  << "polygon.\n";
35007  throw OomphLibError(error_stream.str(),
35008  OOMPH_CURRENT_FUNCTION,
35009  OOMPH_EXCEPTION_LOCATION);
35010  }
35011  }
35012  else
35013  {
35014  // Reverse the current vector to line up with the previous one
35015  std::reverse(vector_vertex_node.begin(),
35016  vector_vertex_node.end());
35017  }
35018  }
35019 
35020  } // if p > 0
35021 
35022  } // is mesh not distributed?
35023 
35024  if (!check_only)
35025  {
35026  // Now update the polyline according to the new vertices The new
35027  // one representation
35028  TriangleMeshPolyLine* tmp_polyline =
35029  new TriangleMeshPolyLine(vector_vertex_node, bound);
35030 
35031  // Create a temporal "curve section" version of the recently
35032  // created polyline
35033  TriangleMeshCurveSection* tmp_curve_section = tmp_polyline;
35034 
35035  // Copy the unrefinement and refinement information
35036  tmp_polyline->set_unrefinement_tolerance(unrefinement_tolerance);
35037  tmp_polyline->set_refinement_tolerance(refinement_tolerance);
35038 
35039  // Establish the maximum length constraint
35040  tmp_polyline->set_maximum_length(maximum_length);
35041 
35042  // Pass the connection information from the old polyline to the
35043  // new one
35044  this->copy_connection_information(open_polyline_pt->polyline_pt(p),
35045  tmp_curve_section);
35046 
35047  std::set<TriangleMeshCurveSection*>::iterator it =
35048  this->Free_curve_section_pt.find(
35049  open_polyline_pt->curve_section_pt(p));
35050 
35051  bool delete_it_on_destructor = false;
35052 
35053  if (it != this->Free_curve_section_pt.end())
35054  {
35055  // Free previous representation only if you created
35056  this->Free_curve_section_pt.erase(it);
35057  delete open_polyline_pt->curve_section_pt(p);
35058  delete_it_on_destructor = true;
35059  }
35060 
35061  // *****************************************************************
35062  // Copying the new representation
35063  open_polyline_pt->curve_section_pt(p) = tmp_polyline;
35064 
35065  // Update the Boundary <--> PolyLine map
35066  this->Boundary_curve_section_pt[bound] =
35067  open_polyline_pt->curve_section_pt(p);
35068 
35069  if (delete_it_on_destructor)
35070  {
35071  this->Free_curve_section_pt.insert(
35072  open_polyline_pt->curve_section_pt(p));
35073  }
35074 
35075  } // if(!check_only)
35076 
35077  } // n_polylines
35078 
35079  // Cleanup (but only the elements -- the nodes still exist in
35080  // the bulk mesh!
35081  for (unsigned p = 0; p < n_polyline; p++)
35082  {
35083  face_mesh_pt[p]->flush_node_storage();
35084  delete face_mesh_pt[p];
35085  }
35086 
35087  if (check_only)
35088  {
35089  // if we end up all the way down here, no update of the internal
35090  // boundaries is necessary (in case we only check)
35091  return false;
35092  }
35093  else
35094  {
35095  // if we not only check, but actually perform the update and end
35096  // up all the way down here then we indicate whether an update was
35097  // performed or not
35098  return (unrefinement_was_performed || refinement_was_performed ||
35099  max_length_applied);
35100  }
35101  }
35102 
35103  //=========================================================================
35104  /// Helper function that performs the unrefinement process
35105  /// on the specified boundary by using the provided vertices
35106  /// representation. Optional boolean is used to run it as test only (if
35107  /// true is specified as input) in which case vertex coordinates aren't
35108  /// actually modified. Returned boolean indicates if polyline was (or
35109  /// would have been -- if called with check_only=false) changed.
35110  //=========================================================================
35111  template<class ELEMENT>
35113  const unsigned& b,
35114  const unsigned& c,
35115  Vector<Vector<double>>& vector_bnd_vertices,
35116  double& unrefinement_tolerance,
35117  const bool& check_only)
35118  {
35119  // Store the vertices not allowed for deletion
35120  std::set<Vector<double>> no_delete_vertex;
35121 
35122  // Does the boundary receives connections?
35123  const bool boundary_receive_connections =
35124  this->boundary_connections(b, c, no_delete_vertex);
35125 
35126  // Boolean that indicates whether an actual update of the vertex
35127  // coordinates was performed or not
35128  bool unrefinement_was_performed = false;
35129 
35130  unsigned n_vertex = vector_bnd_vertices.size();
35131 
35132  // Initialise counter that indicates at which vertex we're currently
35133  // considering for deletion
35134  unsigned counter = 1;
35135 
35136  // Loop over the nodes; start with the second one and increment by two
35137  // this way a "pack" of three nodes will be considered for calculation:
35138  // the middle-node (which is to be deleted or not) and the adjacent
35139  // nodes
35140  for (unsigned i = 1; i <= n_vertex - 2; i += 2)
35141  {
35142  // Maths from http://www.cgafaq.info/wiki/Circle_Through_Three_Points
35143  double a_x = vector_bnd_vertices[i - 1][1];
35144  double a_y = vector_bnd_vertices[i - 1][2];
35145  double b_x = vector_bnd_vertices[i][1];
35146  double b_y = vector_bnd_vertices[i][2];
35147  double c_x = vector_bnd_vertices[i + 1][1];
35148  double c_y = vector_bnd_vertices[i + 1][2];
35149 
35150  double a = b_x - a_x;
35151  double b = b_y - a_y;
35152  double c = c_x - a_x;
35153  double d = c_y - a_y;
35154 
35155  double e = a * (a_x + b_x) + b * (a_y + b_y);
35156  double f = c * (a_x + c_x) + d * (a_y + c_y);
35157 
35158  double g = 2.0 * (a * (c_y - b_y) - b * (c_x - b_x));
35159 
35160  bool do_it = false;
35161  if (std::fabs(g) < 1.0e-14)
35162  {
35163  do_it = true;
35164  if (check_only)
35165  {
35166  return true;
35167  }
35168  }
35169  else
35170  {
35171  double p_x = (d * e - b * f) / g;
35172  double p_y = (a * f - c * e) / g;
35173 
35174  double r = sqrt(pow((a_x - p_x), 2) + pow((a_y - p_y), 2));
35175 
35176  double rhalfca_x = 0.5 * (a_x - c_x);
35177  double rhalfca_y = 0.5 * (a_y - c_y);
35178 
35179  double halfca_squared = pow(rhalfca_x, 2) + pow(rhalfca_y, 2);
35180 
35181  double sticky_out_bit = r - sqrt(std::fabs((r * r) - halfca_squared));
35182 
35183  // If sticky out bit divided by distance between end nodes
35184  // is less than tolerance the boundary is so flat that we
35185  // can safely kill the node
35186  if ((sticky_out_bit / (2.0 * sqrt(halfca_squared))) <
35187  unrefinement_tolerance)
35188  {
35189  do_it = true;
35190  if (check_only)
35191  {
35192  return true;
35193  }
35194  }
35195  }
35196 
35197  // If the vertex was proposed for deletion check that it is
35198  // allowed for being deleted
35199  if (do_it && boundary_receive_connections)
35200  {
35201  // Is the vertex one of the non deletable vertices
35202  for (std::set<Vector<double>>::iterator it = no_delete_vertex.begin();
35203  it != no_delete_vertex.end();
35204  it++)
35205  {
35206  // Compute the distance between the proposed node to delete
35207  // and the ones that should not be deleted
35208  const double x = (*it)[0];
35209  const double y = (*it)[1];
35210  double error = (b_x - x) * (b_x - x) + (b_y - y) * (b_y - y);
35211  error = sqrt(error);
35212 
35213  if (error < ToleranceForVertexMismatchInPolygons::Tolerable_error)
35214  {
35215  // Do not delete the vertex
35216  do_it = false;
35217  break;
35218  }
35219  }
35220 
35221  } // if (do_it && boundary_receive_connections)
35222 
35223  // Remove node?
35224  if (do_it)
35225  {
35226  vector_bnd_vertices[i].resize(0);
35227  }
35228 
35229  // Increase the counter, that indicates the number of the
35230  // next middle node
35231  counter += 2;
35232  }
35233 
35234  // coming out of here the value of counter is the index of the
35235  // last node on the polyline counter=n_vertex-1 (in case of an
35236  // even number of nodes) or counter has the value of the number
35237  // of nodes on the polyline counter=n_vertex (in case of an odd
35238  // number of nodes
35239 
35240  // Special treatment for the end of the polyline:
35241  // If the number of nodes is even, then the previous loop stopped
35242  // at the last but second node, i.e. the current value of counter
35243  // is the index of the last node. If that's the case, the last but
35244  // one node needs to be treated separately
35245  if ((counter) == (n_vertex - 1))
35246  {
35247  // Set the last but one node as middle node
35248  unsigned i = vector_bnd_vertices.size() - 2;
35249 
35250  // Index of the current! last but second node (considering any
35251  // previous deletion)
35252  unsigned n = 0;
35253 
35254  if (vector_bnd_vertices[counter - 2].size() != 0)
35255  {
35256  // if the initial last but second node does still exist then
35257  // this one is obviously also the current last but second one
35258  n = counter - 2;
35259  }
35260  else
35261  {
35262  // if the initial last but second node was deleted then the
35263  // initial last but third node is the current last but second
35264  // node
35265  n = counter - 3;
35266  }
35267 
35268  // CODE DUPLICATION -- CAN'T BE BOTHERED TO WRITE A SEPARATE
35269  // FUNCTION FOR THIS; PROBABLY WORTH DOING IF/WHEN THERE'S
35270  // A MISTAKE IN ANY OF THIS AND IT NEEDS TO BE FIXED...
35271 
35272  // Maths from http://www.cgafaq.info/wiki/Circle_Through_Three_Points
35273  double a_x = vector_bnd_vertices[n][1];
35274  double a_y = vector_bnd_vertices[n][2];
35275  double b_x = vector_bnd_vertices[i][1];
35276  double b_y = vector_bnd_vertices[i][2];
35277  double c_x = vector_bnd_vertices[i + 1][1];
35278  double c_y = vector_bnd_vertices[i + 1][2];
35279 
35280  double a = b_x - a_x;
35281  double b = b_y - a_y;
35282  double c = c_x - a_x;
35283  double d = c_y - a_y;
35284 
35285  double e = a * (a_x + b_x) + b * (a_y + b_y);
35286  double f = c * (a_x + c_x) + d * (a_y + c_y);
35287 
35288  double g = 2.0 * (a * (c_y - b_y) - b * (c_x - b_x));
35289 
35290  bool do_it = false;
35291  if (std::fabs(g) < 1.0e-14)
35292  {
35293  do_it = true;
35294  if (check_only)
35295  {
35296  return true;
35297  }
35298  }
35299  else
35300  {
35301  double p_x = (d * e - b * f) / g;
35302  double p_y = (a * f - c * e) / g;
35303 
35304  double r = sqrt(pow((a_x - p_x), 2) + pow((a_y - p_y), 2));
35305 
35306  double rhalfca_x = 0.5 * (a_x - c_x);
35307  double rhalfca_y = 0.5 * (a_y - c_y);
35308 
35309  double halfca_squared = pow(rhalfca_x, 2) + pow(rhalfca_y, 2);
35310 
35311  double sticky_out_bit = r - sqrt(std::fabs((r * r) - halfca_squared));
35312 
35313  // If sticky out bit divided by distance between end nodes
35314  // is less than tolerance the boundary is so flat that we
35315  // can safely kill the node
35316  if ((sticky_out_bit / (2.0 * sqrt(halfca_squared))) <
35317  unrefinement_tolerance)
35318  {
35319  do_it = true;
35320  if (check_only)
35321  {
35322  return true;
35323  }
35324  }
35325  }
35326 
35327  // If the vertex was proposed for deletion check that it is
35328  // allowed for being deleted
35329  if (do_it && boundary_receive_connections)
35330  {
35331  // Is the vertex one of the non deletable vertices
35332  for (std::set<Vector<double>>::iterator it = no_delete_vertex.begin();
35333  it != no_delete_vertex.end();
35334  it++)
35335  {
35336  // Compute the distance between the proposed node to delete
35337  // and the ones that should not be deleted
35338  const double x = (*it)[0];
35339  const double y = (*it)[1];
35340  double error = (b_x - x) * (b_x - x) + (b_y - y) * (b_y - y);
35341  error = sqrt(error);
35342 
35343  if (error < ToleranceForVertexMismatchInPolygons::Tolerable_error)
35344  {
35345  // Do not delete the vertex
35346  do_it = false;
35347  break;
35348  }
35349  }
35350 
35351  } // if (do_it && boundary_receive_connections)
35352 
35353  // Remove node?
35354  if (do_it)
35355  {
35356  vector_bnd_vertices[i].resize(0);
35357  }
35358  }
35359 
35360  // Create another vector, which will only contain entries of
35361  // nodes that still exist
35362  Vector<Vector<double>> compact_vector;
35363  compact_vector.reserve(n_vertex);
35364  for (unsigned i = 0; i < n_vertex; i++)
35365  {
35366  // If the entry was not deleted include it in the new vector
35367  if (vector_bnd_vertices[i].size() != 0)
35368  {
35369  compact_vector.push_back(vector_bnd_vertices[i]);
35370  }
35371  }
35372 
35373  /// Get the size of the vector that now includes all remaining nodes
35374  n_vertex = compact_vector.size();
35375 
35376  // If the size of the vector containing the remaining nodes is
35377  // different from the size of the vector before the unrefinement
35378  // routine (with the original nodes)
35379  // then the polyline was obviously updated
35380  if (n_vertex != vector_bnd_vertices.size())
35381  {
35382  unrefinement_was_performed = true;
35383  }
35384 
35385  /// Copy back
35386  vector_bnd_vertices.resize(n_vertex);
35387  for (unsigned i = 0; i < n_vertex; i++)
35388  {
35389  vector_bnd_vertices[i].resize(3);
35390  vector_bnd_vertices[i][0] = compact_vector[i][0];
35391  vector_bnd_vertices[i][1] = compact_vector[i][1];
35392  vector_bnd_vertices[i][2] = compact_vector[i][2];
35393  }
35394 
35395  return unrefinement_was_performed;
35396  }
35397 
35398  //=========================================================================
35399  /// Helper function that performs the refinement process
35400  /// on the specified boundary by using the provided vertices
35401  /// representation. Optional boolean is used to run it as test only (if
35402  /// true is specified as input) in which case vertex coordinates aren't
35403  /// actually modified. Returned boolean indicates if polyline was (or
35404  /// would have been -- if called with check_only=false) changed.
35405  //=========================================================================
35406  template<class ELEMENT>
35408  Mesh* face_mesh_pt,
35409  Vector<Vector<double>>& vector_bnd_vertices,
35410  double& refinement_tolerance,
35411  const bool& check_only)
35412  {
35413  // Boolean that indicates whether an actual update of the vertex
35414  // coordinates was performed or not
35415  bool refinement_was_performed = false;
35416 
35417  // Create a geometric object from the mesh to represent
35418  // the curvilinear boundary
35419  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
35420 
35421  // Get the total number of current vertices
35422  unsigned n_vertex = vector_bnd_vertices.size();
35423 
35424  // Create a new (temporary) vector for the nodes, so
35425  // that new nodes can be stored
35426  Vector<Vector<double>> extended_vector;
35427 
35428  // Reserve memory space for twice the number of already
35429  // existing nodes (worst case)
35430  extended_vector.reserve(2 * n_vertex);
35431 
35432  // Loop over the nodes until the last but one node
35433  for (unsigned inod = 0; inod < n_vertex - 1; inod++)
35434  {
35435  // Get local coordinate of "left" node
35436  double zeta_left = vector_bnd_vertices[inod][0];
35437 
35438  // Get position vector of "left" node
35439  Vector<double> R_left(2);
35440  for (unsigned i = 0; i < 2; i++)
35441  {
35442  R_left[i] = vector_bnd_vertices[inod][i + 1];
35443  }
35444 
35445  // Get local coordinate of "right" node
35446  double zeta_right = vector_bnd_vertices[inod + 1][0];
35447 
35448  // Get position vector of "right" node
35449  Vector<double> R_right(2);
35450  for (unsigned i = 0; i < 2; i++)
35451  {
35452  R_right[i] = vector_bnd_vertices[inod + 1][i + 1];
35453  }
35454 
35455  // Get the boundary coordinate of the midpoint
35456  Vector<double> zeta_mid(1);
35457  zeta_mid[0] = 0.5 * (zeta_left + zeta_right);
35458 
35459  // Get the position vector of the midpoint on the
35460  // curvilinear boundary
35461  Vector<double> R_mid(2);
35462  mesh_geom_obj_pt->position(zeta_mid, R_mid);
35463 
35464  // Get the position vector of the midpoint on the straight
35465  // line connecting "left" and "right" node
35466  Vector<double> R_mid_polygon(2);
35467  for (unsigned i = 0; i < 2; i++)
35468  {
35469  R_mid_polygon[i] = 0.5 * (R_right[i] + R_left[i]);
35470  }
35471 
35472  // Calculate the distance between the midpoint on the curvilinear
35473  // boundary and the midpoint on the straight line
35474  double distance =
35475  sqrt((R_mid[0] - R_mid_polygon[0]) * (R_mid[0] - R_mid_polygon[0]) +
35476  (R_mid[1] - R_mid_polygon[1]) * (R_mid[1] - R_mid_polygon[1]));
35477 
35478  // Calculating the length of the straight line
35479  double length = sqrt((R_right[0] - R_left[0]) * (R_right[0] - R_left[0]) +
35480  (R_right[1] - R_left[1]) * (R_right[1] - R_left[1]));
35481 
35482  // If the ratio of distance between the midpoints to the length
35483  // of the straight line is larger than the tolerance
35484  // specified for the criterion when points can be deleted,
35485  // create a new node and add it to the (temporary) vector
35486  if ((distance / length) > refinement_tolerance)
35487  {
35488  if (check_only)
35489  {
35490  // Delete the allocated memory for the geometric object
35491  // that represents the curvilinear boundary
35492  delete mesh_geom_obj_pt;
35493  return true;
35494  }
35495 
35496  Vector<double> new_node(3);
35497  new_node[0] = zeta_mid[0];
35498  new_node[1] = R_mid[0];
35499  new_node[2] = R_mid[1];
35500 
35501  // Include the "left" node in the new "temporary" vector
35502  extended_vector.push_back(vector_bnd_vertices[inod]);
35503 
35504  // Include the new node as well
35505  extended_vector.push_back(new_node);
35506  }
35507  else
35508  {
35509  // Include the "left" node in the new "temporary" vector
35510  // and move on to the next node
35511  extended_vector.push_back(vector_bnd_vertices[inod]);
35512  }
35513  } // end of loop over nodes
35514 
35515  // Add the last node to the vector
35516  extended_vector.push_back(vector_bnd_vertices[n_vertex - 1]);
35517 
35518  /// Get the size of the vector that now includes all added nodes
35519  n_vertex = extended_vector.size();
35520 
35521  // If the size of the vector including the added nodes is
35522  // different from the size of the vector before the refinement
35523  // routine then the polyline was obviously updated
35524  if (n_vertex != vector_bnd_vertices.size())
35525  {
35526  refinement_was_performed = true;
35527  }
35528 
35529  // Copy across
35530  vector_bnd_vertices.resize(n_vertex);
35531  for (unsigned i = 0; i < n_vertex; i++)
35532  {
35533  vector_bnd_vertices[i].resize(3);
35534  vector_bnd_vertices[i][0] = extended_vector[i][0];
35535  vector_bnd_vertices[i][1] = extended_vector[i][1];
35536  vector_bnd_vertices[i][2] = extended_vector[i][2];
35537  }
35538 
35539  // Delete the allocated memory for the geometric object
35540  // that represents the curvilinear boundary
35541  delete mesh_geom_obj_pt;
35542 
35543  return refinement_was_performed;
35544  }
35545 
35546  //=========================================================================
35547  // Helper function that applies the maximum length constraint
35548  // when it was specified. This will increase the number of points in
35549  // the current curve section in case that any segment on it does not
35550  // fulfils the requirement
35551  //=========================================================================
35552  template<class ELEMENT>
35554  Mesh* face_mesh_pt,
35555  Vector<Vector<double>>& vector_bnd_vertices,
35556  double& max_length_constraint)
35557  {
35558  // Boolean that indicates whether an actual update of the vertex
35559  // coordinates was performed or not
35560  bool max_length_applied = false;
35561 
35562  // Create a geometric object from the mesh to represent
35563  // the curvilinear boundary
35564  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
35565 
35566  // Get the total number of current vertices
35567  unsigned n_vertex = vector_bnd_vertices.size();
35568 
35569  // Create a new (temporary) vector for the nodes, so
35570  // that new nodes can be stored
35571  Vector<Vector<double>> extended_vector;
35572 
35573  // Loop over the nodes until the last but one node
35574  for (unsigned inod = 0; inod < n_vertex - 1; inod++)
35575  {
35576  // Get local coordinate of "left" node
35577  double zeta_left = vector_bnd_vertices[inod][0];
35578 
35579  // Get position vector of "left" node
35580  Vector<double> R_left(2);
35581  for (unsigned i = 0; i < 2; i++)
35582  {
35583  R_left[i] = vector_bnd_vertices[inod][i + 1];
35584  }
35585 
35586  // Get local coordinate of "right" node
35587  double zeta_right = vector_bnd_vertices[inod + 1][0];
35588 
35589  // Get position vector of "right" node
35590  Vector<double> R_right(2);
35591  for (unsigned i = 0; i < 2; i++)
35592  {
35593  R_right[i] = vector_bnd_vertices[inod + 1][i + 1];
35594  }
35595 
35596  // Include the "left" node in the new "temporary" vector
35597  extended_vector.push_back(vector_bnd_vertices[inod]);
35598 
35599  // Check whether the current distance between the left and right node
35600  // is longer than the specified constraint or not
35601  double length = std::fabs(zeta_right - zeta_left);
35602 
35603  // Do we need to introduce new nodes?
35604  if (length > max_length_constraint)
35605  {
35606  double n_pts = length / max_length_constraint;
35607  // We only want the integer part
35608  unsigned n_points = static_cast<unsigned>(n_pts);
35609  double zeta_increment =
35610  (zeta_right - zeta_left) / ((double)n_points + 1);
35611 
35612  Vector<double> zeta(1);
35613  // Create the n_points+1 points inside the segment
35614  for (unsigned s = 1; s < n_points + 1; s++)
35615  {
35616  // Get the coordinates
35617  zeta[0] = zeta_left + zeta_increment * double(s);
35618  Vector<double> vertex(2);
35619  mesh_geom_obj_pt->position(zeta, vertex);
35620 
35621  // Create the new node
35622  Vector<double> new_node(3);
35623  new_node[0] = zeta[0];
35624  new_node[1] = vertex[0];
35625  new_node[2] = vertex[1];
35626 
35627  // Include the new node
35628  extended_vector.push_back(new_node);
35629  }
35630  }
35631  }
35632 
35633  // Add the last node to the vector
35634  extended_vector.push_back(vector_bnd_vertices[n_vertex - 1]);
35635 
35636  /// Get the size of the vector that now includes all added nodes
35637  n_vertex = extended_vector.size();
35638 
35639  // If the size of the vector including the added nodes is
35640  // different from the size of the vector before applying the maximum length
35641  // constraint then the polyline was obviously updated
35642  if (n_vertex != vector_bnd_vertices.size())
35643  {
35644  max_length_applied = true;
35645  }
35646 
35647  // Copy across
35648  vector_bnd_vertices.resize(n_vertex);
35649  for (unsigned i = 0; i < n_vertex; i++)
35650  {
35651  vector_bnd_vertices[i].resize(3);
35652  vector_bnd_vertices[i][0] = extended_vector[i][0];
35653  vector_bnd_vertices[i][1] = extended_vector[i][1];
35654  vector_bnd_vertices[i][2] = extended_vector[i][2];
35655  }
35656 
35657  // Delete the allocated memory for the geometric object
35658  // that represents the curvilinear boundary
35659  delete mesh_geom_obj_pt;
35660 
35661  return max_length_applied;
35662  }
35663 
35664  //=========================================================================
35665  /// Helper function
35666  /// Creates an unsorted face mesh representation from the specified
35667  /// boundary id. It means that the elements are not sorted along the
35668  /// boundary
35669  //=========================================================================
35670  template<class ELEMENT>
35672  create_unsorted_face_mesh_representation(const unsigned& boundary_id,
35673  Mesh* face_mesh_pt)
35674  {
35675  // Create a face mesh adjacent to specified boundary.
35676  // The face mesh consists of FaceElements that may also be
35677  // interpreted as GeomObjects
35678 
35679  // Build the face mesh
35680  this->template build_face_mesh<ELEMENT, FaceElementAsGeomObject>(
35681  boundary_id, face_mesh_pt);
35682 
35683  // Find the total number of added elements
35684  unsigned n_element = face_mesh_pt->nelement();
35685  // Loop over the elements
35686  for (unsigned e = 0; e < n_element; e++)
35687  {
35688  // Cast the element pointer to the correct thing!
35689  FaceElementAsGeomObject<ELEMENT>* el_pt =
35690  dynamic_cast<FaceElementAsGeomObject<ELEMENT>*>(
35691  face_mesh_pt->element_pt(e));
35692 
35693  // Set bulk boundary number
35694  el_pt->set_boundary_number_in_bulk_mesh(boundary_id);
35695  }
35696  }
35697 
35698  //=========================================================================
35699  /// Helper function
35700  /// Creates a sorted face mesh representation of the specified PolyLine
35701  /// It means that the elements are sorted along the boundary
35702  //=========================================================================
35703  template<class ELEMENT>
35705  const unsigned& boundary_id,
35706  Mesh* face_mesh_pt,
35707  std::map<FiniteElement*, bool>& is_inverted,
35708  bool& inverted_face_mesh)
35709  {
35710  Mesh* tmp_unsorted_face_mesh_pt = new Mesh();
35711 
35712  // First step we get the unsorted version of the face mesh
35713  create_unsorted_face_mesh_representation(boundary_id,
35714  tmp_unsorted_face_mesh_pt);
35715 
35716  // Once with the unsorted version of the face mesh
35717  // only left to sort it out!!!
35718 
35719  // Put all face elements in order
35720  //-------------------------------
35721 
35722  // Put first element into ordered list
35723  // Temporal list for sorting the elements
35724  std::list<FiniteElement*> sorted_el_pt;
35725  FiniteElement* el_pt = tmp_unsorted_face_mesh_pt->finite_element_pt(0);
35726  sorted_el_pt.push_back(el_pt);
35727 
35728  // Number of nodes
35729  unsigned nnod = el_pt->nnode();
35730 
35731  // Count elements that have been done
35732  unsigned count_done = 0;
35733 
35734  // How many face elements are there?
35735  unsigned n_face_element = tmp_unsorted_face_mesh_pt->nelement();
35736 
35737  // Keep track of who's done
35738  std::map<FiniteElement*, bool> done_el;
35739 
35740  is_inverted.clear();
35741 
35742  // Fit in the other elements in at most nel^2 loops
35743  for (unsigned ee = 1; ee < n_face_element; ee++)
35744  {
35745  // Loop over all elements to check if they fit to the right
35746  // or the left of the current one
35747  for (unsigned e = 1; e < n_face_element; e++)
35748  {
35749  // Candidate element
35750  el_pt = tmp_unsorted_face_mesh_pt->finite_element_pt(e);
35751 
35752  // Is it done yet?
35753  if (!done_el[el_pt])
35754  {
35755  // Left and rightmost elements
35756  FiniteElement* first_el_pt = (*sorted_el_pt.begin());
35757  std::list<FiniteElement*>::iterator it = sorted_el_pt.end();
35758  it--;
35759  FiniteElement* last_el_pt = *it;
35760 
35761  // Left and rightmost nodes
35762  Node* left_node_pt = first_el_pt->node_pt(0);
35763  if (is_inverted[first_el_pt])
35764  {
35765  left_node_pt = first_el_pt->node_pt(nnod - 1);
35766  }
35767  Node* right_node_pt = last_el_pt->node_pt(nnod - 1);
35768  if (is_inverted[last_el_pt])
35769  {
35770  right_node_pt = last_el_pt->node_pt(0);
35771  }
35772 
35773  // New element fits at the left of first element and is not inverted
35774  if (left_node_pt == el_pt->node_pt(nnod - 1))
35775  {
35776  sorted_el_pt.push_front(el_pt);
35777  done_el[el_pt] = true;
35778  count_done++;
35779  is_inverted[el_pt] = false;
35780  }
35781  // New element fits at the left of first element and is inverted
35782 
35783  else if (left_node_pt == el_pt->node_pt(0))
35784  {
35785  sorted_el_pt.push_front(el_pt);
35786  done_el[el_pt] = true;
35787  count_done++;
35788  is_inverted[el_pt] = true;
35789  }
35790  // New element fits on the right of last element and is not inverted
35791 
35792  else if (right_node_pt == el_pt->node_pt(0))
35793  {
35794  sorted_el_pt.push_back(el_pt);
35795  done_el[el_pt] = true;
35796  count_done++;
35797  is_inverted[el_pt] = false;
35798  }
35799  // New element fits on the right of last element and is inverted
35800 
35801  else if (right_node_pt == el_pt->node_pt(nnod - 1))
35802  {
35803  sorted_el_pt.push_back(el_pt);
35804  done_el[el_pt] = true;
35805  count_done++;
35806  is_inverted[el_pt] = true;
35807  }
35808 
35809  if (done_el[el_pt])
35810  {
35811  break;
35812  }
35813  }
35814  }
35815  }
35816 
35817  // Are we done?
35818  if (count_done != (n_face_element - 1))
35819  {
35820  std::ostringstream error_message;
35821  error_message << "When ordering FaceElements on "
35822  << "boundary " << boundary_id << " only managed to order \n"
35823  << count_done << " of " << n_face_element
35824  << " face elements.\n"
35825  << std::endl;
35826  throw OomphLibError(
35827  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
35828  }
35829 
35830  // Now make a mesh that contains the FaceElements in order
35831  // Remember that we currently have a list, not a mesh of sorted elements
35832 
35833  // Fill it
35834  for (std::list<FiniteElement*>::iterator it = sorted_el_pt.begin();
35835  it != sorted_el_pt.end();
35836  it++)
35837  {
35838  // Get element
35839  FiniteElement* el_pt = *it;
35840 
35841  // add this face element to the order original mesh
35842  face_mesh_pt->add_element_pt(el_pt);
35843  }
35844 
35845  // Verify if face mesh representation is not inverted according to the
35846  // polyline specified by the user, it means that the initial and the
35847  // final vertex does really correspond to the first and last vertex
35848  // respectively, if not, state that the face mesh representation is
35849  // inverted
35850 
35851  // Get the associated polyline representation to the boundary
35852  TriangleMeshPolyLine* bnd_polyline =
35853  this->Boundary_curve_section_pt[boundary_id];
35854 
35855  // Get the really first vertex
35856  Vector<double> first_vertex = bnd_polyline->vertex_coordinate(0);
35857 
35858  // Now get the first node based on the face mesh representation
35859  // First get access to the first element
35860  FiniteElement* first_el_pt = face_mesh_pt->finite_element_pt(0);
35861 
35862  // Now get access to the first node
35863  unsigned n_node = first_el_pt->nnode();
35864  // Get the very first node (taking into account if it is
35865  // inverted or not!!)
35866  Node* first_node_pt = first_el_pt->node_pt(0);
35867  if (is_inverted[first_el_pt])
35868  {
35869  first_node_pt = first_el_pt->node_pt(n_node - 1);
35870  }
35871 
35872  double error = (first_node_pt->x(0) - first_vertex[0]) *
35873  (first_node_pt->x(0) - first_vertex[0]) +
35874  (first_node_pt->x(1) - first_vertex[1]) *
35875  (first_node_pt->x(1) - first_vertex[1]);
35876 
35877  error = sqrt(error);
35878 
35879  if (error < ToleranceForVertexMismatchInPolygons::Tolerable_error)
35880  {
35881  inverted_face_mesh = false;
35882  }
35883  else
35884  {
35885  inverted_face_mesh = true;
35886  }
35887  }
35888 
35889  //=========================================================================
35890  /// Helper function to construct face mesh representation of all polylines,
35891  /// possibly with segments re-distributed between polylines
35892  /// to maintain an approximately even sub-division of the polygon
35893  //=========================================================================
35894  template<class ELEMENT>
35896  TriangleMeshPolygon* polygon_pt, Vector<Mesh*>& face_mesh_pt)
35897  {
35898  // Number of polylines
35899  unsigned n_polyline = polygon_pt->npolyline();
35900  face_mesh_pt.resize(n_polyline);
35901 
35902  // Are we eligible for re-distributing polyline segments between
35903  // polylines? We're not if any of the boundaries are associated
35904  // with a GeomObject because we're then tied to the start and
35905  // end coordinates along it.
35906  bool eligible_for_segment_redistribution = true;
35907 
35908  // Loop over constituent polylines
35909  for (unsigned p = 0; p < n_polyline; p++)
35910  {
35911  // Get the boundary id of the polyline
35912  unsigned bound = polygon_pt->polyline_pt(p)->boundary_id();
35913 
35914  // If the boundary has a geometric object representation then
35915  // we can't redistribute
35916  GeomObject* const geom_object_pt = this->boundary_geom_object_pt(bound);
35917  if (geom_object_pt != 0)
35918  {
35919  eligible_for_segment_redistribution = false;
35920  }
35921 
35922  face_mesh_pt[p] = new Mesh();
35923  create_unsorted_face_mesh_representation(bound, face_mesh_pt[p]);
35924  }
35925 
35926  if (!polygon_pt->is_redistribution_of_segments_between_polylines_enabled())
35927  {
35928  return;
35929  }
35930 
35931  // If there is more than one region we have to think... Die for now.
35932  if (this->nregion() > 1)
35933  {
35934  std::ostringstream warn_message;
35935  warn_message
35936  << "Can't currently re-distribute segments between polylines if there\n"
35937  << "are multiple regions; returning..." << std::endl;
35938  OomphLibWarning(warn_message.str(),
35939  "RefineableTriangleMesh::get_face_mesh_representation()",
35940  OOMPH_EXCEPTION_LOCATION);
35941  return;
35942  }
35943 
35944  // Redistribution overruled
35945  if (!eligible_for_segment_redistribution)
35946  {
35947  std::ostringstream warn_message;
35948  warn_message
35949  << "Over-ruling re-distribution of segments between polylines\n"
35950  << "because at least one boundary is associated with a GeomObject."
35951  << "Returning..." << std::endl;
35952  OomphLibWarning(warn_message.str(),
35953  "RefineableTriangleMesh::get_face_mesh_representation()",
35954  OOMPH_EXCEPTION_LOCATION);
35955  return;
35956  }
35957 
35958  // Create a vector for ordered face mesh
35959  Vector<Mesh*> ordered_face_mesh_pt(n_polyline);
35960 
35961  // Storage for the total arclength of polygon
35962  double s_total = 0.0;
35963 
35964  // Storage for first and last nodes on polylines so we can figure
35965  // out if they are inverted relative to each other
35966  Vector<Node*> first_polyline_node_pt(n_polyline);
35967  Vector<Node*> last_polyline_node_pt(n_polyline);
35968  std::vector<bool> is_reversed(n_polyline, false);
35969 
35970  // Loop over constituent polylines
35971  for (unsigned p = 0; p < n_polyline; p++)
35972  {
35973  // Put all face elements in order
35974  //-------------------------------
35975 
35976  // Put first element into ordered list
35977  std::list<FiniteElement*> ordered_el_pt;
35978  FiniteElement* el_pt = face_mesh_pt[p]->finite_element_pt(0);
35979  ordered_el_pt.push_back(el_pt);
35980 
35981  // Number of nodes
35982  unsigned nnod = el_pt->nnode();
35983 
35984  // Default for first and last node on polyline
35985  first_polyline_node_pt[p] = el_pt->node_pt(0);
35986  last_polyline_node_pt[p] = el_pt->node_pt(nnod - 1);
35987 
35988  // Count elements that have been done
35989  unsigned count_done = 0;
35990 
35991  // How many face elements are there?
35992  unsigned n_face_element = face_mesh_pt[p]->nelement();
35993 
35994  // Get the boundary id of the polyline
35995  unsigned bound = polygon_pt->polyline_pt(p)->boundary_id();
35996 
35997  // Keep track of who's done
35998  std::map<FiniteElement*, bool> done_el;
35999 
36000  // Keep track of which element is inverted
36001  std::map<FiniteElement*, bool> is_inverted;
36002 
36003  // Fit in the other elements in at most nel^2 loops
36004  for (unsigned ee = 1; ee < n_face_element; ee++)
36005  {
36006  // Loop over all elements to check if they fit to the right
36007  // or the left of the current one
36008  for (unsigned e = 1; e < n_face_element; e++)
36009  {
36010  // Candidate element
36011  el_pt = face_mesh_pt[p]->finite_element_pt(e);
36012 
36013  // Is it done yet?
36014  if (!done_el[el_pt])
36015  {
36016  // Left and rightmost elements
36017  FiniteElement* first_el_pt = (*ordered_el_pt.begin());
36018  std::list<FiniteElement*>::iterator it = ordered_el_pt.end();
36019  it--;
36020  FiniteElement* last_el_pt = *it;
36021 
36022  // Left and rightmost nodes
36023  Node* left_node_pt = first_el_pt->node_pt(0);
36024  if (is_inverted[first_el_pt])
36025  {
36026  left_node_pt = first_el_pt->node_pt(nnod - 1);
36027  }
36028  Node* right_node_pt = last_el_pt->node_pt(nnod - 1);
36029  if (is_inverted[last_el_pt])
36030  {
36031  right_node_pt = last_el_pt->node_pt(0);
36032  }
36033 
36034  // New element fits at the left of first element and is not inverted
36035  if (left_node_pt == el_pt->node_pt(nnod - 1))
36036  {
36037  ordered_el_pt.push_front(el_pt);
36038  done_el[el_pt] = true;
36039  count_done++;
36040  is_inverted[el_pt] = false;
36041  first_polyline_node_pt[p] = el_pt->node_pt(0);
36042  }
36043  // New element fits at the left of first element and is inverted
36044 
36045  else if (left_node_pt == el_pt->node_pt(0))
36046  {
36047  ordered_el_pt.push_front(el_pt);
36048  done_el[el_pt] = true;
36049  count_done++;
36050  is_inverted[el_pt] = true;
36051  first_polyline_node_pt[p] = el_pt->node_pt(nnod - 1);
36052  }
36053  // New element fits on the right of last element and is not inverted
36054 
36055  else if (right_node_pt == el_pt->node_pt(0))
36056  {
36057  ordered_el_pt.push_back(el_pt);
36058  done_el[el_pt] = true;
36059  count_done++;
36060  is_inverted[el_pt] = false;
36061  last_polyline_node_pt[p] = el_pt->node_pt(nnod - 1);
36062  }
36063  // New element fits on the right of last element and is inverted
36064 
36065  else if (right_node_pt == el_pt->node_pt(nnod - 1))
36066  {
36067  ordered_el_pt.push_back(el_pt);
36068  done_el[el_pt] = true;
36069  count_done++;
36070  is_inverted[el_pt] = true;
36071  last_polyline_node_pt[p] = el_pt->node_pt(0);
36072  }
36073 
36074  if (done_el[el_pt])
36075  {
36076  break;
36077  }
36078  }
36079  }
36080  }
36081 
36082  // Are we done?
36083  if (count_done != (n_face_element - 1))
36084  {
36085  std::ostringstream error_message;
36086  error_message << "When ordering FaceElements on "
36087  << "boundary " << bound << " only managed to order \n"
36088  << count_done << " of " << n_face_element
36089  << " face elements.\n"
36090  << std::endl;
36091  throw OomphLibError(error_message.str(),
36092  OOMPH_CURRENT_FUNCTION,
36093  OOMPH_EXCEPTION_LOCATION);
36094  }
36095 
36096  // Now make a mesh that contains the FaceElements in order
36097  ordered_face_mesh_pt[p] = new Mesh;
36098 
36099  // Fill it
36100  for (std::list<FiniteElement*>::iterator it = ordered_el_pt.begin();
36101  it != ordered_el_pt.end();
36102  it++)
36103  {
36104  // Get element
36105  FiniteElement* el_pt = *it;
36106 
36107  // add this face element to the order original mesh
36108  ordered_face_mesh_pt[p]->add_element_pt(el_pt);
36109  }
36110 
36111  // Get the arclength along the polygon
36112  for (unsigned e = 0; e < n_face_element; ++e)
36113  {
36114  FiniteElement* el_pt = ordered_face_mesh_pt[p]->finite_element_pt(e);
36115  unsigned n_node = el_pt->nnode();
36116  double element_length_squared = 0.0;
36117  for (unsigned i = 0; i < 2; i++)
36118  {
36119  element_length_squared +=
36120  pow(el_pt->node_pt(n_node - 1)->x(i) - el_pt->node_pt(0)->x(i), 2);
36121  }
36122 
36123  // Determine element length
36124  double element_length = sqrt(element_length_squared);
36125 
36126  // Add this length to the total arclength
36127  s_total += element_length;
36128  }
36129 
36130  // Empty the original meshes
36131  face_mesh_pt[p]->flush_element_and_node_storage();
36132  }
36133 
36134  // Is first one reversed?
36135  if ((last_polyline_node_pt[0] == first_polyline_node_pt[1]) ||
36136  (last_polyline_node_pt[0] == last_polyline_node_pt[1]))
36137  {
36138  is_reversed[0] = false;
36139  }
36140  else if ((first_polyline_node_pt[0] == first_polyline_node_pt[1]) ||
36141  (first_polyline_node_pt[0] == last_polyline_node_pt[1]))
36142  {
36143  is_reversed[0] = true;
36144  }
36145 
36146  // Reorder the face meshes so that they are contiguous
36147  Vector<Mesh*> tmp_face_mesh_pt(n_polyline);
36148  std::vector<bool> mesh_done(n_polyline, false);
36149  Vector<unsigned> old_polyline_number(n_polyline);
36150 
36151  // Initial entry
36152  tmp_face_mesh_pt[0] = ordered_face_mesh_pt[0];
36153  unsigned current = 0;
36154  old_polyline_number[0] = 0;
36155  unsigned count_found = 0;
36156 
36157  // Fill in the next entries
36158  for (unsigned p = 1; p < n_polyline; p++)
36159  {
36160  Node* end_node_pt = last_polyline_node_pt[current];
36161  if (is_reversed[current])
36162  {
36163  end_node_pt = first_polyline_node_pt[current];
36164  }
36165 
36166  // Loop over all remaining face meshes to see which one fits
36167  for (unsigned pp = 1; pp < n_polyline; pp++)
36168  {
36169  if (!mesh_done[pp])
36170  {
36171  // Current one is not reversed, candidate is not reversed
36172  if ((!is_reversed[current]) &&
36173  (end_node_pt == first_polyline_node_pt[pp]))
36174  {
36175  tmp_face_mesh_pt[p] = ordered_face_mesh_pt[pp];
36176  mesh_done[pp] = true;
36177  is_reversed[pp] = false;
36178  old_polyline_number[p] = pp;
36179  current = pp;
36180  count_found++;
36181  break;
36182  }
36183  // Current one is not reversed, candidate is reversed
36184 
36185  else if ((!is_reversed[current]) &&
36186  (end_node_pt == last_polyline_node_pt[pp]))
36187  {
36188  tmp_face_mesh_pt[p] = ordered_face_mesh_pt[pp];
36189  mesh_done[pp] = true;
36190  is_reversed[pp] = true;
36191  old_polyline_number[p] = pp;
36192  current = pp;
36193  count_found++;
36194  break;
36195  }
36196  // Current one is reversed, candidate is not reversed
36197 
36198  else if ((is_reversed[current]) &&
36199  (end_node_pt == first_polyline_node_pt[pp]))
36200  {
36201  tmp_face_mesh_pt[p] = ordered_face_mesh_pt[pp];
36202  mesh_done[pp] = true;
36203  is_reversed[pp] = false;
36204  old_polyline_number[p] = pp;
36205  current = pp;
36206  count_found++;
36207  break;
36208  }
36209  // Current one is reversed, candidate is reversed
36210 
36211  else if ((is_reversed[current]) &&
36212  (end_node_pt == last_polyline_node_pt[pp]))
36213  {
36214  tmp_face_mesh_pt[p] = ordered_face_mesh_pt[pp];
36215  mesh_done[pp] = true;
36216  is_reversed[pp] = true;
36217  old_polyline_number[p] = pp;
36218  current = pp;
36219  count_found++;
36220  break;
36221  }
36222  }
36223  }
36224  }
36225 
36226 #ifdef PARANOID
36227  if (count_found != n_polyline - 1)
36228  {
36229  std::ostringstream error_message;
36230  error_message << "Only found " << count_found << " out of "
36231  << n_polyline - 1 << " polylines to be fitted in.\n";
36232  throw OomphLibError(
36233  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
36234  }
36235 #endif
36236 
36237  // Now overwrite the re-ordered data
36238  for (unsigned i = 0; i < n_polyline; i++)
36239  {
36240  ordered_face_mesh_pt[i] = tmp_face_mesh_pt[i];
36241  }
36242 
36243  // Now do an approximate equidistribution of polylines
36244  //----------------------------------------------------
36245  double s = 0.0;
36246  unsigned new_face_id = 0;
36247 
36248  // Matrix map to indicate if node must not be removed from specified
36249  // boundary (!=0) or not (=0). Initialises itself to zero
36250  std::map<Node*, std::map<unsigned, unsigned>>
36251  node_must_not_be_removed_from_boundary_flag;
36252 
36253  // Loop over the old face mesh
36254  for (unsigned p = 0; p < n_polyline; p++)
36255  {
36256  // Loop over the face elements
36257  unsigned n_face_element = ordered_face_mesh_pt[p]->nelement();
36258  for (unsigned e = 0; e < n_face_element; e++)
36259  {
36260  unsigned el_number = e;
36261  if (is_reversed[p])
36262  {
36263  el_number = n_face_element - e - 1;
36264  }
36265 
36266  FiniteElement* el_pt =
36267  ordered_face_mesh_pt[p]->finite_element_pt(el_number);
36268  unsigned n_node = el_pt->nnode();
36269 
36270  // Determine element length
36271  double element_length_squared = 0.0;
36272  for (unsigned i = 0; i < 2; i++)
36273  {
36274  element_length_squared +=
36275  pow(el_pt->node_pt(n_node - 1)->x(i) - el_pt->node_pt(0)->x(i), 2);
36276  }
36277  double element_length = sqrt(element_length_squared);
36278 
36279  // Add this length to the total arclength
36280  s += element_length;
36281 
36282  // Check if the current 'arclength' is less than the
36283  // whole 'arclength' divided by the number of polylines
36284  if (s < s_total / double(n_polyline) + 1e-6)
36285  {
36286  // If so add this face element to the new face mesh
36287  face_mesh_pt[new_face_id]->add_element_pt(el_pt);
36288 
36289  unsigned bound_old =
36290  polygon_pt->polyline_pt(old_polyline_number[p])->boundary_id();
36291 
36292  unsigned bound_new =
36293  polygon_pt->polyline_pt(new_face_id)->boundary_id();
36294 
36295  // Loop over the nodes in the element
36296  for (unsigned i = 0; i < n_node; i++)
36297  {
36298  // Get the pointer to the node
36299  Node* nod_pt = el_pt->node_pt(i);
36300 
36301  // If the two boundary id's are different, the face element's nodes
36302  // have to be added to the new boundary
36303  if (bound_new != bound_old)
36304  {
36305  // Add it to the new boundary
36306  add_boundary_node(bound_new, nod_pt);
36307 
36308  // We are happy for this node to be removed from the
36309  // old boundary?
36310  node_must_not_be_removed_from_boundary_flag[nod_pt][bound_old] +=
36311  0;
36312  }
36313 
36314  // If the face element hasn't moved, its nodes MUST remain
36315  // on that boundary (incl. any nodes that ar shared by
36316  // FaceElements that have moved (see above)
36317 
36318  else
36319  {
36320  node_must_not_be_removed_from_boundary_flag[nod_pt][bound_old] +=
36321  1;
36322  }
36323  }
36324  }
36325 
36326  // If not, reset the current 'arclength' to zero,
36327  // increase the new face id by one and go one element
36328  // back by decreasing e by one to make sure the current
36329  // element gets added to the next face mesh
36330 
36331  else
36332  {
36333  if (new_face_id != n_polyline - 1)
36334  {
36335  s = 0.0;
36336  new_face_id++;
36337  --e;
36338  }
36339  else
36340  {
36341  s = 0.0;
36342  --e;
36343  }
36344  }
36345  }
36346  } // end of loop over all polylines -- they are now re-distributed
36347 
36348 
36349  // Loop over all nodes on the boundaries of the polygon to remove
36350  // nodes from boundaries they are no longer on
36351  unsigned move_count = 0;
36352  for (std::map<Node*, std::map<unsigned, unsigned>>::iterator it =
36353  node_must_not_be_removed_from_boundary_flag.begin();
36354  it != node_must_not_be_removed_from_boundary_flag.end();
36355  it++)
36356  {
36357  // Get the node
36358  Node* nod_pt = (*it).first;
36359 
36360  // Now we loop over the boundaries that this node is on
36361  for (std::map<unsigned, unsigned>::iterator it_2 = (*it).second.begin();
36362  it_2 != (*it).second.end();
36363  it_2++)
36364  {
36365  // Get the boundary id
36366  unsigned bound = (*it_2).first;
36367 
36368  // Remove it from that boundary?
36369  if ((*it_2).second == 0)
36370  {
36371  remove_boundary_node(bound, nod_pt);
36372  move_count++;
36373  }
36374  }
36375  }
36376 
36377  // Loop over the new face mesh to assign new boundary IDs
36378  for (unsigned p = 0; p < n_polyline; p++)
36379  {
36380  // Get the boundary id of the polyline
36381  unsigned bound = polygon_pt->polyline_pt(p)->boundary_id();
36382 
36383  // Loop over the face elements
36384  unsigned n_face_element = face_mesh_pt[p]->nelement();
36385  for (unsigned e = 0; e < n_face_element; e++)
36386  {
36387  // Cast the element pointer to the correct thing!
36388  FaceElementAsGeomObject<ELEMENT>* el_pt =
36389  dynamic_cast<FaceElementAsGeomObject<ELEMENT>*>(
36390  face_mesh_pt[p]->element_pt(e));
36391 
36392  // Set bulk boundary number
36393  el_pt->set_boundary_number_in_bulk_mesh(bound);
36394  }
36395  }
36396 
36397  // Update look-up for elements next to boundary
36398  setup_boundary_element_info();
36399 
36400  // Now re-create the boundary coordinates
36401  for (unsigned p = 0; p < n_polyline; p++)
36402  {
36403  // Get the boundary id of the polyline
36404  unsigned bound = polygon_pt->polyline_pt(p)->boundary_id();
36405 
36406  // Do it
36407  this->template setup_boundary_coordinates<ELEMENT>(bound);
36408  }
36409 
36410  // Clean up
36411  for (unsigned p = 0; p < n_polyline; p++)
36412  {
36413  // Flush the nodes from the face mesh to make sure we
36414  // don't delete them (the face mesh that we're returning from here
36415  // still needs them!)
36416  ordered_face_mesh_pt[p]->flush_element_and_node_storage();
36417  delete ordered_face_mesh_pt[p];
36418  }
36419  }
36420 
36421  //=========================================================================
36422  /// Helper function to construct face mesh representation of all polylines
36423  //=========================================================================
36424  template<class ELEMENT>
36426  TriangleMeshOpenCurve* open_polyline_pt, Vector<Mesh*>& face_mesh_pt)
36427  {
36428  // Number of polylines
36429  unsigned n_polyline = open_polyline_pt->ncurve_section();
36430  face_mesh_pt.resize(n_polyline);
36431 
36432  // Loop over constituent polylines
36433  for (unsigned p = 0; p < n_polyline; p++)
36434  {
36435  // Get the boundary id of the polyline
36436  unsigned bound = open_polyline_pt->curve_section_pt(p)->boundary_id();
36437 
36438  face_mesh_pt[p] = new Mesh();
36439  create_unsorted_face_mesh_representation(bound, face_mesh_pt[p]);
36440  }
36441  }
36442 
36443  //======================================================================
36444  /// Update the PSLG that define the inner boundaries of the mesh.
36445  /// Optional boolean is used to run it as test only (if
36446  /// true is specified as input) in which case PSLG isn't actually
36447  /// modified. Returned boolean indicates if PSLG was (or would have
36448  /// been -- if called with check_only=false) changed.
36449  //======================================================================
36450  template<class ELEMENT>
36452  ELEMENT>::surface_remesh_for_inner_hole_boundaries(Vector<Vector<double>>&
36453  internal_point_coord,
36454  const bool& check_only)
36455  {
36456  // Boolean to indicate whether an actual update of the internal
36457  // holes was performed
36458  bool update_was_performed = false;
36459  // Loop over the number of internal boundaries
36460  unsigned n_hole = internal_point_coord.size();
36461  for (unsigned ihole = 0; ihole < n_hole; ihole++)
36462  {
36463  // Cache the pointer to the polygon representation
36464  TriangleMeshPolygon* const poly_pt = this->Internal_polygon_pt[ihole];
36465 
36466 
36467  // Can the polygon update its own configuration, in which case this
36468  // is easy
36469  if (poly_pt->can_update_reference_configuration())
36470  {
36471  poly_pt->reset_reference_configuration();
36472 
36473  // Initialize Vector hole_coordinates
36474  internal_point_coord[ihole].resize(2);
36475 
36476  // Get the vector of hole coordinates
36477  internal_point_coord[ihole] = poly_pt->internal_point();
36478  }
36479  // Otherwise we have to work much harder
36480 
36481  else
36482  {
36483  // if we only want to check whether an update of the inner
36484  // hole is necessary
36485  if (check_only)
36486  {
36487  // is it necessary?
36488  bool update_necessary =
36489  this->update_polygon_using_face_mesh(poly_pt, check_only);
36490 
36491  // Yes?
36492  if (update_necessary)
36493  {
36494  // then we have to adaptand return 'true'
36495  return true;
36496  }
36497  }
36498  // if we not only want to check, then we actually perform
36499  // the update
36500  else
36501  {
36502  update_was_performed = this->update_polygon_using_face_mesh(poly_pt);
36503  }
36504 
36505  // Now we need to sort out the hole coordinates
36506  if (!poly_pt->internal_point().empty())
36507  {
36508  // If fixed don't update and simply
36509  // Read out the existing value
36510  if (poly_pt->is_internal_point_fixed())
36511  {
36512  // Get the vector of hole coordinates
36513  internal_point_coord[ihole] = poly_pt->internal_point();
36514  }
36515  // This is where the work starts and this could be made much
36516  // better than the current hack
36517  else
36518  {
36519  // If the user has set their own function then use that
36520  if (this->Internal_hole_point_update_fct_pt != 0)
36521  {
36522  this->Internal_hole_point_update_fct_pt(ihole, poly_pt);
36523  }
36524  // Otherwise use our clunky default
36525  else
36526  {
36527  // Now sort out the hole coordinates
36528  Vector<double> vertex_coord;
36529  unsigned n_polyline = poly_pt->npolyline();
36530 
36531  // Initialize Vector hole_coordinates
36532  vertex_coord.resize(2);
36533  internal_point_coord[ihole].resize(2);
36534 
36535  // Hole centre will be found by averaging the position of
36536  // all vertex nodes
36537  internal_point_coord[ihole][0] = 0.0;
36538  internal_point_coord[ihole][1] = 0.0;
36539 
36540  for (unsigned p = 0; p < n_polyline; p++)
36541  {
36542  Vector<double> poly_ave(2, 0.0);
36543  // How many vertices are there in the segment
36544  unsigned n_vertex = poly_pt->polyline_pt(p)->nvertex();
36545  for (unsigned v = 0; v < n_vertex; v++)
36546  {
36547  vertex_coord = poly_pt->polyline_pt(p)->vertex_coordinate(v);
36548  for (unsigned i = 0; i < 2; i++)
36549  {
36550  poly_ave[i] += vertex_coord[i];
36551  }
36552  }
36553 
36554  // Add the average polyline coordinate to the hole centre
36555  for (unsigned i = 0; i < 2; i++)
36556  {
36557  internal_point_coord[ihole][i] += poly_ave[i] / n_vertex;
36558  }
36559  }
36560 
36561  // Now average out the hole centre
36562  for (unsigned i = 0; i < 2; i++)
36563  {
36564  internal_point_coord[ihole][i] /= n_polyline;
36565  }
36566 
36567  // We have now found the hole centre stored in
36568  // internal_point_coordinate[ihole][i]
36569 
36570  // Find polylines that intersect at y average value
36571  // Alice's version but this does not work if the end point of a
36572  // segment is the intersection point (i.e. at the y average value)
36573  /*Vector<double> vertex_coord2;
36574  unsigned n_intersect=0;
36575  double x_average=0.0;
36576 
36577  for(unsigned p=0;p<n_polyline;p++)
36578  {
36579  //How many vertices are there in the segment
36580  unsigned n_vertex = poly_pt->polyline_pt(p)->nvertex();
36581  for(unsigned v=0;v<n_vertex-1;v++)
36582  {
36583  vertex_coord = poly_pt->polyline_pt(p)->vertex_coordinate(v);
36584  vertex_coord2 = poly_pt->polyline_pt(p)->vertex_coordinate(v+1);
36585  std::cout << vertex_coord[0] << " " << vertex_coord[1]
36586  << " " <<
36587  vertex_coord2[0] << " " <<
36588 
36589  vertex_coord2[1] << "\n";
36590  //Does the line between vertices intersect the vertical position
36591  if((vertex_coord[1] -internal_point_coord[ihole][1])*
36592  (vertex_coord2[1] - internal_point_coord[ihole][1]) < 0.0)
36593  {
36594  ++n_intersect; x_average += 0.5*(vertex_coord[0] +
36595  vertex_coord2[0]);
36596  }
36597  }
36598  }
36599 
36600  //Now just report the value if we have had intersections
36601  if(n_intersect != 0)
36602  {
36603  //Report
36604  std::cout << "I have computed a hole " << x_average << " " <<
36605  n_intersect << " "
36606  << x_average/((double)n_intersect) << std::endl;
36607  internal_point_coord[ihole][0] =
36608  x_average/((double)n_intersect);
36609  }
36610  */
36611 
36612  // Set the new hole centre
36613  poly_pt->internal_point() = internal_point_coord[ihole];
36614  // std::cout << "I've had my centre updated to "
36615  // << internal_point_coord[ihole][0]
36616  // << " " << internal_point_coord[ihole][1] << "\n";
36617  }
36618  }
36619  }
36620  }
36621  } // End of the action (n_hole for)
36622 
36623  if (check_only)
36624  {
36625  // If we make it up to here and we only check then no update is required
36626  return false;
36627  }
36628  else
36629  {
36630  // otherwise indicate whether an actual update was performed
36631  return update_was_performed;
36632  }
36633 
36634  } // End of the loop of internal boundaries
36635 
36636  //======================================================================
36637  /// Create the polylines and fill associate data structures, used when
36638  /// creating from a mesh from polyfiles
36639  //======================================================================
36640  template<class ELEMENT>
36642  const std::string& node_file_name, const std::string& poly_file_name)
36643  {
36644  // Get the nodes coordinates (the index of the nodes to build the
36645  // polylines is the one used in the node_file_name file)
36646  // Process node file
36647  // -----------------
36648  std::ifstream node_file(node_file_name.c_str(), std::ios_base::in);
36649 
36650  // Check that the file actually opened correctly
36651  if (!node_file.is_open())
36652  {
36653  std::string error_msg("Failed to open node file: ");
36654  error_msg += "\"" + node_file_name + "\".";
36655  throw OomphLibError(
36656  error_msg, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
36657  }
36658 
36659  // Read number of nodes
36660  unsigned nnodes;
36661  node_file >> nnodes;
36662 
36663  // Spatial dimension of nodes
36664  unsigned dimension;
36665  node_file >> dimension;
36666 
36667 #ifdef PARANOID
36668  if (dimension != 2)
36669  {
36670  throw OomphLibError("The dimension must be 2\n",
36671  OOMPH_CURRENT_FUNCTION,
36672  OOMPH_EXCEPTION_LOCATION);
36673  }
36674 #endif
36675 
36676  // Storage the nodes vertices
36677  Vector<double> x_node(nnodes);
36678  Vector<double> y_node(nnodes);
36679 
36680  // Number of attributes
36681  unsigned npoint_attributes;
36682  node_file >> npoint_attributes;
36683  ;
36684 
36685  // Flag for boundary markers
36686  unsigned boundary_markers_flag = 0;
36687  node_file >> boundary_markers_flag;
36688 
36689  // Dummy for node number
36690  unsigned dummy_node_number;
36691  // Dummy for node attribute
36692  unsigned dummy_node_attribute;
36693  // Dummy for node boundary
36694  unsigned dummy_node_boundary;
36695 
36696  // Load in nodal posititions, point attributes
36697  // and boundary markers
36698  for (unsigned i = 0; i < nnodes; i++)
36699  {
36700  node_file >> dummy_node_number;
36701  node_file >> x_node[i];
36702  node_file >> y_node[i];
36703  for (unsigned j = 0; j < npoint_attributes; ++j)
36704  {
36705  node_file >> dummy_node_attribute;
36706  }
36707  if (boundary_markers_flag)
36708  {
36709  node_file >> dummy_node_boundary;
36710  }
36711  }
36712  node_file.close();
36713 
36714  // Get the segments information and use that info. to create the
36715  // polylines
36716 
36717  // A map to store the segments associated to a boundary, non sorted
36718  std::map<unsigned, Vector<std::pair<unsigned, unsigned>>>
36719  unsorted_boundary_segments;
36720 
36721  // Independent storage for the boundaries ids found in the segments so that
36722  // the polylines, and therefore polygons be created in the order they appear
36723  // in the polyfile
36724  Vector<unsigned> sorted_boundaries_ids;
36725 
36726  // Process poly file to extract edges
36727  //-----------------------------------
36728 
36729  // Open poly file
36730  std::ifstream poly_file(poly_file_name.c_str(), std::ios_base::in);
36731 
36732  // Check that the file actually opened correctly
36733  if (!poly_file.is_open())
36734  {
36735  std::string error_msg("Failed to open poly file: ");
36736  error_msg += "\"" + poly_file_name + "\".";
36737  throw OomphLibError(
36738  error_msg, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
36739  }
36740 
36741  // Number of nodes in poly file --- these will be ignore
36742  unsigned n_node_poly;
36743  poly_file >> n_node_poly;
36744 
36745  // Dimension
36746  poly_file >> dimension;
36747 
36748  // Attribute flag
36749  unsigned attribute_flag;
36750  poly_file >> attribute_flag;
36751 
36752  // Flag for boundary markers
36753  poly_file >> boundary_markers_flag;
36754 
36755  // Ignore node information: Note: No, we can't extract the
36756  // actual nodes themselves from here!
36757  unsigned dummy;
36758  for (unsigned i = 0; i < n_node_poly; i++)
36759  {
36760  // Read in (and discard) node number and x and y coordinates
36761  poly_file >> dummy;
36762  poly_file >> dummy;
36763  poly_file >> dummy;
36764  // read in the attributes
36765  for (unsigned j = 0; j < attribute_flag; ++j)
36766  {
36767  poly_file >> dummy;
36768  }
36769  // read in the boundary marker
36770  if (boundary_markers_flag == 1)
36771  {
36772  poly_file >> dummy;
36773  }
36774  }
36775 
36776  // Variable used to read the values from the input file
36777  unsigned read_value;
36778 
36779  // Number of segments
36780  poly_file >> read_value;
36781  const unsigned nglobal_segments = read_value;
36782 
36783  // Boundary marker flag
36784  poly_file >> boundary_markers_flag;
36785 
36786  // Global segment number
36787  unsigned global_segment_number;
36788 
36789  // Node identifier set (used to identify possible internal boundaries)
36790  std::set<unsigned> nodes_ids;
36791 
36792  // Extract information for each segment
36793  for (unsigned i = 0; i < nglobal_segments; i++)
36794  {
36795  // Node id on the edge of the segment
36796  unsigned lnode_id = 0; // left node
36797  unsigned rnode_id = 0; // right node
36798  unsigned bnd_id = 0; // boundary id associated to the current segment
36799  poly_file >> global_segment_number;
36800  poly_file >> lnode_id;
36801  poly_file >> rnode_id;
36802  nodes_ids.insert(lnode_id);
36803  nodes_ids.insert(rnode_id);
36804  if (boundary_markers_flag)
36805  {
36806  poly_file >> bnd_id;
36807  }
36808 
36809  // Store the segments info. (use bnd_id - 1 because the nodes and
36810  // elements associated the bnd_id have been associated by external
36811  // methods to bnd_id - 1)
36812  unsorted_boundary_segments[bnd_id - 1].push_back(
36813  std::make_pair(lnode_id, rnode_id));
36814 
36815  // Add the boundary id to the vector of boundaries ids only if it
36816  // has not been added, the polylines will be created using this
36817  // order
36818 
36819  // Get the number of boundaries ids currently sorted
36820  const unsigned nsorted_boundaries_ids = sorted_boundaries_ids.size();
36821  // Flag to know if the boundary id was found
36822  bool boundary_id_found = false;
36823  for (unsigned ib = 0; ib < nsorted_boundaries_ids; ib++)
36824  {
36825  if (sorted_boundaries_ids[ib] == bnd_id - 1)
36826  {
36827  boundary_id_found = true;
36828  break;
36829  } // if (sorted_boundaries_ids[ib] == bnd_id - 1)
36830  } // for (ib < nsorted_boundaries_ids)
36831 
36832  // If th boundary id has not been added, then add it!!!
36833  if (!boundary_id_found)
36834  {
36835  sorted_boundaries_ids.push_back(bnd_id - 1);
36836  } // if (!boundary_id_found)
36837  }
36838 
36839  // Verify if there are internal boundaries defined, if that is the
36840  // case we can not continue since we are not yet supporting internal
36841  // boundaries defined in polyfiles to created a mesh that may be
36842  // adapted
36843 #ifdef PARANOID
36844  if (nglobal_segments != nodes_ids.size())
36845  {
36846  std::ostringstream error_message;
36847  error_message
36848  << "The number of nodes (" << nodes_ids.size() << ") and segments ("
36849  << nglobal_segments << ") is different.\nThis may mean that there "
36850  << "are internal non-closed boundaries defined in\nthe polyfile. "
36851  << "If you need this feature please use the TriangleMeshPoyLine\n"
36852  << "and TriangleMeshCurviLine objects to define your domain.\n\n";
36853  throw OomphLibError(
36854  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
36855  }
36856 #endif
36857 
36858  // Now sort the segments associated to a boundary to create a contiguous
36859  // polyline, but first check that the number of found boundaries be the
36860  // same as the current number of boundaries in the mesh
36861  const unsigned nboundary = unsorted_boundary_segments.size();
36862 
36863 #ifdef PARANOID
36864  if (nboundary != this->nboundary())
36865  {
36866  std::ostringstream error_message;
36867  error_message
36868  << "The number of boundaries on the mesh (" << this->nboundary()
36869  << ") is different from the number of\nboundaries read from the "
36870  << "polyfiles (" << unsorted_boundary_segments.size() << ")!!!\n\n\n";
36871  throw OomphLibError(
36872  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
36873  }
36874 #endif
36875 
36876  // Get the number of sorted boundaries ids and check that it matches
36877  // with the total number of boundaries
36878  const unsigned nsorted_boundaries_ids = sorted_boundaries_ids.size();
36879 #ifdef PARANOID
36880  if (nsorted_boundaries_ids != this->nboundary())
36881  {
36882  std::ostringstream error_message;
36883  error_message
36884  << "The number of boundaries on the mesh (" << this->nboundary()
36885  << ") is different from the number of\nsorted boundaries ids read "
36886  << "from the polyfiles (" << nsorted_boundaries_ids << ")!!!\n\n\n";
36887  throw OomphLibError(
36888  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
36889  }
36890 #endif
36891 
36892  // Sorted segments (to create a polyline -- boundary)
36893  std::map<unsigned, std::list<unsigned>> sorted_boundary_segments;
36894 
36895  // Go through all the found boundaries
36896  std::map<unsigned, Vector<std::pair<unsigned, unsigned>>>::iterator it;
36897 
36898  for (it = unsorted_boundary_segments.begin();
36899  it != unsorted_boundary_segments.end();
36900  it++)
36901  {
36902  // Get the current boundary id, only look for the segments
36903  // associated with this boundary
36904  const unsigned bnd_id = (*it).first;
36905  Vector<std::pair<unsigned, unsigned>> segments_edges = (*it).second;
36906 
36907  // Now sort the segments associated to this boundary
36908  std::map<std::pair<unsigned, unsigned>, bool> segment_done;
36909  const unsigned nsegments = segments_edges.size();
36910 
36911  // Sorted nodes for the current segment
36912  std::list<unsigned> sorted_segments;
36913 
36914  // Get the left and right node of the zero segment
36915  unsigned left_node_id = segments_edges[0].first;
36916  unsigned right_node_id = segments_edges[0].second;
36917 
36918  // ... and add it to the sorted segments structure
36919  sorted_segments.push_back(left_node_id);
36920  sorted_segments.push_back(right_node_id);
36921 
36922  // Mark the current segment as done
36923  segment_done[segments_edges[0]] = true;
36924 
36925  // Set the number of sorted segments
36926  unsigned nsorted_segments = 1;
36927 
36928  while (nsorted_segments < nsegments)
36929  {
36930  for (unsigned i = 1; i < nsegments; i++)
36931  {
36932  // Check if the i-th segments has been done
36933  if (!segment_done[segments_edges[i]])
36934  {
36935  // Get the left and right node id
36936  unsigned current_left_node_id = segments_edges[i].first;
36937  unsigned current_right_node_id = segments_edges[i].second;
36938 
36939  // Now check if the current segment can be added to the left
36940  // or right side of the sorted segments
36941  if (current_left_node_id == right_node_id)
36942  {
36943  // Add the current_right_node_id to the right of the sorted
36944  // segments
36945  sorted_segments.push_back(current_right_node_id);
36946  // Increase the number of sorted segments
36947  nsorted_segments++;
36948  // Mark the segment as done
36949  segment_done[segments_edges[i]] = true;
36950  // Update the right most node
36951  right_node_id = current_right_node_id;
36952  // Break the for loop
36953  break;
36954  }
36955  else if (current_right_node_id == left_node_id)
36956  {
36957  // Add the current_left_node_id to the left of the sorted
36958  // segments
36959  sorted_segments.push_front(current_left_node_id);
36960  // Increase the number of sorted segments
36961  nsorted_segments++;
36962  // Mark the segment as done
36963  segment_done[segments_edges[i]] = true;
36964  // Update the left most node
36965  left_node_id = current_left_node_id;
36966  // Break the for loop
36967  break;
36968  }
36969  else if (current_left_node_id == left_node_id)
36970  {
36971  // Add the current_right_node_id to the left of the sorted
36972  // segments
36973  sorted_segments.push_front(current_right_node_id);
36974  // Increase the number of sorted segments
36975  nsorted_segments++;
36976  // Mark the segment as done
36977  segment_done[segments_edges[i]] = true;
36978  // Update the left most node
36979  left_node_id = current_right_node_id;
36980  // Break the for loop
36981  break;
36982  }
36983  else if (current_right_node_id == right_node_id)
36984  {
36985  // Add the current_left_node_id to the right of the sorted
36986  // segments
36987  sorted_segments.push_back(current_left_node_id);
36988  // Increase the number of sorted segments
36989  nsorted_segments++;
36990  // Mark the segment as done
36991  segment_done[segments_edges[i]] = true;
36992  // Update the left most node
36993  right_node_id = current_left_node_id;
36994  // Break the for loop
36995  break;
36996  }
36997  } // if (!segment_done[segments_edges[i]])
36998  } // for (i < nsegments)
36999  } // while(nsorted_segments < nsegments)
37000 
37001  sorted_boundary_segments[bnd_id] = sorted_segments;
37002 
37003  } // for (unsorted_boundary_segments.begin();
37004  // unsorted_boundary_segments.end())
37005 
37006 #ifdef PARANOID
37007  if (sorted_boundary_segments.size() != this->nboundary())
37008  {
37009  std::ostringstream error_message;
37010  error_message
37011  << "The number of boundaries on the mesh (" << this->nboundary()
37012  << ") is different from the number\nof sorted boundaries to create the "
37013  << "polylines (" << sorted_boundary_segments.size() << ")\n\n";
37014  throw OomphLibError(
37015  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
37016  }
37017 #endif
37018 
37019  // Now we have the sorted nodes, we can create the polylines by
37020  // getting the vertices of the nodes
37021  Vector<TriangleMeshPolyLine*> polylines_pt(nboundary);
37022  unsigned current_polyline = 0;
37023 
37024  // Go through the sorted boundaries using the sorted boundaries ids
37025  for (unsigned ib = 0; ib < nsorted_boundaries_ids; ib++)
37026  {
37027  // Get the boundary id from the vector of sorted boundaries ids
37028  const unsigned bnd_id = sorted_boundaries_ids[ib];
37029 
37030  // Create a vector representation for ease to use
37031  // Get the vertices of the nodes that create the boundary / polyline
37032  Vector<unsigned> nodes_ids;
37033  for (std::list<unsigned>::iterator it_list =
37034  sorted_boundary_segments[bnd_id].begin();
37035  it_list != sorted_boundary_segments[bnd_id].end();
37036  it_list++)
37037  {
37038  nodes_ids.push_back((*it_list));
37039  }
37040 
37041  // Get the number of vertices for the polyline
37042  const unsigned nvertices = nodes_ids.size();
37043 
37044  // The storage for the vertices
37045  Vector<Vector<double>> vertices(nvertices);
37046 
37047  // Now get the vertices of the nodes of the current boundary
37048  for (unsigned i = 0; i < nvertices; i++)
37049  {
37050  // Get the vertices
37051  vertices[i].resize(2);
37052  vertices[i][0] = x_node[nodes_ids[i] - 1];
37053  vertices[i][1] = y_node[nodes_ids[i] - 1];
37054  }
37055 
37056  // Now create the polyline
37057 
37058  // Note: The bnd_id is the real bnd_id (from the input file) - 1
37059  // since nodes and elements of the current boundary have been
37060  // associated to bnd_id - 1)
37061  polylines_pt[current_polyline] =
37062  new TriangleMeshPolyLine(vertices, bnd_id);
37063 
37064  // Updates bnd_id<--->curve section map
37065  this->Boundary_curve_section_pt[bnd_id] =
37066  dynamic_cast<TriangleMeshCurveSection*>(polylines_pt[current_polyline]);
37067 
37068  // Increase the index for the polyline storage
37069  current_polyline++;
37070 
37071  } // for (it_sorted = sorted_boundary_segments.begin();
37072  // it_sorted != sorted_boundary_segments.end())
37073 
37074  // Now create the polygons or closed curves
37075  // Sort the polylines to create polygons
37076  unsigned nsorted_polylines = 0;
37077 
37078  // Number of created polygons
37079  unsigned npolygons = 0;
37080 
37081  // Storage for the polygons
37082  Vector<TriangleMeshPolygon*> polygons_pt;
37083 
37084  // Mark the already done polylines
37085  std::map<unsigned, bool> polyline_done;
37086  while (nsorted_polylines < nboundary)
37087  {
37088  // Storage for the curve sections that create a polygon
37089  std::list<TriangleMeshCurveSection*> sorted_curve_sections_pt;
37090 
37091  unsigned init_poly = 0;
37092 #ifdef PARANOID
37093  bool found_root_polyline = false;
37094 #endif
37095  // Get the left and right node of the current polyline
37096  for (unsigned i = 0; i < nboundary; i++)
37097  {
37098  if (!polyline_done[i])
37099  {
37100  init_poly = i;
37101  // Increase the number of sorted polylines
37102  nsorted_polylines++;
37103 #ifdef PARANOID
37104  // Mark as found the root polyline
37105  found_root_polyline = true;
37106 #endif
37107  // Mark the polyline as done
37108  polyline_done[i] = true;
37109  // Add the polyline to the curve sections storage
37110  sorted_curve_sections_pt.push_back(polylines_pt[i]);
37111  // Break the loop to set we have found a root polyline
37112  break;
37113  }
37114  }
37115 
37116 #ifdef PARANOID
37117  if (!found_root_polyline)
37118  {
37119  std::ostringstream error_message;
37120  error_message << "Was not possible to found the root polyline to "
37121  "create polygons\n\n";
37122  throw OomphLibError(error_message.str(),
37123  OOMPH_CURRENT_FUNCTION,
37124  OOMPH_EXCEPTION_LOCATION);
37125  }
37126 #endif
37127 
37128  // Get the associated boundary to the current polyline
37129  const unsigned bnd_id = polylines_pt[init_poly]->boundary_id();
37130  // Get the initial and final node id of the current polyline
37131  unsigned left_node_id = sorted_boundary_segments[bnd_id].front();
37132  unsigned right_node_id = sorted_boundary_segments[bnd_id].back();
37133 
37134  // Flag to know that we already have a closed polygon
37135  bool closed_polygon = false;
37136 
37137  do
37138  {
37139  // Go through all the polylines
37140  for (unsigned i = init_poly; i < nboundary; i++)
37141  {
37142  // Check that the polyline has not been currently done
37143  if (!polyline_done[i])
37144  {
37145  // Get the initial and final nodes id of the current polyline
37146 
37147  // Get the associated boundary to the current polyline
37148  const unsigned cbnd_id = polylines_pt[i]->boundary_id();
37149  // Get the initial and final node id of the current polyline
37150  unsigned cleft_node_id = sorted_boundary_segments[cbnd_id].front();
37151  unsigned cright_node_id = sorted_boundary_segments[cbnd_id].back();
37152 
37153  // Check if the polyline goes to the left or right of the
37154  // current sorted polylines
37155  if (cleft_node_id == right_node_id)
37156  {
37157  // Add the polyline to the curve section storage
37158  sorted_curve_sections_pt.push_back(polylines_pt[i]);
37159  // Mark the polyline as done
37160  polyline_done[i] = true;
37161  // Update the right node
37162  right_node_id = cright_node_id;
37163  // Increase the number of done polyines
37164  nsorted_polylines++;
37165  // Break the for loop
37166  break;
37167  }
37168  else if (cright_node_id == left_node_id)
37169  {
37170  // Add the polyline to the curve section storage
37171  sorted_curve_sections_pt.push_front(polylines_pt[i]);
37172  // Mark the polyline as done
37173  polyline_done[i] = true;
37174  // Update the right node
37175  left_node_id = cleft_node_id;
37176  // Increase the number of done polyines
37177  nsorted_polylines++;
37178  // Break the for loop
37179  break;
37180  }
37181  else if (cleft_node_id == left_node_id)
37182  {
37183  // First reverse the polyline
37184  polylines_pt[i]->reverse();
37185  // Add the polyline to the curve section storage
37186  sorted_curve_sections_pt.push_front(polylines_pt[i]);
37187  // Mark the polyline as done
37188  polyline_done[i] = true;
37189  // Update the right node
37190  left_node_id = cright_node_id;
37191  // Increase the number of done polyines
37192  nsorted_polylines++;
37193  // Break the for loop
37194  break;
37195  }
37196  else if (cright_node_id == right_node_id)
37197  {
37198  // First reverse the polyline
37199  polylines_pt[i]->reverse();
37200  // Add the polyline to the curve section storage
37201  sorted_curve_sections_pt.push_back(polylines_pt[i]);
37202  // Mark the polyline as done
37203  polyline_done[i] = true;
37204  // Update the right node
37205  right_node_id = cleft_node_id;
37206  // Increase the number of done polyines
37207  nsorted_polylines++;
37208  // Break the for loop
37209  break;
37210  }
37211  } // if (!polyline_done[i])
37212 
37213  } // for (i < nboundary)
37214 
37215  // We have created a polygon
37216  if (left_node_id == right_node_id)
37217  {
37218  // Set the flag as true
37219  closed_polygon = true;
37220  }
37221 
37222  } while (nsorted_polylines < nboundary && !closed_polygon);
37223 
37224 #ifdef PARANOID
37225  if (!closed_polygon)
37226  {
37227  std::ostringstream error_message;
37228  error_message
37229  << "It was not possible to create a closed curve, these are the "
37230  << "vertices of the already sorted polylines\n\n";
37231  unsigned cpolyline = 0;
37232  for (std::list<TriangleMeshCurveSection*>::iterator it_list =
37233  sorted_curve_sections_pt.begin();
37234  it_list != sorted_curve_sections_pt.end();
37235  it_list++)
37236  {
37237  error_message << "Polyline (" << cpolyline << ")\n";
37238  TriangleMeshPolyLine* tmp_poly_pt =
37239  dynamic_cast<TriangleMeshPolyLine*>((*it_list));
37240  const unsigned nvertex = tmp_poly_pt->nvertex();
37241  for (unsigned v = 0; v < nvertex; v++)
37242  {
37243  error_message << "(" << tmp_poly_pt->vertex_coordinate(v)[0] << ", "
37244  << tmp_poly_pt->vertex_coordinate(v)[1] << ")\n";
37245  }
37246  error_message << "\n";
37247  cpolyline++;
37248  }
37249  throw OomphLibError(error_message.str(),
37250  OOMPH_CURRENT_FUNCTION,
37251  OOMPH_EXCEPTION_LOCATION);
37252  }
37253 #endif
37254 
37255  // Create a vector version to create the polygon from the sorted
37256  // polyines
37257  Vector<TriangleMeshCurveSection*> tmp_sorted_curve_sections_pt;
37258  for (std::list<TriangleMeshCurveSection*>::iterator it_list =
37259  sorted_curve_sections_pt.begin();
37260  it_list != sorted_curve_sections_pt.end();
37261  it_list++)
37262  {
37263  tmp_sorted_curve_sections_pt.push_back((*it_list));
37264  }
37265 
37266  // Create a new polygon by using the new created polylines
37267  TriangleMeshPolygon* polygon_pt =
37268  new TriangleMeshPolygon(tmp_sorted_curve_sections_pt);
37269 
37270  // Keep track of new created polygons that need to be deleted!!!
37271  this->Free_polygon_pt.insert(polygon_pt);
37272 
37273  // Store the polygon in the polygons storages
37274  polygons_pt.push_back(polygon_pt);
37275 
37276  npolygons++;
37277 
37278  } // while(nsorted_polylines < nboundary)
37279 
37280  // ------------------------------------------------------------------
37281  // Before filling the data structures we need to identify the outer
37282  // closed boundary and the inner closed boundaries.
37283  // If the nodes are not in order we throw a warning message
37284 
37285  // Index for the polygon that is currently considered as the outer
37286  // boundary
37287  unsigned index_outer = 0;
37288 
37289  for (unsigned idx_outer = 0; idx_outer < npolygons; idx_outer++)
37290  {
37291  // Get the vertices of the outer boundary
37292  Vector<Vector<double>> outer_vertex_coordinates;
37293 
37294  // Flag to know if ALL the inner closed boundaries are inside the
37295  // outer closed boundary
37296  bool all_inner_inside = true;
37297 
37298  // Number of polylines of the outer boundary
37299  const unsigned nouter_polylines = polygons_pt[idx_outer]->npolyline();
37300  for (unsigned p = 0; p < nouter_polylines; p++)
37301  {
37302  TriangleMeshPolyLine* tmp_poly_pt =
37303  polygons_pt[idx_outer]->polyline_pt(p);
37304  const unsigned nvertex = tmp_poly_pt->nvertex();
37305  for (unsigned v = 0; v < nvertex; v++)
37306  {
37307  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37308  outer_vertex_coordinates.push_back(current_vertex);
37309  } // for (v < nvertex)
37310  } // for (p < nouter_polylines)
37311 
37312  // Now get the vertices for the inner boundaries
37313 
37314  // First get the number of inner closed boundaries (polygons size
37315  // minus one because one of the polygons is considered to be the
37316  // outer closed boundary
37317  const unsigned ninner_polygons = polygons_pt.size() - 1;
37318 
37319  // Store the vertices of the inner closed boundaries
37320  Vector<Vector<Vector<double>>> inner_vertex_coordinates(ninner_polygons);
37321  // Get all the vertices of the inner closed boundaries
37322  for (unsigned i = 0; i <= ninner_polygons; i++)
37323  {
37324  if (i != idx_outer)
37325  {
37326  // Number of polylines of the current internal closed boundary
37327  const unsigned ninner_polylines = polygons_pt[i]->npolyline();
37328  for (unsigned p = 0; p < ninner_polylines; p++)
37329  {
37330  TriangleMeshPolyLine* tmp_poly_pt = polygons_pt[i]->polyline_pt(p);
37331  const unsigned nvertex = tmp_poly_pt->nvertex();
37332  for (unsigned v = 0; v < nvertex; v++)
37333  {
37334  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37335  if (i < idx_outer)
37336  {
37337  inner_vertex_coordinates[i].push_back(current_vertex);
37338  }
37339  else if (i > idx_outer)
37340  {
37341  inner_vertex_coordinates[i - 1].push_back(current_vertex);
37342  }
37343  } // for (v < nvertex)
37344 
37345  } // for (p < ninner_polylines)
37346 
37347  } // if (i != index_outer)
37348 
37349  } // for (i <= ninner_polygons)
37350 
37351  // Now check that ALL the vertices of ALL the internal closed
37352  // boundaries are inside the outer closed boundary
37353  for (unsigned i = 0; i < ninner_polygons; i++)
37354  {
37355  // Get the number of vertices in the current internal closed
37356  // boundary
37357  const unsigned nvertex_internal = inner_vertex_coordinates[i].size();
37358  for (unsigned v = 0; v < nvertex_internal; v++)
37359  {
37360  // Get a vertex in the current internal closed boundary
37361  Vector<double> current_point = inner_vertex_coordinates[i][v];
37362  all_inner_inside &= this->is_point_inside_polygon_helper(
37363  outer_vertex_coordinates, current_point);
37364 
37365  // Check if we should continue checking for more points inside
37366  // the current proposed outer boundary
37367  if (!all_inner_inside)
37368  {
37369  // Break the "for" for the vertices
37370  break;
37371  }
37372 
37373  } // for (v < nvertex_internal)
37374 
37375  // Check if we should continue checking for more inner closed
37376  // boundaries inside the current proposed outer boundary
37377  if (!all_inner_inside)
37378  {
37379  // Break the "for" for the inner boundaries
37380  break;
37381  }
37382 
37383  } // for (i < ninner_polygons)
37384 
37385  // Check if all the vertices of all the polygones are inside the
37386  // current proposed outer boundary
37387  if (all_inner_inside)
37388  {
37389  index_outer = idx_outer;
37390  break;
37391  }
37392 
37393  } // for (idx_outer < npolygons)
37394 
37395 #ifdef PARANOID
37396  // Check if the first nodes listed in the polyfiles correspond to
37397  // the outer boundary, if that is not the case then throw a warning
37398  // message
37399  if (index_outer != 0)
37400  {
37401  std::ostringstream warning_message;
37402  warning_message
37403  << "The first set of nodes listed in the input polyfiles does not\n"
37404  << "correspond to the outer closed boundary. This may lead to\n"
37405  << "problems at the adaptation stage if the holes coordinates\n"
37406  << "are no correctly associated to the inner closed boundaries.\n"
37407  << "You can check the generated mesh by calling the output() method\n"
37408  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37409  OomphLibWarning(warning_message.str(),
37410  OOMPH_CURRENT_FUNCTION,
37411  OOMPH_EXCEPTION_LOCATION);
37412  } // if (index_outer != 0)
37413 #endif
37414 
37415  // ------------------------------------------------------------------
37416  // Now fill the data structures
37417 
37418  // Store outer polygon
37419  // We are assuming there is only one outer polygon
37420  this->Outer_boundary_pt.resize(1);
37421  this->Outer_boundary_pt[0] = polygons_pt[index_outer];
37422 
37423  this->Internal_polygon_pt.resize(npolygons - 1);
37424  for (unsigned i = 0; i < npolygons; i++)
37425  {
37426  if (i != index_outer)
37427  {
37428  if (i < index_outer)
37429  {
37430  // Store internal polygons by copy constructor
37431  this->Internal_polygon_pt[i] = polygons_pt[i];
37432  }
37433  else if (i > index_outer)
37434  {
37435  // Store internal polygons by copy constructor
37436  this->Internal_polygon_pt[i - 1] = polygons_pt[i];
37437  }
37438  } // if (i != index_outer)
37439  } // for (i < npolygons)
37440 
37441  // Before assigning the hole vertex coordinate to the inner closed
37442  // boundaries check that the holes are listed in orderm if that is
37443  // not the case the associate each hole vertex coordinate to the
37444  // inner closed boundaries
37445 
37446  // Store the vertices of the inner closed boundaries
37447  Vector<Vector<Vector<double>>> inner_vertex_coordinates(npolygons - 1);
37448  // Get all the vertices of the inner closed boundaries
37449  for (unsigned i = 0; i < npolygons - 1; i++)
37450  {
37451  // Number of polylines of the current internal closed boundary
37452  const unsigned ninner_polylines =
37453  this->Internal_polygon_pt[i]->npolyline();
37454  for (unsigned p = 0; p < ninner_polylines; p++)
37455  {
37456  TriangleMeshPolyLine* tmp_poly_pt =
37457  this->Internal_polygon_pt[i]->polyline_pt(p);
37458  // Number of vertices of the current polyline in the current
37459  // internal closed polygon
37460  const unsigned nvertex = tmp_poly_pt->nvertex();
37461  for (unsigned v = 0; v < nvertex; v++)
37462  {
37463  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37464  inner_vertex_coordinates[i].push_back(current_vertex);
37465  } // for (v < nvertex)
37466 
37467  } // for (p < ninner_polylines)
37468 
37469  } // for (i <= ninner_polygons)
37470 
37471  // Holes information
37472  unsigned nholes;
37473  poly_file >> nholes;
37474 
37475 #ifdef PARANOID
37476  if (npolygons > 1 && (npolygons - 1) != nholes)
37477  {
37478  std::ostringstream error_message;
37479  error_message
37480  << "The number of holes (" << nholes << ") does not correspond "
37481  << "with the number\nof internal polygons (" << npolygons - 1 << ")\n\n"
37482  << "Using polyfiles as input does not currently allows the\n"
37483  << "definition of more than one outer polygon\n\n";
37484  throw OomphLibError(
37485  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
37486  }
37487 #endif
37488 
37489  // Storage for the holes
37490  Vector<Vector<double>> hole_coordinates(nholes);
37491 
37492  // Dummy for hole number
37493  unsigned dummy_hole;
37494  // Loop over the holes to get centre coords
37495  for (unsigned ihole = 0; ihole < nholes; ihole++)
37496  {
37497  hole_coordinates[ihole].resize(2);
37498  // Read the centre value
37499  poly_file >> dummy_hole;
37500  poly_file >> hole_coordinates[ihole][0];
37501  poly_file >> hole_coordinates[ihole][1];
37502  }
37503 
37504  // Vector that store the index of the hole coordinate that
37505  // correspond to each internal closed polygon
37506  Vector<unsigned> index_hole_of_internal_polygon(npolygons - 1);
37507  std::map<unsigned, bool> hole_done;
37508 
37509  // Now associate each hole vertex to a corresponding internal closed
37510  // polygon
37511  for (unsigned i = 0; i < npolygons - 1; i++)
37512  {
37513  // Find which hole is associated to each internal closed boundary
37514  for (unsigned h = 0; h < nholes; h++)
37515  {
37516  // If the hole has not been previously associated
37517  if (!hole_done[h])
37518  {
37519  // Get the hole coordinate
37520  Vector<double> current_point = hole_coordinates[h];
37521 
37522  const bool hole_in_polygon = this->is_point_inside_polygon_helper(
37523  inner_vertex_coordinates[i], current_point);
37524 
37525  // If the hole is inside the polygon
37526  if (hole_in_polygon)
37527  {
37528  // Mark the hole as done
37529  hole_done[h] = true;
37530  // Associate the current hole with the current inner closed
37531  // boundary
37532  index_hole_of_internal_polygon[i] = h;
37533  // Break the search
37534  break;
37535  }
37536 
37537  } // if (!hole_done[h])
37538 
37539  } // for (h < nholes)
37540 
37541  } // for (i < npolygons-1)
37542 
37543 #ifdef PARANOID
37544  if (hole_done.size() != npolygons - 1)
37545  {
37546  std::ostringstream error_message;
37547  error_message
37548  << "Not all the holes were associated to an internal closed boundary\n"
37549  << "Only (" << hole_done.size()
37550  << ") holes were assigned for a total of\n"
37551  << "(" << npolygons - 1 << ") internal closed boundaries.\n"
37552  << "You can check the generated mesh by calling the output() method\n"
37553  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37554  throw OomphLibError(
37555  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
37556  } // if (index_hole != ihole)
37557 #endif
37558 
37559  // Assign the holes coordinates to the internal polygons
37560  for (unsigned ihole = 0; ihole < nholes; ihole++)
37561  {
37562  // Get the index hole of the current internal closed polygon
37563  const unsigned index_hole = index_hole_of_internal_polygon[ihole];
37564 #ifdef PARANOID
37565  // Check if the hole index is the same as the internal closed
37566  // boundary, it means that the holes were listed in the same order
37567  // as the nodes of the internal closed boundaries
37568  if (index_hole != ihole)
37569  {
37570  std::ostringstream error_message;
37571  error_message
37572  << "The hole vertices coordinates are not listed in the same order\n"
37573  << "as the nodes that define the internal closed boundaries.\n"
37574  << "This may lead to problems in case that the holes coordinates\n"
37575  << "were no properly assigned to the internal closed boundaries.\n"
37576  << "You can check the generated mesh by calling the output() method\n"
37577  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37578  throw OomphLibError(error_message.str(),
37579  OOMPH_CURRENT_FUNCTION,
37580  OOMPH_EXCEPTION_LOCATION);
37581  } // if (index_hole != ihole)
37582 #endif
37583 
37584  // Set the hole coordinate for the internal polygon
37585  this->Internal_polygon_pt[ihole]->internal_point() =
37586  hole_coordinates[index_hole];
37587  }
37588 
37589  // Ignore the first line with structure description
37590  poly_file.ignore(80, '\n');
37591 
37592  // Regions information
37593  unsigned nregions;
37594 
37595  // Extract regions information
37596  // But first check if there are regions or not
37597  std::string regions_info_string;
37598 
37599  // Read line up to termination sign
37600  getline(poly_file, regions_info_string);
37601 
37602  // Check if the read string is a number or a comment wrote by triangle,
37603  // if it is a number then that is the number of regions
37604  if (isdigit(regions_info_string.c_str()[0]))
37605  {
37606  nregions = std::atoi(regions_info_string.c_str());
37607  }
37608  else
37609  {
37610  nregions = 0;
37611  }
37612 
37613  // The regions coordinates
37614  std::map<unsigned, Vector<double>> regions_coordinates;
37615 
37616  // Dummy for regions number
37617  unsigned dummy_region;
37618 
37619  unsigned region_id;
37620 
37621  // Loop over the regions to get their coords
37622  for (unsigned iregion = 0; iregion < nregions; iregion++)
37623  {
37624  Vector<double> tmp_region_coordinates(2);
37625  // Read the regions coordinates
37626  poly_file >> dummy_region;
37627  poly_file >> tmp_region_coordinates[0];
37628  poly_file >> tmp_region_coordinates[1];
37629  poly_file >> region_id;
37630  regions_coordinates[region_id].resize(2);
37631  regions_coordinates[region_id][0] = tmp_region_coordinates[0];
37632  regions_coordinates[region_id][1] = tmp_region_coordinates[1];
37633 
37634  // Ignore the first line with structure description
37635  poly_file.ignore(80, '\n');
37636 
37637  // Verify if not using the default region number (zero)
37638  if (region_id == 0)
37639  {
37640  std::ostringstream error_message;
37641  error_message
37642  << "Please use another region id different from zero.\n"
37643  << "It is internally used as the default region number.\n";
37644  throw OomphLibError(error_message.str(),
37645  OOMPH_CURRENT_FUNCTION,
37646  OOMPH_EXCEPTION_LOCATION);
37647  }
37648  }
37649 
37650  // Store the extra regions coordinates
37651  this->Regions_coordinates = regions_coordinates;
37652 
37653  poly_file.close();
37654  }
37655 
37656  //======================================================================
37657  /// Updates the polygon but using the elements area instead of
37658  /// the default refinement and unrefinement methods
37659  //======================================================================
37660  template<class ELEMENT>
37662  TriangleMeshPolygon*& polygon_pt, const Vector<double>& target_area)
37663  {
37664  // Verify that there was a change on the polygon representation
37665  unsigned update_was_performed = false;
37666 
37667  const unsigned nele = this->nelement();
37668 
37669  // - Get the vertices along the boundaries and for each element identify
37670  // its associated target error.
37671  // - Get face mesh representation of each polyline.
37672  // - Get the vertices with the help of face elements.
37673  // - Find the global index in the mesh of the face element and use
37674  // it to get its associated target area
37675 
37676  // Get the face mesh representation
37677  Vector<Mesh*> face_mesh_pt;
37678  get_face_mesh_representation(polygon_pt, face_mesh_pt);
37679 
37680  // Create vertices of the polylines by using the vertices of the
37681  // FaceElements
37682  Vector<double> vertex_coord(3); // zeta,x,y
37683  Vector<double> bound_left(1);
37684  Vector<double> bound_right(1);
37685 
37686  unsigned n_polyline = polygon_pt->npolyline();
37687 
37688  // Go for each polyline
37689  for (unsigned p = 0; p < n_polyline; p++)
37690  {
37691  // Get the MeshAsGeomObject representation just once per polyline,
37692  // this object is only used by the
37693  // refine_boundary_constrained_by_target_area() method. We get it
37694  // here to ensure that all processors (in a distributed context)
37695  // get this representation just once, and because an AllToAll MPI
37696  // communication is used in this calling
37697  MeshAsGeomObject* mesh_geom_obj_pt =
37698  new MeshAsGeomObject(face_mesh_pt[p]);
37699 
37700  // Set of coordinates on the boundary
37701  // Set entries are ordered on first entry in vector which stores
37702  // the boundary coordinate so the vertices come out in order!
37703  std::set<Vector<double>> vertex_nodes;
37704 
37705  // Vector to store the vertices, transfer the sorted vertices from the
37706  // set to this vector, --- including the z-value ---
37707  Vector<Vector<double>> tmp_vector_vertex_node;
37708 
37709  // Vector to store the coordinates of the polylines, same as the
37710  // tmp_vector_vertex_node vector (after adding more nodes) but
37711  // --- without the z-value ---, used to re-generate the polylines
37712  Vector<Vector<double>> vector_vertex_node;
37713 
37714 #ifdef OOMPH_HAS_MPI
37715  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
37716  // Set of coordinates that are on the boundary (splitted boundary version)
37717  // The first vector is used to allocate the points for each sub-boundary
37718  // Set entries are ordered on first entry in vector which stores
37719  // the boundary coordinate so the vertices come out in order!
37720  Vector<std::set<Vector<double>>> sub_vertex_nodes;
37721 
37722  // Vector to store the vertices, transfer the sorted vertices from the
37723  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
37724  Vector<Vector<Vector<double>>> sub_tmp_vector_vertex_node;
37725 
37726  // Vector to store the coordinates of the polylines that will represent
37727  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
37728  // but --- without the z-value ---, used to generate the sub-polylines
37729  Vector<Vector<Vector<double>>> sub_vector_vertex_node;
37730  // --------- Stuff to deal with splitted boundaries ----------- End ------
37731 #endif
37732 
37733  // Get the boundary id
37734  const unsigned bound = polygon_pt->curve_section_pt(p)->boundary_id();
37735 
37736  // Get the chunk number
37737  const unsigned chunk = polygon_pt->curve_section_pt(p)->boundary_chunk();
37738 
37739  /// Use a vector of vector for vertices and target areas to deal
37740  /// with the cases when the boundaries are split by the
37741  /// distribution process
37742 
37743  // Loop over the face elements (ordered) and add their vertices
37744  const unsigned nface_element = face_mesh_pt[p]->nelement();
37745 
37746  // Store the non halo face elements, the ones from which we will
37747  // get the vertices
37748  Vector<FiniteElement*> non_halo_face_element_pt;
37749 
37750  // Map to store the index of the face element on a boundary
37751  std::map<FiniteElement*, unsigned> face_element_index_on_boundary;
37752 
37753  for (unsigned ef = 0; ef < nface_element; ++ef)
37754  {
37755  FiniteElement* ele_face_pt = face_mesh_pt[p]->finite_element_pt(ef);
37756 #ifdef OOMPH_HAS_MPI
37757  // Skip the halo elements if working with a distributed mesh
37758  if (this->is_mesh_distributed() && ele_face_pt->is_halo())
37759  {
37760  continue;
37761  }
37762 #endif
37763  // Add the face element to the vector
37764  non_halo_face_element_pt.push_back(ele_face_pt);
37765  face_element_index_on_boundary[ele_face_pt] = ef;
37766  }
37767 
37768  // Get the number of non halo face element
37769  const unsigned nnon_halo_face_element = non_halo_face_element_pt.size();
37770 
37771  // Map to know the already sorted face elements
37772  std::map<FiniteElement*, bool> face_element_done;
37773 
37774  // Number of done face elements
37775  unsigned nsorted_face_elements = 0;
37776 
37777 #ifdef OOMPH_HAS_MPI
37778  // Counter for sub_boundaries
37779  unsigned nsub_boundaries = 0;
37780 #endif // #ifdef OOMPH_HAS_MPI
37781 
37782  // Continue until all the face elements have been sorted
37783  // While to deal with split boundaries cases
37784  while (nsorted_face_elements < nnon_halo_face_element)
37785  {
37786  // Get and initial face element
37787  FiniteElement* ele_face_pt = 0;
37788 #ifdef PARANOID
37789  bool found_initial_face_element = false;
37790 #endif
37791 
37792  unsigned iface = 0;
37793  for (iface = 0; iface < nnon_halo_face_element; iface++)
37794  {
37795  ele_face_pt = non_halo_face_element_pt[iface];
37796  // If not done then take it as initial face element
37797  if (!face_element_done[ele_face_pt])
37798  {
37799 #ifdef PARANOID
37800  found_initial_face_element = true;
37801 #endif
37802  nsorted_face_elements++;
37803  iface++;
37804  break;
37805  }
37806  }
37807 
37808 #ifdef PARANOID
37809  if (!found_initial_face_element)
37810  {
37811  std::ostringstream error_message;
37812  error_message << "Could not find an initial face element for the "
37813  "current segment\n";
37814  // << "----- Possible memory leak -----\n";
37815  throw OomphLibError(
37816  error_message.str(),
37817  "RefineableTriangleMesh::update_polygon_using_elements_area()",
37818  OOMPH_EXCEPTION_LOCATION);
37819  }
37820 #endif
37821 
37822  // Local set of coordinates that are on the boundary
37823  // Set entries are ordered on first entry in vector which stores
37824  // the boundary coordinate so the vertices come out in order!
37825  std::set<Vector<double>> local_vertex_nodes;
37826 
37827  // Vector to store the vertices, transfer the sorted vertices from the
37828  // set (local) to this vector (local), --- including the z-value ---
37829  Vector<Vector<double>> local_tmp_vector_vertex_node;
37830 
37831  // Vector to store the target areas, uses the same approach as the
37832  // set for the local_vertex_nodes, ordered on first entry
37833  std::set<Vector<double>> sorted_target_areas;
37834 
37835  // Vector to store the target areas, used to transfer the sorted target
37836  // areas from "local_sorted_target_areas" set
37837  Vector<double> tmp_sorted_target_areas;
37838 
37839  // -----------------------------------------------------------------
37840  // Add the vertices of the initial face element to the set of
37841  // local sorted vertices
37842  // -----------------------------------------------------------------
37843  unsigned nnode = ele_face_pt->nnode();
37844  // Add the left-hand node to the set:
37845  // Boundary coordinate
37846  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound, bound_left);
37847  vertex_coord[0] = bound_left[0];
37848 
37849  // Actual coordinates
37850  for (unsigned i = 0; i < 2; i++)
37851  {
37852  vertex_coord[i + 1] = ele_face_pt->node_pt(0)->x(i);
37853  }
37854  local_vertex_nodes.insert(vertex_coord);
37855 
37856  // Add the right-hand nodes to the set:
37857  // Boundary coordinate
37858  ele_face_pt->node_pt(nnode - 1)->get_coordinates_on_boundary(
37859  bound, bound_right);
37860  vertex_coord[0] = bound_right[0];
37861 
37862  // Actual coordinates
37863  for (unsigned i = 0; i < 2; i++)
37864  {
37865  vertex_coord[i + 1] = ele_face_pt->node_pt(nnode - 1)->x(i);
37866  }
37867  local_vertex_nodes.insert(vertex_coord);
37868 
37869  // The initial and final node on the set
37870  Node* first_node_pt = ele_face_pt->node_pt(0);
37871  Node* last_node_pt = ele_face_pt->node_pt(nnode - 1);
37872 
37873  // Mark the current face element as done
37874  face_element_done[ele_face_pt] = true;
37875 
37876  // -------------------------------------------------------
37877  // Find the global index in the mesh of the face element
37878  // and use it to get its associated target area
37879  // -------------------------------------------------------
37880  // Container to store the zeta value (used as index) and
37881  // the associated target area of the element
37882  Vector<double> zeta_target_area_values(2);
37883 
37884  // Use the minimum zeta value to sort the target areas
37885  // along the boundary
37886  zeta_target_area_values[0] = std::min(bound_left[0], bound_right[0]);
37887 
37888  // Get the index of the face element on the current boundary
37889  unsigned ef = face_element_index_on_boundary[ele_face_pt];
37890  // Get the "ef"-th element on the boundary
37891  FiniteElement* el_pt = this->boundary_element_pt(bound, ef);
37892 
37893 #ifdef PARANOID
37894  bool found_global_element_index = false;
37895 #endif
37896  for (unsigned eg = 0; eg < nele; eg++)
37897  {
37898  // Get the "eg-th" element
37899  FiniteElement* el_compare_pt = this->finite_element_pt(eg);
37900 
37901  // Compare with the element on the boundary, if equal then
37902  // store the target area
37903  if (el_pt == el_compare_pt)
37904  {
37905  zeta_target_area_values[1] = target_area[eg];
37906 #ifdef PARANOID
37907  found_global_element_index = true;
37908 #endif
37909  break; // break the for (e < nele) global element
37910  } // if element_pt == element_compare_pt
37911  } // for nele (on complete mesh)
37912 
37913 #ifdef PARANOID
37914  if (!found_global_element_index)
37915  {
37916  std::ostringstream error_message;
37917  error_message << "The global index for the (" << ef
37918  << ")-th face element "
37919  << "on\nthe (" << bound
37920  << ")-th boundary was not found!!!";
37921  throw OomphLibError(
37922  error_message.str(),
37923  "RefineableTriangleMesh::update_polygon_using_elements_area()",
37924  OOMPH_EXCEPTION_LOCATION);
37925  }
37926 #endif
37927 
37928  // Add the target areas to the sorted set
37929  sorted_target_areas.insert(zeta_target_area_values);
37930  // ------------------------------------------------------------------
37931 
37932  // Continue iterating if a new face element has been added to the
37933  // list
37934  bool face_element_added = false;
37935 
37936  // While a new face element has been added to the set of sorted
37937  // face elements then re-iterate
37938  do
37939  {
37940  // Start from the next face elements since we have already
37941  // added the previous one as the initial face element (any
37942  // previous face element had to be added on previous
37943  // iterations)
37944  for (unsigned iiface = iface; iiface < nnon_halo_face_element;
37945  iiface++)
37946  {
37947  face_element_added = false;
37948  ele_face_pt = non_halo_face_element_pt[iiface];
37949  if (!face_element_done[ele_face_pt])
37950  {
37951  // Get each individual node to check if they are contiguous
37952  nnode = ele_face_pt->nnode();
37953  Node* left_node_pt = ele_face_pt->node_pt(0);
37954  Node* right_node_pt = ele_face_pt->node_pt(nnode - 1);
37955 
37956  if (left_node_pt == first_node_pt)
37957  {
37958  first_node_pt = right_node_pt;
37959  face_element_added = true;
37960  }
37961  else if (left_node_pt == last_node_pt)
37962  {
37963  last_node_pt = right_node_pt;
37964  face_element_added = true;
37965  }
37966  else if (right_node_pt == first_node_pt)
37967  {
37968  first_node_pt = left_node_pt;
37969  face_element_added = true;
37970  }
37971  else if (right_node_pt == last_node_pt)
37972  {
37973  last_node_pt = left_node_pt;
37974  face_element_added = true;
37975  }
37976 
37977  if (face_element_added)
37978  {
37979  // Add the left-hand node to the set:
37980  // Boundary coordinate
37981  left_node_pt->get_coordinates_on_boundary(bound, bound_left);
37982  vertex_coord[0] = bound_left[0];
37983 
37984  // Actual coordinates
37985  for (unsigned i = 0; i < 2; i++)
37986  {
37987  vertex_coord[i + 1] = left_node_pt->x(i);
37988  }
37989  local_vertex_nodes.insert(vertex_coord);
37990 
37991  // Add the right-hand nodes to the set:
37992  // Boundary coordinate
37993  right_node_pt->get_coordinates_on_boundary(bound, bound_right);
37994  vertex_coord[0] = bound_right[0];
37995 
37996  // Actual coordinates
37997  for (unsigned i = 0; i < 2; i++)
37998  {
37999  vertex_coord[i + 1] = right_node_pt->x(i);
38000  }
38001  local_vertex_nodes.insert(vertex_coord);
38002 
38003  // Mark as done only if one of its nodes has been
38004  // added to the list
38005  face_element_done[ele_face_pt] = true;
38006  nsorted_face_elements++;
38007 
38008  // -----------------------------------------------------
38009  // Find the global index in the mesh of the face element
38010  // and use it to get its associated target area
38011  // -----------------------------------------------------
38012  // Use the minimum zeta value to sort the target areas
38013  // along the boundary
38014  zeta_target_area_values[0] =
38015  std::min(bound_left[0], bound_right[0]);
38016 
38017  // Get the "ef"-th element on the boundary
38018  ef = face_element_index_on_boundary[ele_face_pt];
38019  FiniteElement* lel_pt = this->boundary_element_pt(bound, ef);
38020 
38021 #ifdef PARANOID
38022  found_global_element_index = false;
38023 #endif
38024  for (unsigned eg = 0; eg < nele; eg++)
38025  {
38026  // Get the "eg-th" element
38027  FiniteElement* lel_compare_pt = this->finite_element_pt(eg);
38028 
38029  // Compare with the element on the boundary, if equal then
38030  // store the target area
38031  if (lel_pt == lel_compare_pt)
38032  {
38033  zeta_target_area_values[1] = target_area[eg];
38034 #ifdef PARANOID
38035  found_global_element_index = true;
38036 #endif
38037  break; // break the for (e < nele) global element
38038  } // if element_pt == element_compare_pt
38039  } // for nele (on complete mesh)
38040 
38041 #ifdef PARANOID
38042  if (!found_global_element_index)
38043  {
38044  std::ostringstream error_message;
38045  error_message << "The global index for the (" << ef
38046  << ")-th face element "
38047  << "on\nthe (" << bound
38048  << ")-th boundary was not found!!!";
38049  throw OomphLibError(error_message.str(),
38050  "RefineableTriangleMesh::update_polygon_"
38051  "using_elements_area()",
38052  OOMPH_EXCEPTION_LOCATION);
38053  }
38054 #endif
38055 
38056  // Add the target areas to the sorted set
38057  sorted_target_areas.insert(zeta_target_area_values);
38058 
38059  break;
38060  }
38061 
38062  } // if (!edge_done[edge])
38063  } // for (iiedge < nedges)
38064  } while (face_element_added &&
38065  (nsorted_face_elements < nnon_halo_face_element));
38066 
38067  // -----------------------------------------------------------------
38068  // At this point we already have a sorted set of nodes and
38069  // can be used to peform the unrefinement and refinement procedures
38070  // -----------------------------------------------------------------
38071 
38072  // Get the number of nodes on the list
38073  const unsigned nlocal_nodes = local_vertex_nodes.size();
38074  // Change representation to vector for easy of handling ...
38075  local_tmp_vector_vertex_node.resize(nlocal_nodes);
38076 
38077  // Copy the vertices of the nodes
38078  unsigned counter = 0;
38079  std::set<Vector<double>>::iterator it_vertex;
38080  for (it_vertex = local_vertex_nodes.begin();
38081  it_vertex != local_vertex_nodes.end();
38082  it_vertex++)
38083  {
38084  local_tmp_vector_vertex_node[counter].resize(3);
38085  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
38086  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
38087  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
38088  counter++;
38089  }
38090 
38091  // ... same for the info. related with the target areas (turn
38092  // into vector)
38093  const unsigned ntarget_areas = sorted_target_areas.size();
38094  tmp_sorted_target_areas.resize(ntarget_areas);
38095  counter = 0;
38096  std::set<Vector<double>>::iterator it_area;
38097  for (it_area = sorted_target_areas.begin();
38098  it_area != sorted_target_areas.end();
38099  ++it_area)
38100  {
38101  tmp_sorted_target_areas[counter] = (*it_area)[1];
38102  ++counter;
38103  }
38104 
38105 #ifdef PARANOID
38106  if (nlocal_nodes > 0 && (ntarget_areas != nlocal_nodes - 1))
38107  {
38108  std::ostringstream error_message;
38109  error_message
38110  << "The boundary (" << bound << ") was split during the "
38111  << "distribution process.\n"
38112  << "The problem is in the association of the target areas with "
38113  "the\n"
38114  << "elements that gave rise to the vertex coordinates.\n"
38115  << "The number of local nodes (" << nlocal_nodes
38116  << "), on the 'sub-polyline', is not\n"
38117  << "according with the number of target "
38118  << "areas (" << ntarget_areas << ")\nfor that number of nodes.\n"
38119  << "The target areas number MUST be equal to the number of\n"
38120  << "local nodes minus one\n\n";
38121  throw OomphLibError(error_message.str(),
38122  OOMPH_CURRENT_FUNCTION,
38123  OOMPH_EXCEPTION_LOCATION);
38124  }
38125 #endif
38126 
38127  // -------------------------------------------------------------------
38128  // Update the vertices along the boundary using the target area
38129  // to define the distance among them
38130  // -------------------------------------------------------------------
38131 
38132  // Tolerance below which the middle point can be deleted
38133  // (ratio of deflection to element length)
38134  double unrefinement_tolerance =
38135  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
38136 
38137  // Apply unrefinement
38138  bool unrefinement_applied =
38139  unrefine_boundary_constrained_by_target_area(
38140  bound,
38141  chunk,
38142  local_tmp_vector_vertex_node,
38143  unrefinement_tolerance,
38144  tmp_sorted_target_areas);
38145 
38146  // Tolerance for refinement
38147  double refinement_tolerance =
38148  polygon_pt->polyline_pt(p)->refinement_tolerance();
38149 
38150  // Apply refinement
38151  bool refinement_applied = refine_boundary_constrained_by_target_area(
38152  mesh_geom_obj_pt,
38153  local_tmp_vector_vertex_node,
38154  refinement_tolerance,
38155  tmp_sorted_target_areas);
38156 
38157  // Clear the local containter to recover the nodes ordered using the
38158  // zeta value
38159  local_vertex_nodes.clear();
38160 
38161  // At the end of each unrefinement/refinement step store the new nodes
38162  // on the set that will give rise to the vertices of the new polyline
38163  // representation
38164  unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
38165  for (unsigned i = 0; i < nnew_nodes; i++)
38166  {
38167  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
38168  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
38169  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
38170  vertex_nodes.insert(vertex_coord); // Global container
38171  local_vertex_nodes.insert(vertex_coord);
38172  }
38173 
38174  // Update the flag to indicate whether an unrefinement or
38175  // refinement was applied
38176  update_was_performed = (unrefinement_applied || refinement_applied);
38177 
38178 #ifdef OOMPH_HAS_MPI
38179  if (this->is_mesh_distributed())
38180  {
38181  // Add the set of vertices for the boundary, this will help to
38182  // detect if we need to deal with sub-boundaries
38183  sub_vertex_nodes.push_back(local_vertex_nodes);
38184  // Increase the counter for sub-boundaries
38185  nsub_boundaries++;
38186  }
38187 #endif
38188 
38189  } // while(nsorted_face_elements < nnon_halo_face_element)
38190 
38191  // Now turn into vector for ease of handling...
38192  unsigned npoly_vertex = vertex_nodes.size();
38193  // This will store all the vertices whether the boundary was split
38194  // or not
38195  tmp_vector_vertex_node.resize(npoly_vertex);
38196  unsigned count = 0;
38197  for (std::set<Vector<double>>::iterator it = vertex_nodes.begin();
38198  it != vertex_nodes.end();
38199  ++it)
38200  {
38201  tmp_vector_vertex_node[count].resize(3);
38202  tmp_vector_vertex_node[count][0] = (*it)[0];
38203  tmp_vector_vertex_node[count][1] = (*it)[1];
38204  tmp_vector_vertex_node[count][2] = (*it)[2];
38205  ++count;
38206  }
38207 
38208 #ifdef OOMPH_HAS_MPI
38209  // --------- Stuff for the sub_boundaries ----- Begin section ---------
38210 #ifdef PARANOID
38211  unsigned nsub_boundaries_set = sub_vertex_nodes.size();
38212  if (nsub_boundaries_set != nsub_boundaries)
38213  {
38214  std::ostringstream error_message;
38215  error_message
38216  << "The number of found sub-boundaries and the number of counted\n"
38217  << "sub-boundaries are different:\n"
38218  << "Number of found sub-boundaries: (" << nsub_boundaries_set << ")\n"
38219  << "Number of counted sub-boundaries: (" << nsub_boundaries << ")\n";
38220  throw OomphLibError(error_message.str(),
38221  OOMPH_CURRENT_FUNCTION,
38222  OOMPH_EXCEPTION_LOCATION);
38223  }
38224 #endif
38225 
38226  // Are there sub-boundaries (only appear in distributed meshes)
38227  if (this->is_mesh_distributed() && nsub_boundaries > 1)
38228  {
38229  // Mark the boundary as been splitted in the partition process
38230  this->Boundary_was_splitted[bound] = true;
38231  // Resize the vector to store the info. of sub-boundaries
38232  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
38233  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
38234  {
38235  // Turn info. into vector for ease of handling...
38236  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
38237  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
38238  unsigned subcount = 0;
38239  std::set<Vector<double>>::iterator subit;
38240  for (subit = sub_vertex_nodes[isub].begin();
38241  subit != sub_vertex_nodes[isub].end();
38242  ++subit)
38243  {
38244  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
38245  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
38246  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
38247  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
38248  ++subcount;
38249  }
38250  }
38251  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
38252  // --------- Stuff for the sub_boundaries ----- End section ------------
38253 #endif // OOMPH_HAS_MPI
38254 
38255  // For further processing the three-dimensional vector has to be
38256  // reduced to a two-dimensional vector
38257  unsigned n_vertex = tmp_vector_vertex_node.size();
38258 
38259  // Resize the vector for vectices
38260  vector_vertex_node.resize(n_vertex);
38261  for (unsigned i = 0; i < n_vertex; i++)
38262  {
38263  vector_vertex_node[i].resize(2);
38264  vector_vertex_node[i][0] = tmp_vector_vertex_node[i][1];
38265  vector_vertex_node[i][1] = tmp_vector_vertex_node[i][2];
38266  }
38267 
38268 #ifdef OOMPH_HAS_MPI
38269  // --------- Stuff for the sub_boundaries ----- Begin section ----------
38270  // Verify if need to deal with sub_boundaries
38271  if (this->is_mesh_distributed() && nsub_boundaries > 1)
38272  {
38273  // For further processing the three-dimensional vector
38274  // has to be reduced to a two-dimensional vector
38275  // Resize the vector to store the info. of sub-boundaries
38276  sub_vector_vertex_node.resize(nsub_boundaries);
38277  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
38278  {
38279  const unsigned subn_vertex = sub_tmp_vector_vertex_node[isub].size();
38280  // Resize the vector for vectices
38281  sub_vector_vertex_node[isub].resize(subn_vertex);
38282  for (unsigned i = 0; i < subn_vertex; i++)
38283  {
38284  sub_vector_vertex_node[isub][i].resize(2);
38285  sub_vector_vertex_node[isub][i][0] =
38286  sub_tmp_vector_vertex_node[isub][i][1];
38287  sub_vector_vertex_node[isub][i][1] =
38288  sub_tmp_vector_vertex_node[isub][i][2];
38289  }
38290  }
38291  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
38292 
38293  // We already have the info. for the sub-boundaries (if necessary)
38294  // and then we can create the sub-boundaries representations to
38295  // ease the generation of the mesh by Triangle
38296 
38297  // --------- Stuff for the sub_boundaries ----- End section ------------
38298 #endif // OOMPH_HAS_MPI
38299 
38300  // --------------------------------------------------------------------
38301  // Check for contiguousness
38302  // --------------------------------------------------------------------
38303 #ifdef OOMPH_HAS_MPI
38304  // Only perform this checking if the mesh is not distributed. When
38305  // the mesh is distributed the polylines continuity is addressed
38306  // by the sort_polylines_helper() method
38307  if (!this->is_mesh_distributed())
38308 #endif
38309  {
38310  if (p > 0)
38311  {
38312  // Final end point of previous line
38313  Vector<double> final_vertex_of_previous_segment;
38314  unsigned n_prev_vertex =
38315  polygon_pt->curve_section_pt(p - 1)->nvertex();
38316  final_vertex_of_previous_segment =
38317  polygon_pt->polyline_pt(p - 1)->vertex_coordinate(n_prev_vertex -
38318  1);
38319 
38320  unsigned prev_seg_boundary_id =
38321  polygon_pt->curve_section_pt(p - 1)->boundary_id();
38322 
38323  // Find the error between the final vertex of the previous
38324  // line and the first vertex of the current line
38325  double error = 0.0;
38326  for (unsigned i = 0; i < 2; i++)
38327  {
38328  const double dist = final_vertex_of_previous_segment[i] -
38329  (*vector_vertex_node.begin())[i];
38330  error += dist * dist;
38331  }
38332  error = sqrt(error);
38333 
38334  // If the error is bigger than the tolerance then
38335  // we probably need to reverse, but better check
38336  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
38337  {
38338  // Find the error between the final vertex of the previous
38339  // line and the last vertex of the current line
38340  double rev_error = 0.0;
38341  for (unsigned i = 0; i < 2; i++)
38342  {
38343  const double dist = final_vertex_of_previous_segment[i] -
38344  (*--vector_vertex_node.end())[i];
38345  rev_error += dist * dist;
38346  }
38347  rev_error = sqrt(rev_error);
38348 
38349  if (rev_error >
38350  ToleranceForVertexMismatchInPolygons::Tolerable_error)
38351  {
38352  // It could be possible that the first segment be reversed
38353  // and we did not notice it because this check does not
38354  // apply for the first segment. We can verify if the first
38355  // segment is reversed by using the vertex number 1
38356  if (p == 1)
38357  {
38358  // Initial end point of previous line
38359  Vector<double> initial_vertex_of_previous_segment;
38360 
38361  initial_vertex_of_previous_segment =
38362  polygon_pt->polyline_pt(p - 1)->vertex_coordinate(0);
38363 
38364  unsigned prev_seg_boundary_id =
38365  polygon_pt->curve_section_pt(p - 1)->boundary_id();
38366 
38367  // Find the error between the initial vertex of the previous
38368  // line and the first vertex of the current line
38369  double error = 0.0;
38370  for (unsigned i = 0; i < 2; i++)
38371  {
38372  const double dist = initial_vertex_of_previous_segment[i] -
38373  (*vector_vertex_node.begin())[i];
38374  error += dist * dist;
38375  }
38376  error = sqrt(error); // Reversed only the previous one
38377 
38378  // If the error is bigger than the tolerance then
38379  // we probably need to reverse, but better check
38380  if (error >
38381  ToleranceForVertexMismatchInPolygons::Tolerable_error)
38382  {
38383  // Find the error between the final vertex of the previous
38384  // line and the last vertex of the current line
38385  double rev_error = 0.0;
38386  for (unsigned i = 0; i < 2; i++)
38387  {
38388  const double dist = initial_vertex_of_previous_segment[i] -
38389  (*--vector_vertex_node.end())[i];
38390  rev_error += dist * dist;
38391  }
38392  rev_error =
38393  sqrt(rev_error); // Reversed both the current one and
38394  // the previous one
38395 
38396  if (rev_error >
38397  ToleranceForVertexMismatchInPolygons::Tolerable_error)
38398  {
38399  std::ostringstream error_stream;
38400  error_stream
38401  << "The distance between the first node of the current\n"
38402  << "line segment (boundary " << bound
38403  << ") and either end of "
38404  << "the previous line segment\n"
38405  << "(boundary " << prev_seg_boundary_id
38406  << ") is bigger than "
38407  << "the desired tolerance "
38408  << ToleranceForVertexMismatchInPolygons::Tolerable_error
38409  << ".\n"
38410  << "This suggests that the polylines defining the "
38411  << "polygonal\n"
38412  << "representation are not properly ordered.\n"
38413  << "Fail on last vertex of polyline: ("
38414  << prev_seg_boundary_id << ") and\n"
38415  << "first vertex of polyline (" << bound << ").\n"
38416  << "This should have failed when first trying to "
38417  << "construct the\npolygon.\n";
38418  throw OomphLibError(error_stream.str(),
38419  OOMPH_CURRENT_FUNCTION,
38420  OOMPH_EXCEPTION_LOCATION);
38421  }
38422  else
38423  {
38424  // Reverse both
38425  // Reverse the current vector to line up with the
38426  // previous one
38427  std::reverse(vector_vertex_node.begin(),
38428  vector_vertex_node.end());
38429 
38430  polygon_pt->polyline_pt(p - 1)->reverse();
38431  }
38432  }
38433  else
38434  {
38435  // Reverse the previous one
38436  polygon_pt->polyline_pt(p - 1)->reverse();
38437  }
38438 
38439  } // if p == 1
38440  else
38441  {
38442  std::ostringstream error_stream;
38443  error_stream
38444  << "The distance between the first node of the current\n"
38445  << "line segment (boundary " << bound
38446  << ") and either end of "
38447  << "the previous line segment\n"
38448  << "(boundary " << prev_seg_boundary_id
38449  << ") is bigger than the "
38450  << "desired tolerance "
38451  << ToleranceForVertexMismatchInPolygons::Tolerable_error
38452  << ".\n"
38453  << "This suggests that the polylines defining the polygonal\n"
38454  << "representation are not properly ordered.\n"
38455  << "Fail on last vertex of polyline: ("
38456  << prev_seg_boundary_id << ") and\nfirst vertex of polyline ("
38457  << bound << ").\n"
38458  << "This should have failed when first trying to construct"
38459  << " the polygon.\n";
38460  throw OomphLibError(error_stream.str(),
38461  OOMPH_CURRENT_FUNCTION,
38462  OOMPH_EXCEPTION_LOCATION);
38463  }
38464  }
38465  else
38466  {
38467  // Reverse the current vector to line up with the previous one
38468  std::reverse(vector_vertex_node.begin(),
38469  vector_vertex_node.end());
38470  }
38471  } // error
38472 
38473  } // if ( p > 0 )
38474 
38475  } // if (!this->is_mesh_distributed())
38476 
38477  // --------------------------------------------------------------------
38478  // Update the polylines representation
38479  // --------------------------------------------------------------------
38480 
38481  // Always update the polylines representation, in a distributed
38482  // mesh it is necessary to update the polyline representation since
38483  // it may no longer have vertices (the boundary may not be part of
38484  // the domain in the current processor)
38485 
38486  // The new nunber of vertices
38487  n_vertex = vector_vertex_node.size();
38488 
38489  // Now update the polyline according to the new vertices
38490  TriangleMeshPolyLine* tmp_polyline_pt =
38491  new TriangleMeshPolyLine(vector_vertex_node, bound);
38492 
38493  // Create a temporal "curve section" version of the recently
38494  // created polyline
38495  TriangleMeshCurveSection* tmp_curve_section_pt = tmp_polyline_pt;
38496 
38497  // Tolerance below which the middle point can be deleted (ratio of
38498  // deflection to element length)
38499  double unrefinement_tolerance =
38500  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
38501 
38502  // Tolerance to add points
38503  double refinement_tolerance =
38504  polygon_pt->polyline_pt(p)->refinement_tolerance();
38505 
38506  // Establish refinement and unrefinement tolerance
38507  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
38508  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
38509 
38510  // Establish the maximum length constraint
38511  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
38512  tmp_polyline_pt->set_maximum_length(maximum_length);
38513 
38514 #ifdef OOMPH_HAS_MPI
38515  // If the mesh is distributed check that the polyline still has
38516  // vertices
38517  if (this->is_mesh_distributed())
38518  {
38519  if (n_vertex >= 2)
38520  {
38521  // Pass the connection information from the old polyline to the
38522  // new one
38523  this->copy_connection_information(polygon_pt->polyline_pt(p),
38524  tmp_curve_section_pt);
38525  } // if (n_vertex >= 2)
38526  } // if (this->is_mesh_distributed())
38527  else
38528 #endif
38529  {
38530  // Pass the connection information from the old polyline to the
38531  // new one
38532  this->copy_connection_information(polygon_pt->polyline_pt(p),
38533  tmp_curve_section_pt);
38534  }
38535 
38536  // Now update the polyline according to the new vertices but first
38537  // check if the object is allowed to delete the representation or
38538  // if it should be done by other object
38539  bool delete_it_on_destructor = false;
38540 
38541  std::set<TriangleMeshCurveSection*>::iterator it =
38542  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
38543 
38544  if (it != this->Free_curve_section_pt.end())
38545  {
38546  this->Free_curve_section_pt.erase(it);
38547  delete polygon_pt->curve_section_pt(p);
38548  delete_it_on_destructor = true;
38549  }
38550 
38551  // -------------------------------------------------------
38552  // Copying the new representation
38553  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
38554 
38555  // Update the Boundary - Polyline map
38556  this->Boundary_curve_section_pt[bound] = polygon_pt->curve_section_pt(p);
38557 
38558  if (delete_it_on_destructor)
38559  {
38560  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
38561  }
38562 
38563 #ifdef OOMPH_HAS_MPI
38564  // --------- Stuff for the sub_boundaries ----- Begin section --------
38565  // Verify if need to deal with sub_boundaries
38566  if (this->is_mesh_distributed() && nsub_boundaries > 1)
38567  {
38568  // Create temporary representations for the boundaries, only to
38569  // create the mesh when calling Triangle
38570 
38571  // Clear all previous stored data
38572  this->Boundary_subpolylines[bound].clear();
38573 
38574  // Create storage for the sub-boundaries
38575  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
38576  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
38577  {
38578  // Update the polyline according to the sub set of vertices,
38579  TriangleMeshPolyLine* sub_tmp_polyline_pt =
38580  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
38581 
38582  // Add the sub-polyline to the container to represent the
38583  // boundary in parts
38584  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
38585 
38586  // No need to send the unrefinement/refinement and maximum
38587  // length constraints since these are only temporary
38588  // representations. These polylines can be deleted once the new
38589  // polygons that represent the distributed domain have been
38590  // created
38591 
38592  } // for (isub < nsub_boundaries)
38593 
38594  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
38595  // --------- Stuff for the sub_boundaries ----- End section ---------
38596 #endif // OOMPH_HAS_MPI
38597 
38598  // Delete the allocated memory for the geometric object that
38599  // represents the boundary
38600  delete mesh_geom_obj_pt;
38601 
38602  } // for (p < n_polyline)
38603 
38604  // Cleanup the face mesh
38605  for (unsigned p = 0; p < n_polyline; p++)
38606  {
38607  face_mesh_pt[p]->flush_node_storage();
38608  delete face_mesh_pt[p];
38609  }
38610 
38611  return update_was_performed;
38612  }
38613 
38614  //======================================================================
38615  /// Updates the open curve but using the elements area instead
38616  /// of the default refinement and unrefinement methods
38617  //======================================================================
38618  template<class ELEMENT>
38620  TriangleMeshOpenCurve*& open_curve_pt, const Vector<double>& target_area)
38621  {
38622  // Verify if there was a change on the open curve representation
38623  unsigned update_was_performed = false;
38624 
38625  const unsigned nele = this->nelement();
38626 
38627  // - Get the vertices along the boundaries and for each element identify
38628  // its associated target error.
38629  // - Get face mesh representation of each polyline.
38630  // - Get the vertices with the help of face elements.
38631  // - Find the global index in the mesh of the face element
38632  // and use it to get its associated target area.
38633 
38634  // Get the face mesh representation
38635  Vector<Mesh*> face_mesh_pt;
38636  get_face_mesh_representation(open_curve_pt, face_mesh_pt);
38637 
38638  // Create vertices of the polylines by using the vertices of the
38639  // FaceElements
38640  Vector<double> vertex_coord(3); // zeta,x,y
38641  Vector<double> bound_left(1);
38642  Vector<double> bound_right(1);
38643 
38644  const unsigned ncurve_section = open_curve_pt->ncurve_section();
38645 
38646  // Go for each curve section
38647  for (unsigned cs = 0; cs < ncurve_section; cs++)
38648  {
38649  // Get the MeshAsGeomObject representation just once per polyline,
38650  // this object is only used by the
38651  // refine_boundary_constrained_by_target_area() method. We get it
38652  // here to ensure that all processors (in a distributed context)
38653  // get this representation just once, and because an AllToAll MPI
38654  // communication is used in this calling
38655  MeshAsGeomObject* mesh_geom_obj_pt =
38656  new MeshAsGeomObject(face_mesh_pt[cs]);
38657 
38658  // Get the boundary id
38659  const unsigned bound = open_curve_pt->curve_section_pt(cs)->boundary_id();
38660 
38661  // Get the chunk number
38662  const unsigned chunk =
38663  open_curve_pt->curve_section_pt(cs)->boundary_chunk();
38664 
38665  /// Use a vector of vector for vertices and target areas to deal
38666  /// with the cases when the boundaries are split by the
38667  /// distribution process. Internal boundaries may be completely or
38668  /// partially overlapped by shared boundaries
38669 
38670  // Loop over the face elements and add their vertices (they are
38671  // automatically sorted because of the set)
38672  const unsigned nface_element = face_mesh_pt[cs]->nelement();
38673 
38674  // Store the non halo elements and the element at the other side of
38675  // the boundary (whatever it be halo or not), the first will be the
38676  // ones from which we will get the vertices (in even position)
38677  Vector<FiniteElement*> non_halo_doubled_face_element_pt;
38678 
38679  // Map to store the index of the face element on a boundary
38680  std::map<FiniteElement*, unsigned> face_element_index_on_boundary;
38681 
38682  // Map to know the already sorted face elements
38683  std::map<FiniteElement*, bool> face_element_done;
38684 
38685  for (unsigned ef = 0; ef < nface_element; ++ef)
38686  {
38687  FiniteElement* ele_face_pt = face_mesh_pt[cs]->finite_element_pt(ef);
38688 
38689  // Skip the halo elements (not used as base elements, only
38690  // include those elements whose element at the other side of the
38691  // boundary is non halo)
38692 #ifdef OOMPH_HAS_MPI
38693  if (this->is_mesh_distributed())
38694  {
38695  // Only work with non-halo elements
38696  if (ele_face_pt->is_halo())
38697  {
38698  continue;
38699  }
38700  }
38701 #endif
38702 
38703  // Check if not already done
38704  if (!face_element_done[ele_face_pt])
38705  {
38706  // Add the element and look for the element at the other side
38707  // of the boundary to add it immediately after the new added
38708  // element
38709  non_halo_doubled_face_element_pt.push_back(ele_face_pt);
38710  // Create the map of the face element with the index
38711  face_element_index_on_boundary[ele_face_pt] = ef;
38712  // Mark the current element as done
38713  face_element_done[ele_face_pt] = true;
38714  // Get the number of nodes
38715  const unsigned nnodes = ele_face_pt->nnode();
38716  // Get the left and right node to look for the elements at the
38717  // other side of the boundary
38718  Node* left_node_pt = ele_face_pt->node_pt(0);
38719  Node* right_node_pt = ele_face_pt->node_pt(nnodes - 1);
38720 #ifdef PARANOID
38721  // Flag to know if the element at the other side of the
38722  // boundary was found
38723  bool found_other_side_face_ele = false;
38724 #endif
38725  for (unsigned iface = 0; iface < nface_element; iface++)
38726  {
38727  // Get the candidate face element
38728  FiniteElement* cele_face_pt =
38729  face_mesh_pt[cs]->finite_element_pt(iface);
38730  // Check if not already done
38731  if (!face_element_done[cele_face_pt])
38732  {
38733  Node* cleft_node_pt = cele_face_pt->node_pt(0);
38734  Node* cright_node_pt = cele_face_pt->node_pt(nnodes - 1);
38735  // Check if the nodes are the same
38736  if ((left_node_pt == cleft_node_pt &&
38737  right_node_pt == cright_node_pt) ||
38738  (left_node_pt == cright_node_pt &&
38739  right_node_pt == cleft_node_pt))
38740  {
38741  // Add the element to the storage
38742  non_halo_doubled_face_element_pt.push_back(cele_face_pt);
38743  // ... and mark the element as done
38744  face_element_done[cele_face_pt] = true;
38745  // Create the map of the face element with the index
38746  face_element_index_on_boundary[cele_face_pt] = iface;
38747 #ifdef PARANOID
38748  // Set the flag of found other side face element
38749  found_other_side_face_ele = true;
38750 #endif
38751  break;
38752  }
38753  }
38754  } // (iface < nface_element)
38755 
38756 #ifdef PARANOID
38757  if (!found_other_side_face_ele)
38758  {
38759  std::ostringstream error_message;
38760  error_message
38761  << "The face element at the other side of the boundary (" << bound
38762  << ") was not found!!\n"
38763  << "These are the nodes of the face element:\n"
38764  << "(" << left_node_pt->x(0) << ", " << left_node_pt->x(1) << ") "
38765  << "and (" << right_node_pt->x(0) << "," << right_node_pt->x(1)
38766  << ")\n\n";
38767  throw OomphLibError(
38768  error_message.str(),
38769  "RefineableTriangleMesh::update_open_curve_using_elements_area()",
38770  OOMPH_EXCEPTION_LOCATION);
38771  }
38772 #endif
38773  } // if (!face_ele_done[ele_face_pt])
38774 
38775  } // (ef < nface_element)
38776 
38777  // Clear the map of the already done face elements
38778  // This will be used to help sorting the face elements
38779  face_element_done.clear();
38780 
38781  // Set of coordinates that are on the boundary
38782  // The entries are sorted on first entry in vector which stores
38783  // the boundary coordinate so the vertices come out in order!
38784  std::set<Vector<double>> vertex_nodes;
38785 
38786  // Vector to store the vertices, transfer the sorted vertices from the
38787  // set to this vector, --- including the z-value ---
38788  Vector<Vector<double>> tmp_vector_vertex_node;
38789 
38790  // Vector to store the coordinates of the polylines, same as the
38791  // tmp_vector_vertex_node vector (after adding more nodes) but
38792  // --- without the z-value ---, used to re-generate the polylines
38793  Vector<Vector<double>> vector_vertex_node;
38794 
38795 #ifdef OOMPH_HAS_MPI
38796  // Indicates if the set of vertices give rise to a internal
38797  // boundary that will be used as shared boundary or as normal
38798  // internal boundary -- Only used to deal with internal boundaries
38799  // in a distributed scheme
38800  std::vector<bool> internal_to_shared_boundary;
38801 
38802  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
38803  // Set of coordinates that are on the boundary (splitted boundary version)
38804  // The first vector is used to allocate the points for each sub-boundary
38805  // Set entries are ordered on first entry in vector which stores
38806  // the boundary coordinate so the vertices come out in order!
38807  Vector<std::set<Vector<double>>> sub_vertex_nodes;
38808 
38809  // Vector to store the vertices, transfer the sorted vertices from the
38810  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
38811  Vector<Vector<Vector<double>>> sub_tmp_vector_vertex_node;
38812 
38813  // Vector to store the coordinates of the polylines that will represent
38814  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
38815  // but --- without the z-value ---, used to generate the sub-polylines
38816  Vector<Vector<Vector<double>>> sub_vector_vertex_node;
38817 
38818  // --------- Stuff to deal with splitted boundaries ----------- End ------
38819 
38820 #endif // #ifdef OOMPH_HAS_MPI
38821 
38822  // Sort the face element, those that have both elements (one at
38823  // each side of the boundary) marked as nonhalo, and those with one
38824  // nonhalo an the other as halo
38825 
38826  // Number of done face elements
38827  unsigned nsorted_face_elements = 0;
38828 
38829 #ifdef OOMPH_HAS_MPI
38830  // Counter for sub_boundaries
38831  unsigned nsub_boundaries = 0;
38832 #endif // #ifdef OOMPH_HAS_MPI
38833 
38834  // Total number of non halo double face element
38835  const unsigned nnon_halo_doubled_face_ele =
38836  non_halo_doubled_face_element_pt.size();
38837 
38838  // Continue until all the face elements have been sorted
38839  // This while is to deal with the cases of splitted boundaries
38840  while (nsorted_face_elements < nnon_halo_doubled_face_ele)
38841  {
38842  // Get and initial face element
38843  FiniteElement* ele_face_pt = 0;
38844  FiniteElement* repeated_ele_face_pt = 0;
38845 #ifdef PARANOID
38846  bool found_initial_face_element = false;
38847 #endif
38848 
38849  // Flag to know if we are working with a face element which the
38850  // face element at the other side of the boundary is also non
38851  // halo
38852  bool both_root_face_elements_are_nonhalo = false;
38853 
38854  unsigned iface = 0;
38855  for (iface = 0; iface < nnon_halo_doubled_face_ele; iface += 2)
38856  {
38857  ele_face_pt = non_halo_doubled_face_element_pt[iface];
38858  // If not done then take it as initial face element
38859  if (!face_element_done[ele_face_pt])
38860  {
38861  // Mark it as done
38862  face_element_done[ele_face_pt] = true;
38863  // Get the other side boundary face element
38864  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iface + 1];
38865  // ... also mark as done the repeated face element
38866  face_element_done[repeated_ele_face_pt] = true;
38867 
38868 #ifdef OOMPH_HAS_MPI
38869  if (!repeated_ele_face_pt->is_halo())
38870  {
38871  both_root_face_elements_are_nonhalo = true;
38872  }
38873 #endif // #ifdef OOMPH_HAS_MPI
38874 
38875  // Plus two because internal boundaries have
38876  // two face elements per each edge
38877  nsorted_face_elements += 2;
38878  iface += 2;
38879 #ifdef PARANOID
38880  // And set the flag to true
38881  found_initial_face_element = true;
38882 #endif
38883  break;
38884  }
38885  }
38886 
38887 #ifdef PARANOID
38888  if (!found_initial_face_element)
38889  {
38890  std::ostringstream error_message;
38891  error_message << "Could not find an initial face element for the "
38892  "current segment\n";
38893  throw OomphLibError(error_message.str(),
38894  OOMPH_CURRENT_FUNCTION,
38895  OOMPH_EXCEPTION_LOCATION);
38896  }
38897 #endif
38898 
38899  // Local set of coordinates that are on the boundary Set entries
38900  // are ordered on first entry in vector which stores the boundary
38901  // coordinate so the vertices come out in order
38902  std::set<Vector<double>> local_vertex_nodes;
38903 
38904  // Vector to store the vertices, transfer the sorted vertices from the
38905  // set (local) to this vector (local), --- including the z-value ---
38906  Vector<Vector<double>> local_tmp_vector_vertex_node;
38907 
38908  // Vector to store the target areas, uses the same approach as the
38909  // set for the local_vertex_nodes, ordered on first entry
38910  std::set<Vector<double>> sorted_target_areas;
38911 
38912  // Vector to store the target areas, used to transfer the sorted target
38913  // areas from "sorted_target_areas" set
38914  Vector<double> tmp_sorted_target_areas;
38915 
38916  // ------------------------------------------------------------------
38917  // Add the vertices of the initial face element to the set of local
38918  // sorted vertices
38919  // ------------------------------------------------------------------
38920  const unsigned nnode = ele_face_pt->nnode();
38921  // Add the left-hand node to the set:
38922  // Boundary coordinate
38923  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound, bound_left);
38924  vertex_coord[0] = bound_left[0];
38925 
38926  // Actual coordinates
38927  for (unsigned i = 0; i < 2; i++)
38928  {
38929  vertex_coord[i + 1] = ele_face_pt->node_pt(0)->x(i);
38930  }
38931  local_vertex_nodes.insert(vertex_coord);
38932 
38933  // Add the right-hand node to the set:
38934  // Boundary coordinate
38935  ele_face_pt->node_pt(nnode - 1)->get_coordinates_on_boundary(
38936  bound, bound_right);
38937  vertex_coord[0] = bound_right[0];
38938 
38939  // Actual coordinates
38940  for (unsigned i = 0; i < 2; i++)
38941  {
38942  vertex_coord[i + 1] = ele_face_pt->node_pt(nnode - 1)->x(i);
38943  }
38944  local_vertex_nodes.insert(vertex_coord);
38945 
38946  // The initial and final node on the set
38947  Node* first_node_pt = ele_face_pt->node_pt(0);
38948  Node* last_node_pt = ele_face_pt->node_pt(nnode - 1);
38949 
38950  // -----------------------------------------------------
38951  // Find the global index in the mesh of the face element
38952  // and use it to get its associated target area
38953  // -----------------------------------------------------
38954  // Container to store the zeta value (used as index) and
38955  // the associated target area of the element
38956  Vector<double> zeta_target_area_values(2);
38957 
38958  // Use the minimum zeta value to sort the target areas
38959  // along the boundary
38960  zeta_target_area_values[0] = std::min(bound_left[0], bound_right[0]);
38961 
38962  // Get the index of the face element on the current boundary
38963  const unsigned ef = face_element_index_on_boundary[ele_face_pt];
38964  // Get the "ef"-th element on the boundary
38965  FiniteElement* el_pt = this->boundary_element_pt(bound, ef);
38966  double target_area_face_element = 0.0;
38967 
38968 #ifdef PARANOID
38969  bool found_global_element_index = false;
38970 #endif
38971  for (unsigned eg = 0; eg < nele; eg++)
38972  {
38973  // Get the "eg-th" element
38974  FiniteElement* el_compare_pt = this->finite_element_pt(eg);
38975 
38976  // Compare with the element on the boundary, if equal then
38977  // store the target area
38978  if (el_pt == el_compare_pt)
38979  {
38980  target_area_face_element = target_area[eg];
38981 #ifdef PARANOID
38982  found_global_element_index = true;
38983 #endif
38984  break; // break the for (eg < nele) global element
38985  } // if el_pt == el_compare_pt
38986  } // for nele (on complete mesh)
38987 
38988 #ifdef PARANOID
38989  if (!found_global_element_index)
38990  {
38991  std::ostringstream error_message;
38992  error_message << "The global index for the (" << ef
38993  << ")-th face element "
38994  << "on\nthe (" << bound
38995  << ")-th boundary was not found!!!";
38996  throw OomphLibError(error_message.str(),
38997  OOMPH_CURRENT_FUNCTION,
38998  OOMPH_EXCEPTION_LOCATION);
38999  }
39000 #endif
39001 
39002  // Get the index of the repeated face element on the current boundary
39003  const unsigned ref =
39004  face_element_index_on_boundary[repeated_ele_face_pt];
39005  FiniteElement* rel_pt = this->boundary_element_pt(bound, ref);
39006  double target_area_repeated_face_element = 0.0;
39007 
39008 #ifdef PARANOID
39009  bool found_global_repeated_element_index = false;
39010 #endif
39011  for (unsigned eg = 0; eg < nele; eg++)
39012  {
39013  // Get the "eg-th" element
39014  FiniteElement* el_compare_pt = this->finite_element_pt(eg);
39015 
39016  // Compare with the element on the boundary, if equal then
39017  // store the target area
39018  if (rel_pt == el_compare_pt)
39019  {
39020  target_area_repeated_face_element = target_area[eg];
39021 #ifdef PARANOID
39022  found_global_repeated_element_index = true;
39023 #endif
39024  break; // break the for (eg < nele) global element
39025  } // if rel_pt == el_compare_pt
39026  } // for nele (on complete mesh)
39027 
39028 #ifdef PARANOID
39029  if (!found_global_repeated_element_index)
39030  {
39031  std::ostringstream error_message;
39032  error_message << "The global index for the (" << ref
39033  << ")-th face element "
39034  << "on\nthe (" << bound
39035  << ")-th boundary was not found (repeated "
39036  << "face element)!!!";
39037  throw OomphLibError(error_message.str(),
39038  OOMPH_CURRENT_FUNCTION,
39039  OOMPH_EXCEPTION_LOCATION);
39040  }
39041 #endif
39042 
39043  // Choose the minimum target area from both elements, one at each side
39044  // of the edge on the boundary
39045  zeta_target_area_values[1] =
39046  std::min(target_area_face_element, target_area_repeated_face_element);
39047 
39048  // Add the target areas to the sorted set
39049  sorted_target_areas.insert(zeta_target_area_values);
39050  // ------------------------------------------------------------------
39051 
39052  // Continue iterating if a new face element has been added to the
39053  // list
39054  bool face_element_added = false;
39055 
39056  // While a new face element has been added to the set of sorted
39057  // face elements then re-iterate
39058  do
39059  {
39060  // Start from the next face elements since we have already
39061  // added the previous one as the initial face element (any
39062  // previous face element had to be added on previous
39063  // iterations)
39064  for (unsigned iiface = iface; iiface < nnon_halo_doubled_face_ele;
39065  iiface += 2)
39066  {
39067  face_element_added = false;
39068  ele_face_pt = non_halo_doubled_face_element_pt[iiface];
39069 
39070  // Check that the face element with which we are working has
39071  // the same conditions as the root face element (both faces
39072  // are nonhalo or one face is halo and the other nonhalo)
39073 
39074  // Get the face element at the other side of the boundary
39075  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface + 1];
39076  bool both_face_elements_are_nonhalo = false;
39077 
39078 #ifdef OOMPH_HAS_MPI
39079  if (!repeated_ele_face_pt->is_halo())
39080  {
39081  both_face_elements_are_nonhalo = true;
39082  }
39083 #endif // #ifdef OOMPH_HAS_MPI
39084 
39085  if (!face_element_done[ele_face_pt] &&
39086  (both_face_elements_are_nonhalo ==
39087  both_root_face_elements_are_nonhalo))
39088  {
39089  // Get each individual node to check if they are contiguous
39090  const unsigned nlnode = ele_face_pt->nnode();
39091  Node* left_node_pt = ele_face_pt->node_pt(0);
39092  Node* right_node_pt = ele_face_pt->node_pt(nlnode - 1);
39093 
39094  if (left_node_pt == first_node_pt)
39095  {
39096  first_node_pt = right_node_pt;
39097  face_element_added = true;
39098  }
39099  else if (left_node_pt == last_node_pt)
39100  {
39101  last_node_pt = right_node_pt;
39102  face_element_added = true;
39103  }
39104  else if (right_node_pt == first_node_pt)
39105  {
39106  first_node_pt = left_node_pt;
39107  face_element_added = true;
39108  }
39109  else if (right_node_pt == last_node_pt)
39110  {
39111  last_node_pt = left_node_pt;
39112  face_element_added = true;
39113  }
39114 
39115  if (face_element_added)
39116  {
39117  // Add the left-hand node to the set:
39118  // Boundary coordinate
39119  left_node_pt->get_coordinates_on_boundary(bound, bound_left);
39120  vertex_coord[0] = bound_left[0];
39121 
39122  // Actual coordinates
39123  for (unsigned i = 0; i < 2; i++)
39124  {
39125  vertex_coord[i + 1] = left_node_pt->x(i);
39126  }
39127  local_vertex_nodes.insert(vertex_coord);
39128 
39129  // Add the right-hand nodes to the set:
39130  // Boundary coordinate
39131  right_node_pt->get_coordinates_on_boundary(bound, bound_right);
39132  vertex_coord[0] = bound_right[0];
39133 
39134  // Actual coordinates
39135  for (unsigned i = 0; i < 2; i++)
39136  {
39137  vertex_coord[i + 1] = right_node_pt->x(i);
39138  }
39139  local_vertex_nodes.insert(vertex_coord);
39140 
39141  // Mark as done only if one of its nodes has been
39142  // added to the list
39143  face_element_done[ele_face_pt] = true;
39144  // .. also mark as done the face element at the othe side of
39145  // the boundary
39146  repeated_ele_face_pt =
39147  non_halo_doubled_face_element_pt[iiface + 1];
39148  face_element_done[repeated_ele_face_pt] = true;
39149  // ... and increase the number of sorted face elements
39150  nsorted_face_elements += 2;
39151 
39152  // -----------------------------------------------------
39153  // Find the global index in the mesh of the face element
39154  // and use it to get its associated target area
39155  // -----------------------------------------------------
39156  // Use the minimum zeta value to sort the target areas
39157  // along the boundary
39158  zeta_target_area_values[0] =
39159  std::min(bound_left[0], bound_right[0]);
39160 
39161  // Get the "ef"-th element on the boundary
39162  const unsigned lef =
39163  face_element_index_on_boundary[ele_face_pt];
39164  FiniteElement* lel_pt = this->boundary_element_pt(bound, lef);
39165 
39166 #ifdef PARANOID
39167  found_global_element_index = false;
39168 #endif
39169  for (unsigned eg = 0; eg < nele; eg++)
39170  {
39171  // Get the "eg-th" element
39172  FiniteElement* lel_compare_pt = this->finite_element_pt(eg);
39173 
39174  // Compare with the element on the boundary, if equal then
39175  // store the target area
39176  if (lel_pt == lel_compare_pt)
39177  {
39178  target_area_face_element = target_area[eg];
39179 #ifdef PARANOID
39180  found_global_element_index = true;
39181 #endif
39182  break; // break the for (eg < nele) global element
39183  } // if lel_pt == lel_compare_pt
39184  } // for nele (on complete mesh)
39185 
39186 #ifdef PARANOID
39187  if (!found_global_element_index)
39188  {
39189  std::ostringstream error_message;
39190  error_message << "The global index for the (" << lef
39191  << ")-th face element "
39192  << "on\nthe (" << bound
39193  << ")-th boundary was not found!!!";
39194  throw OomphLibError(error_message.str(),
39195  OOMPH_CURRENT_FUNCTION,
39196  OOMPH_EXCEPTION_LOCATION);
39197  }
39198 #endif
39199 
39200  // Get the index of the repeated face element on the boundary
39201  const unsigned rlef =
39202  face_element_index_on_boundary[repeated_ele_face_pt];
39203  FiniteElement* rlel_pt = this->boundary_element_pt(bound, rlef);
39204 
39205 #ifdef PARANOID
39206  found_global_repeated_element_index = false;
39207 #endif
39208  for (unsigned eg = 0; eg < nele; eg++)
39209  {
39210  // Get the "eg-th" element
39211  FiniteElement* lel_compare_pt = this->finite_element_pt(eg);
39212 
39213  // Compare with the element on the boundary, if equal then
39214  // store the target area
39215  if (rlel_pt == lel_compare_pt)
39216  {
39217  target_area_repeated_face_element = target_area[eg];
39218 #ifdef PARANOID
39219  found_global_repeated_element_index = true;
39220 #endif
39221  break; // break the for (eg < nele) global element
39222  } // if rlel_pt == el_compare_pt
39223  } // for nele (on complete mesh)
39224 
39225 #ifdef PARANOID
39226  if (!found_global_repeated_element_index)
39227  {
39228  std::ostringstream error_message;
39229  error_message << "The global index for the (" << rlef
39230  << ")-th face element "
39231  << "on\nthe (" << bound
39232  << ")-th boundary was not found "
39233  << "(repeated face element)!!!";
39234  throw OomphLibError(error_message.str(),
39235  OOMPH_CURRENT_FUNCTION,
39236  OOMPH_EXCEPTION_LOCATION);
39237  }
39238 #endif
39239 
39240  // Choose the minimum target area from both elements, one
39241  // at each side of the edge on the boundary
39242  zeta_target_area_values[1] = std::min(
39243  target_area_face_element, target_area_repeated_face_element);
39244 
39245  // Add the target areas to the sorted set
39246  sorted_target_areas.insert(zeta_target_area_values);
39247 
39248  break;
39249  }
39250 
39251  } // if (!face_element_done[[ele_face_pt])
39252  } // for (iiface<nnon_halo_doubled_face_ele)
39253  } while (face_element_added &&
39254  (nsorted_face_elements < nnon_halo_doubled_face_ele));
39255 
39256  // -------------------------------------------------------------
39257  // At this point we already have a sorted set of nodes and can
39258  // be used to peform the unrefinement and refinement procedures
39259  // -------------------------------------------------------------
39260 
39261  // Get the number of nodes on the list
39262  const unsigned nlocal_nodes = local_vertex_nodes.size();
39263  // Change representation to vector for easy of handling ...
39264  local_tmp_vector_vertex_node.resize(nlocal_nodes);
39265 
39266  // Copy the vertices of the nodes
39267  unsigned counter = 0;
39268  std::set<Vector<double>>::iterator it_vertex;
39269  for (it_vertex = local_vertex_nodes.begin();
39270  it_vertex != local_vertex_nodes.end();
39271  it_vertex++)
39272  {
39273  local_tmp_vector_vertex_node[counter].resize(3);
39274  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
39275  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
39276  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
39277  counter++;
39278  }
39279 
39280  // ... same for the info. related with the target areas (turn
39281  // into vector)
39282  const unsigned ntarget_areas = sorted_target_areas.size();
39283  tmp_sorted_target_areas.resize(ntarget_areas);
39284  counter = 0;
39285  std::set<Vector<double>>::iterator it_area;
39286  for (it_area = sorted_target_areas.begin();
39287  it_area != sorted_target_areas.end();
39288  ++it_area)
39289  {
39290  tmp_sorted_target_areas[counter] = (*it_area)[1];
39291  ++counter;
39292  }
39293 
39294 #ifdef PARANOID
39295  if (nlocal_nodes > 0 && (ntarget_areas != nlocal_nodes - 1))
39296  {
39297  std::ostringstream error_message;
39298  error_message
39299  << "The boundary (" << bound << ") was split during the "
39300  << "distribution process.\n"
39301  << "The problem comes when associating the target areas with the "
39302  << "elements that gave\nrise to the vertex coordinates.\n"
39303  << "The number of local nodes on the 'sub-polyline' ("
39304  << nlocal_nodes << ") is not according with the number of target\n"
39305  << "areas (" << ntarget_areas << ") for that number of nodes.\n"
39306  << "The target areas number must be equal to the number of "
39307  "nodes-1\n";
39308  throw OomphLibError(error_message.str(),
39309  OOMPH_CURRENT_FUNCTION,
39310  OOMPH_EXCEPTION_LOCATION);
39311  }
39312 #endif
39313 
39314  // The unrefinement and refinement process needs to be applied
39315  // from the bottom-left node since the internal open curve could
39316  // lie on the shared boundaries
39317  if (local_tmp_vector_vertex_node[nlocal_nodes - 1][2] <
39318  local_tmp_vector_vertex_node[0][2])
39319  {
39320  std::reverse(local_tmp_vector_vertex_node.begin(),
39321  local_tmp_vector_vertex_node.end());
39322  std::reverse(tmp_sorted_target_areas.begin(),
39323  tmp_sorted_target_areas.end());
39324  }
39325  else if (local_tmp_vector_vertex_node[nlocal_nodes - 1][2] ==
39326  local_tmp_vector_vertex_node[0][2])
39327  {
39328  if (local_tmp_vector_vertex_node[nlocal_nodes - 1][1] <
39329  local_tmp_vector_vertex_node[0][1])
39330  {
39331  std::reverse(local_tmp_vector_vertex_node.begin(),
39332  local_tmp_vector_vertex_node.end());
39333  std::reverse(tmp_sorted_target_areas.begin(),
39334  tmp_sorted_target_areas.end());
39335  }
39336  }
39337 
39338  // ------------------------------------------------------------
39339  // Create the vertices along the boundary using the target
39340  // area to define the distance among them
39341  // ------------------------------------------------------------
39342 
39343  // Tolerance below which the middle point can be deleted
39344  // (ratio of deflection to element length)
39345  double unrefinement_tolerance =
39346  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
39347 
39348  // Apply unrefinement
39349  bool unrefinement_applied =
39350  unrefine_boundary_constrained_by_target_area(
39351  bound,
39352  chunk,
39353  local_tmp_vector_vertex_node,
39354  unrefinement_tolerance,
39355  tmp_sorted_target_areas);
39356 
39357  // Tolerance for refinement
39358  double refinement_tolerance =
39359  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
39360 
39361  // Apply refinement
39362  bool refinement_applied = refine_boundary_constrained_by_target_area(
39363  mesh_geom_obj_pt,
39364  local_tmp_vector_vertex_node,
39365  refinement_tolerance,
39366  tmp_sorted_target_areas);
39367 
39368  // Clear the local containter to recover the nodes ordered using
39369  // the zeta value
39370  local_vertex_nodes.clear();
39371 
39372  // At the end of each unrefinement/refinement step store the new
39373  // nodes on the set that will give rise to the vertices of the
39374  // new polyline representation
39375  const unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
39376  for (unsigned i = 0; i < nnew_nodes; i++)
39377  {
39378  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
39379  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
39380  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
39381  vertex_nodes.insert(vertex_coord); // Global container
39382  local_vertex_nodes.insert(vertex_coord);
39383  }
39384 
39385  // Update the flag to indicate whether an unrefinement or
39386  // refinement was applied
39387  update_was_performed = (unrefinement_applied || refinement_applied);
39388 
39389 #ifdef OOMPH_HAS_MPI
39390  if (this->is_mesh_distributed())
39391  {
39392  // Add the set of vertices for the boundary, this will help to
39393  // detect if we need to deal with sub_boundaries and
39394  // sub_polylines representations
39395  sub_vertex_nodes.push_back(local_vertex_nodes);
39396  // Increase the counter for sub_boundaries
39397  nsub_boundaries++;
39398 
39399  // Mark if the polyline created by these vertices will be used
39400  // as a shared boundary or as an internal boundary
39401  if (both_root_face_elements_are_nonhalo)
39402  {
39403  internal_to_shared_boundary.push_back(false);
39404  }
39405  else
39406  {
39407  internal_to_shared_boundary.push_back(true);
39408  }
39409  }
39410 #endif
39411 
39412  } // while(nsorted_face_elements < nnon_halo_doubled_face_ele)
39413  // This while is in charge of sorting all the face elements to
39414  // create the new representation of the polyline (also deals
39415  // with the sub-boundary cases)
39416 
39417  // Now turn into vector for ease of handling...
39418  const unsigned npoly_vertex = vertex_nodes.size();
39419  tmp_vector_vertex_node.resize(npoly_vertex);
39420  unsigned count = 0;
39421  for (std::set<Vector<double>>::iterator it = vertex_nodes.begin();
39422  it != vertex_nodes.end();
39423  ++it)
39424  {
39425  tmp_vector_vertex_node[count].resize(3);
39426  tmp_vector_vertex_node[count][0] = (*it)[0];
39427  tmp_vector_vertex_node[count][1] = (*it)[1];
39428  tmp_vector_vertex_node[count][2] = (*it)[2];
39429  ++count;
39430  }
39431 
39432 #ifdef OOMPH_HAS_MPI
39433  // Check that the number of set of vertices marked to be part of a
39434  // shared boundary or of an internal boundaries be the same as the
39435  // total number of sub-boundaries
39436 #ifdef PARANOID
39437  const unsigned nsub_boundaries_set = sub_vertex_nodes.size();
39438  const unsigned ninternal_to_shared_boundaries =
39439  internal_to_shared_boundary.size();
39440  if (nsub_boundaries_set != ninternal_to_shared_boundaries)
39441  {
39442  std::ostringstream error_message;
39443  error_message
39444  << "The number of found sub-boundaries and the number of marked "
39445  << "internal\nboundaries are different\n"
39446  << "Number of found sub-boundaries: (" << nsub_boundaries_set << ")\n"
39447  << "Number of marked internal boundaries: ("
39448  << ninternal_to_shared_boundaries << ")\n\n";
39449  throw OomphLibError(error_message.str(),
39450  OOMPH_CURRENT_FUNCTION,
39451  OOMPH_EXCEPTION_LOCATION);
39452  }
39453 #endif
39454 
39455  // --------- Stuff for the sub_boundaries ----- Begin section -------
39456 #ifdef PARANOID
39457  if (nsub_boundaries_set != nsub_boundaries)
39458  {
39459  std::ostringstream error_message;
39460  error_message
39461  << "The number of found sub-boundaries and the number of counted\n"
39462  << "sub-boundaries are different:\n"
39463  << "Number of found sub-boundaries: (" << nsub_boundaries_set << ")\n"
39464  << "Number of counted sub-boundaries: (" << nsub_boundaries
39465  << ")\n\n";
39466  throw OomphLibError(error_message.str(),
39467  OOMPH_CURRENT_FUNCTION,
39468  OOMPH_EXCEPTION_LOCATION);
39469  }
39470 #endif
39471 
39472  // Verify if need to deal with sub_boundaries
39473  if (this->is_mesh_distributed() && nsub_boundaries > 1)
39474  {
39475  // Mark the boundary as been splitted in the partition process
39476  this->Boundary_was_splitted[bound] = true;
39477 
39478  // Resize the vector to store the info. of sub-boundaries
39479  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
39480  // Loop over the sub-boundaries
39481  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39482  {
39483  // Turn info. into vector for ease of handling...
39484  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
39485  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
39486  unsigned subcount = 0;
39487  std::set<Vector<double>>::iterator subit;
39488  for (subit = sub_vertex_nodes[isub].begin();
39489  subit != sub_vertex_nodes[isub].end();
39490  ++subit)
39491  {
39492  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
39493  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
39494  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
39495  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
39496  ++subcount;
39497  }
39498  }
39499  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39500  // --------- Stuff for the sub_boundaries ----- End section ----------
39501 #endif // OOMPH_HAS_MPI
39502 
39503  // For further processing the three-dimensional vector has to be
39504  // reduced to a two-dimensional vector
39505  unsigned n_vertex = tmp_vector_vertex_node.size();
39506 
39507  // Resize the vector for vectices
39508  vector_vertex_node.resize(n_vertex);
39509  for (unsigned i = 0; i < n_vertex; i++)
39510  {
39511  vector_vertex_node[i].resize(2);
39512  vector_vertex_node[i][0] = tmp_vector_vertex_node[i][1];
39513  vector_vertex_node[i][1] = tmp_vector_vertex_node[i][2];
39514  }
39515 
39516 #ifdef OOMPH_HAS_MPI
39517  // --------- Stuff for the sub_boundaries ----- Begin section -------
39518  // Verify if need to deal with sub_boundaries
39519  if (this->is_mesh_distributed() && nsub_boundaries > 1)
39520  {
39521  // For further processing the three-dimensional vector has to be
39522  // reduced to a two-dimensional vector
39523  // Resize the vector to store the info. of sub-boundaries
39524  sub_vector_vertex_node.resize(nsub_boundaries);
39525  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39526  {
39527  const unsigned subn_vertex = sub_tmp_vector_vertex_node[isub].size();
39528  // Resize the vector for vectices
39529  sub_vector_vertex_node[isub].resize(subn_vertex);
39530  for (unsigned i = 0; i < subn_vertex; i++)
39531  {
39532  sub_vector_vertex_node[isub][i].resize(2);
39533  sub_vector_vertex_node[isub][i][0] =
39534  sub_tmp_vector_vertex_node[isub][i][1];
39535  sub_vector_vertex_node[isub][i][1] =
39536  sub_tmp_vector_vertex_node[isub][i][2];
39537  }
39538  }
39539  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39540 
39541  // We already have the info. for the sub-boundaries (if necessary)
39542  // and then we can create the sub-boundaries representations to
39543  // ease the generation of the mesh by Triangle
39544 
39545  // --------- Stuff for the sub_boundaries ----- End section ---------
39546 #endif // OOMPH_HAS_MPI
39547 
39548  // ------------------------------------------------------------------
39549  // Check for contiguousness
39550  // ------------------------------------------------------------------
39551 #ifdef OOMPH_HAS_MPI
39552  // Only perform this checking if the mesh is not distributed When
39553  // the mesh is distributed the polylines continuity is addressed by
39554  // the sort_polylines_helper() method
39555  if (!this->is_mesh_distributed())
39556 #endif
39557  {
39558  if (cs > 0)
39559  {
39560  // Final end point of previous line
39561  Vector<double> final_vertex_of_previous_segment;
39562  unsigned n_prev_vertex =
39563  open_curve_pt->curve_section_pt(cs - 1)->nvertex();
39564  final_vertex_of_previous_segment =
39565  open_curve_pt->polyline_pt(cs - 1)->vertex_coordinate(
39566  n_prev_vertex - 1);
39567 
39568  unsigned prev_seg_boundary_id =
39569  open_curve_pt->curve_section_pt(cs - 1)->boundary_id();
39570 
39571  // Find the error between the final vertex of the previous
39572  // line and the first vertex of the current line
39573  double error = 0.0;
39574  for (unsigned i = 0; i < 2; i++)
39575  {
39576  const double dist = final_vertex_of_previous_segment[i] -
39577  (*vector_vertex_node.begin())[i];
39578  error += dist * dist;
39579  }
39580  error = sqrt(error);
39581 
39582  // If the error is bigger than the tolerance then
39583  // we probably need to reverse, but better check
39584  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
39585  {
39586  // Find the error between the final vertex of the previous
39587  // line and the last vertex of the current line
39588  double rev_error = 0.0;
39589  for (unsigned i = 0; i < 2; i++)
39590  {
39591  const double dist = final_vertex_of_previous_segment[i] -
39592  (*--vector_vertex_node.end())[i];
39593  rev_error += dist * dist;
39594  }
39595  rev_error = sqrt(rev_error);
39596 
39597  if (rev_error >
39598  ToleranceForVertexMismatchInPolygons::Tolerable_error)
39599  {
39600  // It could be possible that the first segment be reversed and we
39601  // did not notice it because this check does not apply for the
39602  // first segment. We can verify if the first segment is reversed
39603  // by using the vertex number 1
39604  if (cs == 1)
39605  {
39606  // Initial end point of previous line
39607  Vector<double> initial_vertex_of_previous_segment;
39608 
39609  initial_vertex_of_previous_segment =
39610  open_curve_pt->polyline_pt(cs - 1)->vertex_coordinate(0);
39611 
39612  unsigned prev_seg_boundary_id =
39613  open_curve_pt->curve_section_pt(cs - 1)->boundary_id();
39614 
39615  // Find the error between the initial vertex of the previous
39616  // line and the first vertex of the current line
39617  double error = 0.0;
39618  for (unsigned i = 0; i < 2; i++)
39619  {
39620  const double dist = initial_vertex_of_previous_segment[i] -
39621  (*vector_vertex_node.begin())[i];
39622  error += dist * dist;
39623  }
39624  error = sqrt(error); // Reversed only the previous one
39625 
39626  // If the error is bigger than the tolerance then
39627  // we probably need to reverse, but better check
39628  if (error >
39629  ToleranceForVertexMismatchInPolygons::Tolerable_error)
39630  {
39631  // Find the error between the final vertex of the previous
39632  // line and the last vertex of the current line
39633  double rev_error = 0.0;
39634  for (unsigned i = 0; i < 2; i++)
39635  {
39636  const double dist = initial_vertex_of_previous_segment[i] -
39637  (*--vector_vertex_node.end())[i];
39638  rev_error += dist * dist;
39639  }
39640  rev_error = sqrt(rev_error); // Reversed both the current
39641  // one and the previous one
39642 
39643  if (rev_error >
39644  ToleranceForVertexMismatchInPolygons::Tolerable_error)
39645  {
39646  std::ostringstream error_stream;
39647  error_stream
39648  << "The distance between the first node of the current\n"
39649  << "line segment (boundary " << bound
39650  << ") and either end of "
39651  << "the previous line segment\n"
39652  << "(boundary " << prev_seg_boundary_id
39653  << ") is bigger than"
39654  << " the desired tolerance "
39655  << ToleranceForVertexMismatchInPolygons::Tolerable_error
39656  << ".\n"
39657  << "This suggests that the polylines defining the "
39658  "polygonal\n"
39659  << "representation are not properly ordered.\n"
39660  << "Fail on last vertex of polyline: ("
39661  << prev_seg_boundary_id
39662  << ") and\nfirst vertex of polyline (" << bound
39663  << ").\nThis should have failed when first trying to "
39664  << "construct the\npolygon.\n";
39665  throw OomphLibError(error_stream.str(),
39666  OOMPH_CURRENT_FUNCTION,
39667  OOMPH_EXCEPTION_LOCATION);
39668  }
39669  else
39670  {
39671  // Reverse both
39672  // Reverse the current vector to line up with the previous
39673  // one
39674  std::reverse(vector_vertex_node.begin(),
39675  vector_vertex_node.end());
39676  open_curve_pt->polyline_pt(cs - 1)->reverse();
39677  }
39678  }
39679  else
39680  {
39681  // Reverse the previous one
39682  open_curve_pt->polyline_pt(cs - 1)->reverse();
39683  }
39684 
39685  } // if (cs == 1)
39686  else
39687  {
39688  std::ostringstream error_stream;
39689  error_stream
39690  << "The distance between the first node of the current\n"
39691  << "line segment (boundary " << bound
39692  << ") and either end of "
39693  << "the previous line segment\n"
39694  << "(boundary " << prev_seg_boundary_id
39695  << ") is bigger than the "
39696  << "desired tolerance "
39697  << ToleranceForVertexMismatchInPolygons::Tolerable_error
39698  << ".\n"
39699  << "This suggests that the polylines defining the polygonal\n"
39700  << "representation are not properly ordered.\n"
39701  << "Fail on last vertex of polyline: ("
39702  << prev_seg_boundary_id << ") and\nfirst vertex of polyline ("
39703  << bound << ").\n"
39704  << "This should have failed when first trying to construct\n"
39705  << "the polygon.\n";
39706  throw OomphLibError(error_stream.str(),
39707  OOMPH_CURRENT_FUNCTION,
39708  OOMPH_EXCEPTION_LOCATION);
39709  }
39710  }
39711  else
39712  {
39713  // Reverse the current vector to line up with the previous one
39714  std::reverse(vector_vertex_node.begin(),
39715  vector_vertex_node.end());
39716  }
39717  }
39718 
39719  } // if (cs > 0)
39720 
39721  } // if (!this->is_mesh_distributed())
39722 
39723  // ---------------------------------------------------------------
39724  // Update the polylines representation
39725  // ---------------------------------------------------------------
39726  // Always update the polylines representation, in a distributed
39727  // mesh it is necessary to update the polyline representation since
39728  // it may no longer have vertices (the boundary may not be part of
39729  // the domain in the current processor)
39730 
39731  // The new number of vertices
39732  n_vertex = vector_vertex_node.size();
39733 
39734  // Update the polyline according to the new vertices
39735  TriangleMeshPolyLine* tmp_polyline_pt =
39736  new TriangleMeshPolyLine(vector_vertex_node, bound);
39737 
39738  // Create a temporal "curve section" version of the recently
39739  // created polyline
39740  TriangleMeshCurveSection* tmp_curve_section_pt = tmp_polyline_pt;
39741 
39742  // Tolerance below which the middle point can be deleted (ratio of
39743  // deflection to element length)
39744  double unrefinement_tolerance =
39745  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
39746 
39747  // Tolerance to add points
39748  double refinement_tolerance =
39749  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
39750 
39751  // Establish refinement and unrefinement tolerance
39752  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
39753  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
39754 
39755  // Establish the maximum length constraint
39756  double maximum_length = open_curve_pt->polyline_pt(cs)->maximum_length();
39757  tmp_polyline_pt->set_maximum_length(maximum_length);
39758 
39759 #ifdef OOMPH_HAS_MPI
39760  // If the mesh is distributed check that the polyline still has
39761  // vertices
39762  if (this->is_mesh_distributed())
39763  {
39764  if (n_vertex >= 2)
39765  {
39766  // Pass the connection information from the old polyline to
39767  // the new one
39768  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
39769  tmp_curve_section_pt);
39770  } // if (n_vertex >= 2)
39771  } // if (this->is_mesh_distributed())
39772  else
39773 #endif
39774  {
39775  // Pass the connection information from the old polyline to the
39776  // new one
39777  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
39778  tmp_curve_section_pt);
39779  }
39780 
39781  // Now update the polyline according to the new vertices but first
39782  // check if the object is allowed to delete the representation or
39783  // if it should be done by other object
39784  bool delete_it_on_destructor = false;
39785 
39786  std::set<TriangleMeshCurveSection*>::iterator it =
39787  this->Free_curve_section_pt.find(open_curve_pt->curve_section_pt(cs));
39788 
39789  if (it != this->Free_curve_section_pt.end())
39790  {
39791  this->Free_curve_section_pt.erase(it);
39792  delete open_curve_pt->curve_section_pt(cs);
39793  delete_it_on_destructor = true;
39794  }
39795 
39796  // -------------------------------------------------------------
39797  // Copying the new representation
39798  open_curve_pt->curve_section_pt(cs) = tmp_polyline_pt;
39799 
39800  // Update the Boundary - Polyline map
39801  this->Boundary_curve_section_pt[bound] =
39802  open_curve_pt->curve_section_pt(cs);
39803 
39804  if (delete_it_on_destructor)
39805  {
39806  this->Free_curve_section_pt.insert(open_curve_pt->curve_section_pt(cs));
39807  }
39808 
39809 #ifdef OOMPH_HAS_MPI
39810  // If there are not sub-boundaries mark the boundary if need to be
39811  // trated as shared or as internal boundary
39812  if (this->is_mesh_distributed() && nsub_boundaries == 1)
39813  {
39814  // Clear all previous stored data
39815  this->Boundary_marked_as_shared_boundary[bound].clear();
39816 
39817  // .. and store the flag for the boundary
39818  this->Boundary_marked_as_shared_boundary[bound].push_back(
39819  internal_to_shared_boundary[0]);
39820  }
39821  // --------- Stuff for the sub_boundaries ----- Begin section --------
39822  // Verify if need to deal with sub_boundaries
39823  else if (this->is_mesh_distributed() && nsub_boundaries > 1)
39824  {
39825  // Create temporary representations for the boundaries, only to
39826  // create the mesh when calling Triangle
39827 
39828  // Clear all previous stored data
39829  this->Boundary_subpolylines[bound].clear();
39830  // Now create storage for the sub-boundaries
39831  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
39832 
39833  // Clear all previous stored data
39834  this->Boundary_marked_as_shared_boundary[bound].clear();
39835  // Create storage to mark the internal boundaries as shared
39836  // boundaries
39837  this->Boundary_marked_as_shared_boundary[bound].resize(nsub_boundaries);
39838  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39839  {
39840  // Now update the polyline according to the sub set of
39841  // vertices, set the chunk number of the polyline
39842  TriangleMeshPolyLine* sub_tmp_polyline_pt =
39843  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
39844 
39845  // Add the sub-polyline to the container to represent the
39846  // boundary in parts
39847  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
39848 
39849  // Copy the flag that mark the boundary as internal or as
39850  // shared bound
39851  this->Boundary_marked_as_shared_boundary[bound][isub] =
39852  internal_to_shared_boundary[isub];
39853 
39854  // No need to send the unrefinement/refinement and maximum
39855  // length constraints since these are only temporary
39856  // representations
39857 
39858  // But we certanly we need to pass the connection information
39859  // to the sub-polylines
39860  // Get a curve section representation of the sub-polyline
39861  TriangleMeshCurveSection* tmp_sub_curve_section_pt =
39862  sub_tmp_polyline_pt;
39863  this->copy_connection_information_to_sub_polylines(
39864  tmp_curve_section_pt, tmp_sub_curve_section_pt);
39865 
39866  } // for (isub < nsub_boundaries)
39867 
39868  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39869  // --------- Stuff for the sub_boundaries ----- End section ---------
39870 #endif // OOMPH_HAS_MPI
39871 
39872  // Delete the allocated memory for the geometric object
39873  // that represents the curvilinear boundary
39874  delete mesh_geom_obj_pt;
39875 
39876  } // for (cs < ncurve_section)
39877 
39878  // Cleanup the face mesh
39879  for (unsigned p = 0; p < ncurve_section; p++)
39880  {
39881  face_mesh_pt[p]->flush_node_storage();
39882  delete face_mesh_pt[p];
39883  }
39884 
39885  return update_was_performed;
39886  }
39887 
39888 #ifdef OOMPH_HAS_MPI
39889  //======================================================================
39890  /// Updates the polylines using the elements area as
39891  /// constraint for the number of points along the boundaries
39892  //======================================================================
39893  template<class ELEMENT>
39895  Vector<TriangleMeshPolyLine*>& vector_polyline_pt,
39896  const Vector<double>& target_areas)
39897  {
39898  // Flag to check if there were a change on the shared boundary
39899  // representation
39900  unsigned update_was_performed = false;
39901 
39902  // Go through all the shared boundaries/polylines
39903  const unsigned n_polylines = vector_polyline_pt.size();
39904  for (unsigned pp = 0; pp < n_polylines; pp++)
39905  {
39906  // Get the boundary id of the current polyline
39907  const unsigned shd_bnd_id = vector_polyline_pt[pp]->boundary_id();
39908 
39909  // Get the chunk number
39910  const unsigned chunk = vector_polyline_pt[pp]->boundary_chunk();
39911 
39912  // Get the face elements that created the shared boundary from the
39913  // bulk shared boundary elements
39914 
39915  // Compute the face elements from the shared boundary elements,
39916  // create an association from the face element with the "bulk"
39917  // elements
39918  std::map<FiniteElement*, FiniteElement*> face_ele_pt_to_bulk_element_pt;
39919 
39920  // The temporary storage for the halo face elements
39921  Vector<FiniteElement*> halo_shared_face_ele_pt;
39922  // The temporary storage for the nonhalo face elements
39923  Vector<FiniteElement*> nonhalo_shared_face_ele_pt;
39924 
39925  // Get the number of shared boundary elements associated with the
39926  // current shared boundary
39927  const unsigned nshared_bound_ele =
39928  this->nshared_boundary_element(shd_bnd_id);
39929 
39930  // Loop over the elements in the shared boundary to create the face
39931  // elements
39932  for (unsigned e = 0; e < nshared_bound_ele; e++)
39933  {
39934  // Get the shared boundary element
39935  FiniteElement* bulk_ele_pt =
39936  this->shared_boundary_element_pt(shd_bnd_id, e);
39937 
39938  // Get the face index
39939  int face_index = this->face_index_at_shared_boundary(shd_bnd_id, e);
39940 
39941  // Before adding the new element we need to ensure that the edge
39942  // that this element represents has not been already added
39943  FiniteElement* face_ele_pt =
39944  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
39945 
39946  // Establish the association between the bulk element and the
39947  // face element
39948  face_ele_pt_to_bulk_element_pt[face_ele_pt] = bulk_ele_pt;
39949 
39950  // Nonhalo element
39951  if (!bulk_ele_pt->is_halo())
39952  {
39953  // Add nonhalo shared face element to the container
39954  nonhalo_shared_face_ele_pt.push_back(face_ele_pt);
39955  }
39956  else // halo element
39957  {
39958  // Add halo shared face element to the container
39959  halo_shared_face_ele_pt.push_back(face_ele_pt);
39960  }
39961 
39962  } // for (e < nshared_bound_ele)
39963 
39964  // Now we have the face elements, we need to ensure that the halo
39965  // and nonhalo bulk element are sorted one after the other
39966  Vector<Vector<FiniteElement*>> unsorted_shared_bulk_ele_pt;
39967 
39968  // Mark the face elements already used
39969  std::map<FiniteElement*, bool> shared_face_done;
39970 
39971  // Get the number of nonhalo face elements
39972  const unsigned nnonhalo_face_shared_ele =
39973  nonhalo_shared_face_ele_pt.size();
39974 
39975  // Get the number of halo face elements
39976  const unsigned nhalo_face_shared_ele = halo_shared_face_ele_pt.size();
39977 
39978 #ifdef PARANOID
39979  // The number of nonhalo shared face boundary elements must be the
39980  // half of the total number of shared boundary elements
39981  if (nshared_bound_ele / 2 != nnonhalo_face_shared_ele)
39982  {
39983  std::ostringstream error_message;
39984  error_message
39985  << "The number of shared boundary elements (" << nshared_bound_ele
39986  << ") is not the double\nof the number of unsorted NONHALO shared "
39987  << "face boundary elements (" << nnonhalo_face_shared_ele << ")\n"
39988  << "for the current boundary (" << shd_bnd_id << ")\n\n";
39989  throw OomphLibError(error_message.str(),
39990  OOMPH_CURRENT_FUNCTION,
39991  OOMPH_EXCEPTION_LOCATION);
39992  }
39993 
39994  // The number of halo shared face boundary elements must be the
39995  // half of the total number of shared boundary elements
39996  if (nshared_bound_ele / 2 != nhalo_face_shared_ele)
39997  {
39998  std::ostringstream error_message;
39999  error_message
40000  << "The number of shared boundary elements (" << nshared_bound_ele
40001  << ") is not the double\nof the number of unsorted HALO shared "
40002  << "face boundary elements (" << nhalo_face_shared_ele << ")\n"
40003  << "for the current boundary (" << shd_bnd_id << ")\n\n";
40004  throw OomphLibError(error_message.str(),
40005  OOMPH_CURRENT_FUNCTION,
40006  OOMPH_EXCEPTION_LOCATION);
40007  }
40008 #endif
40009 
40010  // ------------------------------------------------------------------
40011  // Loop over the nonhalo face elements and look for the halo face
40012  // element at the other side of the shared boundary
40013  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
40014  {
40015  // Get the inh-th face element
40016  FiniteElement* nonhalo_face_ele_pt = nonhalo_shared_face_ele_pt[inh];
40017 
40018  // Get the number of nodes on the face element
40019  const unsigned nnodes_nh = nonhalo_face_ele_pt->nnode();
40020  // Get the first and last node on the element
40021  Node* nh_first_node_pt = nonhalo_face_ele_pt->node_pt(0);
40022  Node* nh_last_node_pt = nonhalo_face_ele_pt->node_pt(nnodes_nh - 1);
40023 
40024  // Now find the (halo) face element at the other side of the
40025  // shared boundary
40026  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
40027  {
40028  // Get the ih-th face element
40029  FiniteElement* halo_face_ele_pt = halo_shared_face_ele_pt[ih];
40030 
40031  // Check that the face element has not been done
40032  if (!shared_face_done[halo_face_ele_pt])
40033  {
40034  // Get the number of nodes on the face element
40035  const unsigned nnodes_h = halo_face_ele_pt->nnode();
40036  // Get the first and last node on the element
40037  Node* h_first_node_pt = halo_face_ele_pt->node_pt(0);
40038  Node* h_last_node_pt = halo_face_ele_pt->node_pt(nnodes_h - 1);
40039 
40040  // If the nodes are the same then we have found the (halo)
40041  // face element at the other side of the shared boundary
40042  if (nh_first_node_pt == h_first_node_pt &&
40043  nh_last_node_pt == h_last_node_pt)
40044  {
40045  // Get the BULK elements associated with the face elements
40046  Vector<FiniteElement*> tmp_bulk_element_pt;
40047  // Get the BULK elements associated to the face elements
40048  // (the nonhalo and the halo)
40049  FiniteElement* nonhalo_bulk_ele_pt =
40050  face_ele_pt_to_bulk_element_pt[nonhalo_face_ele_pt];
40051  FiniteElement* halo_bulk_ele_pt =
40052  face_ele_pt_to_bulk_element_pt[halo_face_ele_pt];
40053 
40054  // Add the BULK elements to the temporal storage
40055  tmp_bulk_element_pt.push_back(nonhalo_bulk_ele_pt);
40056  tmp_bulk_element_pt.push_back(halo_bulk_ele_pt);
40057 
40058  // Store the pair of elements associated to the "edge"
40059  unsorted_shared_bulk_ele_pt.push_back(tmp_bulk_element_pt);
40060 
40061  // Mark the face elements as done
40062  shared_face_done[nonhalo_face_ele_pt] = true;
40063  shared_face_done[halo_face_ele_pt] = true;
40064 
40065  // Break the loop for (ih < nhalo_face_shared_ele)
40066  break;
40067  } // if (nh_first_node_pt == h_first_node_pt &&
40068  // nh_last_node_pt == h_last_node_pt)
40069  else if (nh_first_node_pt == h_last_node_pt &&
40070  nh_last_node_pt == h_first_node_pt)
40071  {
40072  // Get the BULK elements associated with the face elements
40073  Vector<FiniteElement*> tmp_bulk_element_pt;
40074  // Get the BULK elements associated to the face elements
40075  // (the nonhalo and the halo)
40076  FiniteElement* nonhalo_bulk_ele_pt =
40077  face_ele_pt_to_bulk_element_pt[nonhalo_face_ele_pt];
40078  FiniteElement* halo_bulk_ele_pt =
40079  face_ele_pt_to_bulk_element_pt[halo_face_ele_pt];
40080 
40081  // Add the BULK elements to the temporal storage
40082  tmp_bulk_element_pt.push_back(nonhalo_bulk_ele_pt);
40083  tmp_bulk_element_pt.push_back(halo_bulk_ele_pt);
40084 
40085  // Store the pair of elements associated to the "edge"
40086  unsorted_shared_bulk_ele_pt.push_back(tmp_bulk_element_pt);
40087 
40088  // Mark the face elements as done
40089  shared_face_done[nonhalo_face_ele_pt] = true;
40090  shared_face_done[halo_face_ele_pt] = true;
40091 
40092  // Break the loop for (ih < nhalo_face_shared_ele)
40093  break;
40094  } // else if (nh_first_node_pt == h_last_node_pt &&
40095  // nh_last_node_pt == h_first_node_pt)
40096 
40097  } // if (face_done[halo_face_ele_pt])
40098 
40099  } // for (ih < nhalo_face_shared_ele)
40100 
40101  } // for (inh < nnonhalo_face_shared_ele)
40102 
40103  // -------------------------------------------------------------
40104  // Now sort the face elements
40105  // -------------------------------------------------------------
40106 
40107  // We already have the shared face elements that make the shared
40108  // boundary (and the bulk elements), now sort them to create a
40109  // contiguous boundary
40110 
40111 #ifdef PARANOID
40112  const unsigned nunsorted_shared_bulk_ele =
40113  unsorted_shared_bulk_ele_pt.size();
40114 
40115  // The number of unsorted shared BULK elements MUST be the same
40116  // as the number of shared_boundary elements divided by two
40117  if (nshared_bound_ele / 2 != nunsorted_shared_bulk_ele)
40118  {
40119  std::ostringstream error_message;
40120  error_message
40121  << "The number of shared boundary elements (" << nshared_bound_ele
40122  << ") is not the double\nof the number of unsorted shared bulk "
40123  << "boundary elements (" << nunsorted_shared_bulk_ele << ")\n"
40124  << "for the current boundary (" << shd_bnd_id << ")\n\n";
40125  throw OomphLibError(error_message.str(),
40126  OOMPH_CURRENT_FUNCTION,
40127  OOMPH_EXCEPTION_LOCATION);
40128  }
40129 
40130  // The number of done shared face elements MUST be the same as the
40131  // sum of the nonhalo and halo shared boundary face elements
40132  if ((nnonhalo_face_shared_ele + nhalo_face_shared_ele) !=
40133  shared_face_done.size())
40134  {
40135  std::ostringstream error_message;
40136  error_message << "The number of DONE shared boundary face elements ("
40137  << shared_face_done.size()
40138  << ") is not the same\n as the sum of"
40139  << "the nonhalo face shared boundary elements ("
40140  << nnonhalo_face_shared_ele
40141  << ")\nand the halo face shared "
40142  << "boundary elements (" << nhalo_face_shared_ele
40143  << ") for the\n/"
40144  << "current boundary (" << shd_bnd_id << ")\n\n";
40145  throw OomphLibError(error_message.str(),
40146  OOMPH_CURRENT_FUNCTION,
40147  OOMPH_EXCEPTION_LOCATION);
40148  }
40149 #endif
40150 
40151  // Clear the already done face elements
40152  shared_face_done.clear();
40153 
40154  // The number of sorted face elements
40155  unsigned nsorted_face_ele = 0;
40156 
40157  // Storing for the sorting nodes extracted from the face
40158  // elements. This are also used to update the polyline
40159  std::list<Node*> sorted_nodes;
40160 
40161  // Storing for the sorted shared face elements
40162  std::list<FiniteElement*> sorted_shared_bound_elements_pt;
40163 
40164  // Get the root face element
40165  FiniteElement* root_face_ele_pt = nonhalo_shared_face_ele_pt[0];
40166  nsorted_face_ele++;
40167 
40168  // Mark face as done
40169  shared_face_done[root_face_ele_pt] = true;
40170 
40171  // The initial and final node on the list
40172  const unsigned nnodes_root = root_face_ele_pt->nnode();
40173  Node* first_node_pt = root_face_ele_pt->node_pt(0);
40174  Node* last_node_pt = root_face_ele_pt->node_pt(nnodes_root - 1);
40175 
40176  // Push back on the list the new nodes
40177  sorted_nodes.push_back(first_node_pt);
40178  sorted_nodes.push_back(last_node_pt);
40179 
40180  // Store the bulk elements of the current face
40181  sorted_shared_bound_elements_pt.push_back(
40182  unsorted_shared_bulk_ele_pt[0][0]);
40183  sorted_shared_bound_elements_pt.push_back(
40184  unsorted_shared_bulk_ele_pt[0][1]);
40185 
40186  // Sort the face elements
40187  while (nsorted_face_ele < nnonhalo_face_shared_ele)
40188  {
40189  // Flag to indicate when a node was added
40190  bool node_added = false;
40191 
40192  // Start from the next edge since we have already added the
40193  // previous one as the initial face element
40194  for (unsigned iface = 1; iface < nnonhalo_face_shared_ele; iface++)
40195  {
40196  FiniteElement* tmp_shared_face_ele_pt =
40197  nonhalo_shared_face_ele_pt[iface];
40198 
40199  // If face has not been sorted
40200  if (!shared_face_done[tmp_shared_face_ele_pt])
40201  {
40202  // Get the number of nodes for the current face element
40203  const unsigned tmp_nnodes = tmp_shared_face_ele_pt->nnode();
40204 
40205  // Get each individual node
40206  Node* left_node_pt = tmp_shared_face_ele_pt->node_pt(0);
40207  Node* right_node_pt =
40208  tmp_shared_face_ele_pt->node_pt(tmp_nnodes - 1);
40209 
40210  if (left_node_pt == first_node_pt)
40211  {
40212  // Push front the new node
40213  sorted_nodes.push_front(right_node_pt);
40214  first_node_pt = right_node_pt;
40215  node_added = true;
40216 
40217  // Store the elements of the current face element
40218  sorted_shared_bound_elements_pt.push_front(
40219  unsorted_shared_bulk_ele_pt[iface][1]);
40220  sorted_shared_bound_elements_pt.push_front(
40221  unsorted_shared_bulk_ele_pt[iface][0]);
40222  }
40223  else if (left_node_pt == last_node_pt)
40224  {
40225  // Push back the new node
40226  sorted_nodes.push_back(right_node_pt);
40227  last_node_pt = right_node_pt;
40228  node_added = true;
40229 
40230  // Store the elements of the current face element
40231  sorted_shared_bound_elements_pt.push_back(
40232  unsorted_shared_bulk_ele_pt[iface][0]);
40233  sorted_shared_bound_elements_pt.push_back(
40234  unsorted_shared_bulk_ele_pt[iface][1]);
40235  }
40236  else if (right_node_pt == first_node_pt)
40237  {
40238  // Push front the new node
40239  sorted_nodes.push_front(left_node_pt);
40240  first_node_pt = left_node_pt;
40241  node_added = true;
40242 
40243  // Store the elements of the current face element
40244  sorted_shared_bound_elements_pt.push_front(
40245  unsorted_shared_bulk_ele_pt[iface][1]);
40246  sorted_shared_bound_elements_pt.push_front(
40247  unsorted_shared_bulk_ele_pt[iface][0]);
40248  }
40249  else if (right_node_pt == last_node_pt)
40250  {
40251  // Push back the new node
40252  sorted_nodes.push_back(left_node_pt);
40253  last_node_pt = left_node_pt;
40254  node_added = true;
40255 
40256  // Store the elements of the current face element
40257  sorted_shared_bound_elements_pt.push_back(
40258  unsorted_shared_bulk_ele_pt[iface][0]);
40259  sorted_shared_bound_elements_pt.push_back(
40260  unsorted_shared_bulk_ele_pt[iface][1]);
40261  }
40262 
40263  if (node_added)
40264  {
40265  // Mark as done if one of its nodes has been added to the
40266  // list
40267  shared_face_done[tmp_shared_face_ele_pt] = true;
40268  nsorted_face_ele++;
40269 
40270  // Break the for
40271  break;
40272  }
40273 
40274  } // if (!shared_face_done[tmp_shared_face_ele_pt])
40275 
40276  } // for (iface < nnonhalo_face_shared_ele)
40277 
40278  } // while (nsorted_face_ele < nnonhalo_face_shared_ele))
40279 
40280  // ----------------------------------------------------------------
40281  // Here we can safely delete the face elements, they are no longer
40282  // required
40283 
40284  // First the nonhalo face elements
40285  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
40286  {
40287  delete nonhalo_shared_face_ele_pt[inh];
40288  nonhalo_shared_face_ele_pt[inh] = 0;
40289  } // for (inh < nnonhalo_face_shared_ele)
40290 
40291  // ... then the halo face elements
40292  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
40293  {
40294  delete halo_shared_face_ele_pt[ih];
40295  halo_shared_face_ele_pt[ih] = 0;
40296  } // for (inh < nhalo_face_shared_ele)
40297 
40298  // ------------------------------------------------------------------
40299  // At this point we already have a sorted list of nodes, get the
40300  // vertices from them and store them in a vector container
40301 
40302  // Get the number of nodes on the list
40303  const unsigned n_nodes = sorted_nodes.size();
40304 
40305  // The vector to store the vertices
40306  Vector<Vector<double>> polyline_vertices(n_nodes);
40307 
40308  // Copy the vertices from the nodes
40309  unsigned counter = 0;
40310  for (std::list<Node*>::iterator it_nodes = sorted_nodes.begin();
40311  it_nodes != sorted_nodes.end();
40312  it_nodes++)
40313  {
40314  polyline_vertices[counter].resize(2);
40315  polyline_vertices[counter][0] = (*it_nodes)->x(0);
40316  polyline_vertices[counter][1] = (*it_nodes)->x(1);
40317  counter++;
40318  }
40319 
40320  // ------------------------------------------------------------------
40321  // Now get the target areas associated to the shared boundary
40322  // elements
40323 
40324  // Copy the sorted elements in a vector
40325  Vector<FiniteElement*> sorted_shared_ele_pt;
40326  for (std::list<FiniteElement*>::iterator it_ele =
40327  sorted_shared_bound_elements_pt.begin();
40328  it_ele != sorted_shared_bound_elements_pt.end();
40329  it_ele++)
40330  {
40331  sorted_shared_ele_pt.push_back((*it_ele));
40332  }
40333 
40334  // Get the number of target areas
40335  const unsigned n_shared_target_areas = sorted_shared_ele_pt.size();
40336  Vector<double> sorted_shared_target_areas(n_shared_target_areas);
40337 
40338  // Mark those shared elements already found
40339  std::map<std::pair<GeneralisedElement*, unsigned>, bool> shared_ele_done;
40340 
40341  // Counter for the number of already done shared elements
40342  unsigned count_found_shared_element = 0;
40343 
40344  // Get the target area associated to the shared boundary elements
40345  const unsigned nele = this->nelement();
40346 
40347  // Loop over the elements to find the target areas associated to
40348  // the shared boundary elements
40349  for (unsigned e = 0; e < nele; e++)
40350  {
40351  GeneralisedElement* current_ele_pt = this->element_pt(e);
40352  // Now compare the current element with those in the sorted
40353  // shared element array
40354  for (unsigned s = 0; s < n_shared_target_areas; s++)
40355  {
40356  // Get the element
40357  GeneralisedElement* current_shared_ele_pt = sorted_shared_ele_pt[s];
40358  // Create the pair element-index to check if done
40359  std::pair<GeneralisedElement*, unsigned> pair_gen_ele_idx =
40360  std::make_pair(current_shared_ele_pt, s);
40361  if (!shared_ele_done[pair_gen_ele_idx])
40362  {
40363  // Compare with the global element
40364  if (current_ele_pt == current_shared_ele_pt)
40365  {
40366  // Store the target area of the current shared element
40367  sorted_shared_target_areas[s] = target_areas[e];
40368  // Mark the shared element as done
40369  shared_ele_done[pair_gen_ele_idx] = true;
40370  // Increase the number of found elements
40371  count_found_shared_element++;
40372  } // if (current_ele_pt == current_shared_ele_pt)
40373  } // if (!shared_ele_done[current_shared_ele_pt])
40374  } // for (s < nshared_taget_areas)
40375 
40376  // Check if all shared elements have been found
40377  if (count_found_shared_element == n_shared_target_areas)
40378  {
40379  break;
40380  }
40381 
40382  } // for (e < nele)
40383 
40384 #ifdef PARANOID
40385  // Check if the number of found target areas is the same as the
40386  // number of shared target areas
40387  if (count_found_shared_element != n_shared_target_areas)
40388  {
40389  std::ostringstream error_message;
40390  error_message << "The number of found target areas ("
40391  << count_found_shared_element
40392  << ") is different from the "
40393  << "total number\nof target areas ("
40394  << n_shared_target_areas << ") in shared boundary ("
40395  << shd_bnd_id << ")\n\n";
40396  throw OomphLibError(error_message.str(),
40397  OOMPH_CURRENT_FUNCTION,
40398  OOMPH_EXCEPTION_LOCATION);
40399  }
40400 #endif
40401 
40402  // The number of vertices
40403  const unsigned n_vertices = n_nodes;
40404 
40405  // Get the number of segments from the input vector_polyline_pt
40406  const unsigned n_segments = vector_polyline_pt[pp]->nsegment();
40407  // Get the number of segments from the input vector_polyline_pt to
40408  // ensure that the shared boundary corresponds to the one
40409  // represented by the shared face elements (this has sence when the
40410  // mesh was re-created from re-starting)
40411 
40412  // Check that the number of vertices correspond with the number of
40413  // segments
40414 #ifdef PARANOID
40415  if (n_segments != n_vertices - 1)
40416  {
40417  std::ostringstream error_message;
40418  error_message
40419  << "The number of segments from the current shared polyline "
40420  << "(" << n_segments << ") does not\ncorrespond with the number of "
40421  << "sorted vertices (" << n_vertices - 1
40422  << ") of the current shared\n"
40423  << "boundary\n\n";
40424  throw OomphLibError(error_message.str(),
40425  OOMPH_CURRENT_FUNCTION,
40426  OOMPH_EXCEPTION_LOCATION);
40427  }
40428 
40429  // Check that the number of target areas correspond with the number
40430  // of vertices
40431  if (n_segments != n_shared_target_areas / 2)
40432  {
40433  std::ostringstream error_message;
40434  error_message
40435  << "The number of segments for the current sorting of edges "
40436  << "(" << n_segments << ") is different\nfrom the number of "
40437  << "target areas (" << n_shared_target_areas / 2 << ")\n\n";
40438  throw OomphLibError(error_message.str(),
40439  OOMPH_CURRENT_FUNCTION,
40440  OOMPH_EXCEPTION_LOCATION);
40441  }
40442 #endif
40443 
40444  // ------------------------------------------------------------------
40445  // Get the target areas that are used to perform the unrefinement
40446  // and refinement operation. For each face element on a shared
40447  // polyline there are two bulk elements, a halo and a haloed
40448  // element, each with an associated target area. Review the
40449  // function
40450  // TriangleMesh::create_polylines_from_halo_elements_helper() to
40451  // check how the shared boundaries were created
40452  Vector<double> polyline_target_area(n_segments);
40453  // Loop over the segments in the shared polyline
40454  for (unsigned s = 0; s < n_segments; s++)
40455  {
40456  // Get the minimum of the associated target areas
40457  polyline_target_area[s] =
40458  std::min(sorted_shared_target_areas[s * 2],
40459  sorted_shared_target_areas[(s * 2) + 1]);
40460  }
40461 
40462  // Before going to the unrefinement or refinement process check
40463  // that in all processors where the shared boundary lives start
40464  // from the same vertex.
40465  // Start from the bottom left vertex
40466  if (polyline_vertices[n_vertices - 1][1] < polyline_vertices[0][1])
40467  {
40468  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
40469  std::reverse(polyline_target_area.begin(), polyline_target_area.end());
40470  }
40471  else if (polyline_vertices[n_vertices - 1][1] == polyline_vertices[0][1])
40472  {
40473  if (polyline_vertices[n_vertices - 1][0] < polyline_vertices[0][0])
40474  {
40475  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
40476  std::reverse(polyline_target_area.begin(),
40477  polyline_target_area.end());
40478  }
40479  }
40480 
40481  // ------------------------------------------------------------------
40482  // Apply unrefinement
40483  bool unrefinement_applied = false;
40484  // Apply unefinement if there are more than three nodes at the
40485  // shared boundary
40486  if (n_vertices > 3)
40487  {
40488  unrefinement_applied =
40489  unrefine_shared_boundary_constrained_by_target_area(
40490  shd_bnd_id, chunk, polyline_vertices, polyline_target_area);
40491  }
40492 
40493  // Apply refinement
40494  bool refinement_applied =
40495  refine_shared_boundary_constrained_by_target_area(polyline_vertices,
40496  polyline_target_area);
40497 
40498  // Was unrefinement/refinement applied
40499  update_was_performed |= (unrefinement_applied || refinement_applied);
40500 
40501  // ------------------------------------------------------------------
40502  // Update the polyline representation of the shared boundary
40503 
40504  // The new shared polyline representation
40505  TriangleMeshPolyLine* new_polyline_pt =
40506  new TriangleMeshPolyLine(polyline_vertices, shd_bnd_id);
40507 
40508  // Get the curve section representation
40509  TriangleMeshCurveSection* curve_section_pt = vector_polyline_pt[pp];
40510 
40511  // Copy the connection information from the old shared polyline to
40512  // the new one
40513  this->copy_connection_information(curve_section_pt, new_polyline_pt);
40514 
40515  // Now update the polyline according to the new vertices but first
40516  // check if the object is allowed to delete the representation or
40517  // if it should be done by other object
40518  bool delete_it_on_destructor = false;
40519 
40520  // Establish the element as being deleted by the destructor of the
40521  // class
40522  std::set<TriangleMeshCurveSection*>::iterator it =
40523  this->Free_curve_section_pt.find(curve_section_pt);
40524 
40525  if (it != this->Free_curve_section_pt.end())
40526  {
40527  this->Free_curve_section_pt.erase(it);
40528  delete curve_section_pt;
40529  delete_it_on_destructor = true;
40530  }
40531 
40532  // Copy the new representation to the output vector_polyline_pt
40533  vector_polyline_pt[pp] = new_polyline_pt;
40534 
40535  // Get the new curve section representation
40536  TriangleMeshCurveSection* new_curve_section_pt = vector_polyline_pt[pp];
40537 
40538  // Update the Boundary - Polyline map
40539  this->Boundary_curve_section_pt[shd_bnd_id] = new_curve_section_pt;
40540 
40541  if (delete_it_on_destructor)
40542  {
40543  this->Free_curve_section_pt.insert(new_curve_section_pt);
40544  }
40545 
40546  } // for (pp < npoly)
40547 
40548  return update_was_performed;
40549  }
40550 #endif // #ifdef OOMPH_HAS_MPI
40551 
40552  //=========================================================================
40553  /// Helper function that performs the unrefinement process
40554  /// on the specified boundary by using the provided vertices
40555  /// representation and the associated target area.
40556  //=========================================================================
40557  template<class ELEMENT>
40560  const unsigned& b,
40561  const unsigned& c,
40562  Vector<Vector<double>>& vector_bnd_vertices,
40563  double& unrefinement_tolerance,
40564  Vector<double>& area_constraint)
40565  {
40566  // Store the vertices not allowed for deletion
40567  std::set<Vector<double>> no_delete_vertex;
40568 
40569  // Does the boundary receives connections?
40570  const bool boundary_receive_connections =
40571  this->boundary_connections(b, c, no_delete_vertex);
40572 
40573  // Boolean that indicates whether an actual update of the vertex
40574  // coordinates was performed
40575  bool unrefinement_applied = false;
40576 
40577  // Return inmedately
40578  if (!Do_boundary_unrefinement_constrained_by_target_areas)
40579  {
40580  return unrefinement_applied;
40581  }
40582 
40583  // Strategy to delete nodes: Consider the target area of the
40584  // elements (e_i and e_(i+1)) sharing the i-th node (middle node),
40585  // if the number of segments to be added is equal to zero for both
40586  // elements then compute the average of both target areas and check
40587  // if the number of segments is still zero, if that holds mark the
40588  // node to be deleted. Before delete the node check whether it is in
40589  // the non_delete_vertex list. Skip the i+1-th node and go for the
40590  // (i+2)-th one, it means, increase the counter for current node by
40591  // two.
40592 
40593  // Number of vertices on the boundary
40594  unsigned n_vertex = vector_bnd_vertices.size();
40595 
40596  // Compute a constant value
40597  const double constant_value = 4.0 / sqrt(3.0);
40598 
40599  if (n_vertex > 2)
40600  {
40601  // Go through all the vertices and delete points when the target area
40602  // indicates zero points along the boundary
40603  for (unsigned i = 1; i < n_vertex - 1; i += 2)
40604  {
40605  if (area_constraint[i - 1] > 0 && area_constraint[i] > 0)
40606  {
40607  const double local_zeta_first = vector_bnd_vertices[i - 1][0];
40608  const double local_zeta_last = vector_bnd_vertices[i + 1][0];
40609  const double local_length_zeta =
40610  std::fabs(local_zeta_last - local_zeta_first);
40611 
40612  const double x1 = vector_bnd_vertices[i - 1][1];
40613  const double y1 = vector_bnd_vertices[i - 1][2];
40614  const double x2 = vector_bnd_vertices[i + 1][1];
40615  const double y2 = vector_bnd_vertices[i + 1][2];
40616  const double local_length =
40617  sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
40618 
40619  const double x_m = vector_bnd_vertices[i][1];
40620  const double y_m = vector_bnd_vertices[i][2];
40621 
40622  const double average_area_constraint =
40623  (area_constraint[i - 1] + area_constraint[i]) / 2.0;
40624 
40625  // Compute the length of the the side of an equilateral
40626  // triangle
40627  const double length_side =
40628  sqrt(constant_value * average_area_constraint);
40629 
40630  const double length_side_zeta =
40631  (local_length_zeta * length_side) / local_length;
40632 
40633  // Is the new length greater that the old one
40634  if ((length_side_zeta / local_length_zeta) > 1.0)
40635  {
40636  // If the number of segments is zero then verify the condition for
40637  // deletion of nodes but using the condition in the default
40638  // unrefine_boundary() method. If both conditions are true then
40639  // delete the node
40640  // Maths from
40641  // http://www.cgafaq.info/wiki/Circle_Through_Three_Points
40642  double a_x = vector_bnd_vertices[i - 1][1];
40643  double a_y = vector_bnd_vertices[i - 1][2];
40644  double b_x = vector_bnd_vertices[i][1];
40645  double b_y = vector_bnd_vertices[i][2];
40646  double c_x = vector_bnd_vertices[i + 1][1];
40647  double c_y = vector_bnd_vertices[i + 1][2];
40648 
40649  double a = b_x - a_x;
40650  double b = b_y - a_y;
40651  double c = c_x - a_x;
40652  double d = c_y - a_y;
40653 
40654  double e = a * (a_x + b_x) + b * (a_y + b_y);
40655  double f = c * (a_x + c_x) + d * (a_y + c_y);
40656 
40657  double g = 2.0 * (a * (c_y - b_y) - b * (c_x - b_x));
40658 
40659  bool do_it = false;
40660  if (std::fabs(g) < 1.0e-14)
40661  {
40662  do_it = true;
40663  }
40664  else
40665  {
40666  double p_x = (d * e - b * f) / g;
40667  double p_y = (a * f - c * e) / g;
40668 
40669  double r = sqrt(pow((a_x - p_x), 2) + pow((a_y - p_y), 2));
40670 
40671  double rhalfca_x = 0.5 * (a_x - c_x);
40672  double rhalfca_y = 0.5 * (a_y - c_y);
40673 
40674  double halfca_squared = pow(rhalfca_x, 2) + pow(rhalfca_y, 2);
40675 
40676  double sticky_out_bit =
40677  r - sqrt(std::fabs((r * r) - halfca_squared));
40678 
40679  // If sticky out bit divided by distance between end nodes
40680  // is less than tolerance the boundary is so flat that we
40681  // can safely kill the node
40682  if ((sticky_out_bit / (2.0 * sqrt(halfca_squared))) <
40683  unrefinement_tolerance)
40684  {
40685  do_it = true;
40686  }
40687  }
40688 
40689  // If the vertex was proposed for deletion check if it is
40690  // allowed for being deleted
40691  if (do_it && boundary_receive_connections)
40692  {
40693  // Is the vertex one of the non deletable vertices
40694  for (std::set<Vector<double>>::iterator it =
40695  no_delete_vertex.begin();
40696  it != no_delete_vertex.end();
40697  it++)
40698  {
40699  // Compute the distance between the proposed node to
40700  // delete and the ones that should not be deleted
40701  const double x = (*it)[0];
40702  const double y = (*it)[1];
40703  double error = (x_m - x) * (x_m - x) + (y_m - y) * (y_m - y);
40704  error = sqrt(error);
40705 
40706  if (error <
40707  ToleranceForVertexMismatchInPolygons::Tolerable_error)
40708  {
40709  // Do not delete the vertex
40710  do_it = false;
40711  break;
40712  }
40713  }
40714 
40715  } // if (do_it && boundary_receive_connections)
40716 
40717  // Remove node?
40718  if (do_it)
40719  {
40720  vector_bnd_vertices[i].resize(0);
40721  }
40722  } // if (n_seg == 0)
40723  } // if (area_constraint[i] >= 0)
40724  } // for (i < n_vertex-1)
40725 
40726  // Create a new (temporary) vector for the nodes, so that deleted nodes
40727  // are not stored
40728  Vector<Vector<double>> compact_vector;
40729 
40730  // Compact vector for target areas too
40731  Vector<double> compact_area_constraint;
40732 
40733  // Copy only the non deleted nodes
40734  for (unsigned i = 0; i < n_vertex; i++)
40735  {
40736  // If the entry was not deleted include it in the new vector
40737  if (vector_bnd_vertices[i].size() != 0)
40738  {
40739  compact_vector.push_back(vector_bnd_vertices[i]);
40740  }
40741  }
40742 
40743  // ------------------------------------------------------------------
40744  // Size of the target areas vector
40745  unsigned nsize_target = area_constraint.size();
40746  if (nsize_target == 1)
40747  {
40748  // No node was deleted, just copy the target area
40749  compact_area_constraint.push_back(area_constraint[0]);
40750  }
40751 
40752  // Copy the target areas
40753  for (unsigned i = 1; i < n_vertex; i += 2)
40754  {
40755  // If the entry was not deleted include the target areas of both
40756  // elements sharing the node
40757  if (vector_bnd_vertices[i].size() != 0)
40758  {
40759  compact_area_constraint.push_back(area_constraint[i - 1]);
40760  // To catch the case when working with even number of vertex
40761  if (i < nsize_target)
40762  {
40763  compact_area_constraint.push_back(area_constraint[i]);
40764  }
40765  }
40766  else
40767  {
40768  // If the node was deleted then compute the new target area as the
40769  // average of the target area of the elements sharing the node
40770  double new_area_constraint =
40771  (area_constraint[i - 1] + area_constraint[i]) / 2.0;
40772  compact_area_constraint.push_back(new_area_constraint);
40773  }
40774  }
40775 
40776  // If the size of the compact vector is different from the size of the
40777  // vector before applying the area length constraint then the polyline
40778  // was updated
40779  if (n_vertex != compact_vector.size())
40780  {
40781  unrefinement_applied = true;
40782  }
40783 
40784  // Copy back to the original vector
40785  n_vertex = compact_vector.size();
40786  vector_bnd_vertices.resize(n_vertex);
40787  for (unsigned i = 0; i < n_vertex; i++)
40788  {
40789  vector_bnd_vertices[i].resize(3);
40790  vector_bnd_vertices[i][0] = compact_vector[i][0];
40791  vector_bnd_vertices[i][1] = compact_vector[i][1];
40792  vector_bnd_vertices[i][2] = compact_vector[i][2];
40793  }
40794 
40795  // Copy back to the original vector of target areas
40796  unsigned ntarget_areas = compact_area_constraint.size();
40797  area_constraint.resize(ntarget_areas);
40798  for (unsigned i = 0; i < ntarget_areas; i++)
40799  {
40800  area_constraint[i] = compact_area_constraint[i];
40801  }
40802 
40803  } // if (n_vertex > 2)
40804 
40805  return unrefinement_applied;
40806  }
40807 
40808  //=========================================================================
40809  /// Helper function that performs the refinement process
40810  /// on the specified boundary by using the provided vertices
40811  /// representation and the associated elements target area.
40812  //=========================================================================
40813  template<class ELEMENT>
40816  MeshAsGeomObject* mesh_geom_obj_pt,
40817  Vector<Vector<double>>& vector_bnd_vertices,
40818  double& refinement_tolerance,
40819  Vector<double>& area_constraint)
40820  {
40821  // Boolean that indicates whether an actual update of the vertex
40822  // coordinates was performed
40823  bool refinement_applied = false;
40824 
40825  // Return inmedately
40826  if (!Do_boundary_refinement_constrained_by_target_areas)
40827  {
40828  return refinement_applied;
40829  }
40830 
40831  // Get the total number of current vertices
40832  unsigned n_vertex = vector_bnd_vertices.size();
40833 
40834  // Compute a constant value
40835  const double constant_value = 4.0 / sqrt(3.0);
40836 
40837  if (n_vertex > 1)
40838  {
40839  // Create a new (temporary) vector for the nodes, so that new
40840  // nodes can be stored
40841  Vector<Vector<double>> new_vector;
40842 
40843  // Go through all the vertices and create points according to the
40844  // specified element area
40845  for (unsigned i = 0; i < n_vertex - 1; i++)
40846  {
40847  // Include the first node
40848  new_vector.push_back(vector_bnd_vertices[i]);
40849 
40850  if (area_constraint[i] > 0)
40851  {
40852  double local_zeta_first = vector_bnd_vertices[i][0];
40853  double local_zeta_last = vector_bnd_vertices[i + 1][0];
40854  const double local_length_zeta =
40855  std::fabs(local_zeta_last - local_zeta_first);
40856 
40857  // Check if need to interchange the zeta first and the zeta
40858  // last (to ensure the same order in zeta values in any two
40859  // processors)
40860  if (local_zeta_first > local_zeta_last)
40861  {
40862  const double tmp_zeta = local_zeta_first;
40863  local_zeta_first = local_zeta_last;
40864  local_zeta_last = tmp_zeta;
40865  }
40866 
40867  const double x1 = vector_bnd_vertices[i][1];
40868  const double y1 = vector_bnd_vertices[i][2];
40869  const double x2 = vector_bnd_vertices[i + 1][1];
40870  const double y2 = vector_bnd_vertices[i + 1][2];
40871  const double local_length =
40872  sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
40873 
40874  // Compute the length in zeta units
40875  const double length_side = sqrt(constant_value * area_constraint[i]);
40876  const double length_side_zeta =
40877  (local_length_zeta * length_side) / local_length;
40878 
40879  // How many segments should be introduced
40880  const double n_seg_double = length_side_zeta / local_length_zeta;
40881 
40882  // One segment initialy (the original one)
40883  unsigned n_seg = 1;
40884 
40885  // How many more segments to introduce?
40886  n_seg += static_cast<unsigned>(std::floor(1.0 / n_seg_double));
40887 
40888  // Are there segments to introduce? There must be at least one
40889  // segment, the original one
40890  if (n_seg > 0)
40891  {
40892  // The zeta increment
40893  double zeta_increment = (local_length_zeta) / ((double)n_seg);
40894 
40895  Vector<double> zeta(1);
40896  // Create the n_seg segmets between each pair of nodes
40897  for (unsigned s = 1; s < n_seg; s++)
40898  {
40899  // Get the coordinates
40900  zeta[0] = local_zeta_first + zeta_increment * double(s);
40901  Vector<double> vertex(2);
40902  mesh_geom_obj_pt->position(zeta, vertex);
40903 
40904  // Create the new node
40905  Vector<double> new_node(3);
40906  new_node[0] = zeta[0];
40907  new_node[1] = vertex[0];
40908  new_node[2] = vertex[1];
40909 
40910  // Include the new node
40911  new_vector.push_back(new_node);
40912 
40913  } // for (s<=n_seg)
40914 
40915  } // if (n_seg > 0)
40916 
40917  } // if (area_constraint[i] >= 0)
40918 
40919  } // for (i < n_vertex-1)
40920 
40921  // Once finished all the vertices add the last node to the vector
40922  new_vector.push_back(vector_bnd_vertices[n_vertex - 1]);
40923 
40924  // If the new size of the vector (including the added nodes) is
40925  // different from the size of the vector before applying the
40926  // area length constraint then the polyline was updated
40927  n_vertex = new_vector.size();
40928  if (n_vertex != vector_bnd_vertices.size())
40929  {
40930  refinement_applied = true;
40931  }
40932 
40933  // Copy the new representation
40934  vector_bnd_vertices.resize(n_vertex);
40935  for (unsigned i = 0; i < n_vertex; i++)
40936  {
40937  vector_bnd_vertices[i].resize(3);
40938  vector_bnd_vertices[i][0] = new_vector[i][0];
40939  vector_bnd_vertices[i][1] = new_vector[i][1];
40940  vector_bnd_vertices[i][2] = new_vector[i][2];
40941  }
40942 
40943  } // if (n_vertex > 1)
40944 
40945  return refinement_applied;
40946  }
40947 
40948  //======================================================================
40949  /// Helper function that performs the unrefinement process
40950  /// on the specified boundary by using the provided vertices
40951  /// representation and the associated target area.
40952  /// NOTE: This is the version that applies unrefinement to shared
40953  /// boundaries
40954  //======================================================================
40955  template<class ELEMENT>
40958  const unsigned& b,
40959  const unsigned& c,
40960  Vector<Vector<double>>& vector_bnd_vertices,
40961  Vector<double>& area_constraint)
40962  {
40963  // Store the vertices not allowed for deletion
40964  std::set<Vector<double>> no_delete_vertex;
40965 
40966  // Does the boundary receives connections?
40967  const bool boundary_receive_connections =
40968  this->boundary_connections(b, c, no_delete_vertex);
40969 
40970  // Boolean that indicates whether an actual update of the vertex
40971  // coordinates was performed
40972  bool unrefinement_applied = false;
40973 
40974  // Return inmedately
40975  if (!Do_shared_boundary_unrefinement_constrained_by_target_areas)
40976  {
40977  return unrefinement_applied;
40978  }
40979 
40980  // Strategy to delete nodes:
40981 
40982  // Strategy to delete nodes: Consider the target area of the
40983  // elements (e_i and e_(i+1)) sharing the i-th node (middle node),
40984  // if the number of segments to be added is equal to zero for both
40985  // elements then compute the average of both target areas and check
40986  // if the number of segments is still zero, if that holds mark the
40987  // node to be deleted. Before delete the node check whether it is in
40988  // the non_delete_vertex list. Skip the i+1-th node and go for the
40989  // (i+2)-th one, it means, increase the counter for current node by
40990  // two.
40991 
40992  // Number of vertices on the boundary
40993  unsigned n_vertex = vector_bnd_vertices.size();
40994 
40995  // Compute a constant value
40996  const double constant_value = 4.0 / sqrt(3.0);
40997 
40998  if (n_vertex > 2)
40999  {
41000  // Go through all the vertices and delete points when the target
41001  // area indicates zero points along the boundary
41002  for (unsigned i = 1; i < n_vertex - 1; i += 2)
41003  {
41004  // Is a target area assigned to the left and right element of
41005  // the i-th node
41006  if (area_constraint[i - 1] > 0 && area_constraint[i] > 0)
41007  {
41008  // Get the vertices to the left
41009  const double x1 = vector_bnd_vertices[i - 1][0];
41010  const double y1 = vector_bnd_vertices[i - 1][1];
41011  // ... and to the right of the i-th vertex
41012  const double x2 = vector_bnd_vertices[i + 1][0];
41013  const double y2 = vector_bnd_vertices[i + 1][1];
41014 
41015  // The distance
41016  const double local_length =
41017  sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
41018 
41019  // Get the middle vertex
41020  const double x_m = vector_bnd_vertices[i][0];
41021  const double y_m = vector_bnd_vertices[i][1];
41022 
41023  // The average area
41024  const double average_area_constraint =
41025  (area_constraint[i - 1] + area_constraint[i]) / 2.0;
41026 
41027  // Compute the base length of the triangle with
41028  // area_constraint area
41029  const double length_side =
41030  sqrt(constant_value * average_area_constraint);
41031 
41032  // Is the new length greater than the old one
41033  if ((length_side / local_length) > 1.0)
41034  {
41035  bool do_it = true;
41036 
41037  // If the vertex was proposed for deletion check that it is
41038  // allowed for being deleted
41039  if (do_it && boundary_receive_connections)
41040  {
41041  // Is the vertex one of the non deletable vertices
41042  for (std::set<Vector<double>>::iterator it =
41043  no_delete_vertex.begin();
41044  it != no_delete_vertex.end();
41045  it++)
41046  {
41047  // Compute the distance between the proposed node to delete
41048  // and the ones that should not be deleted
41049  const double x = (*it)[0];
41050  const double y = (*it)[1];
41051  double error = (x_m - x) * (x_m - x) + (y_m - y) * (y_m - y);
41052  error = sqrt(error);
41053 
41054  if (error <
41055  ToleranceForVertexMismatchInPolygons::Tolerable_error)
41056  {
41057  // Do not delete the vertex
41058  do_it = false;
41059  break;
41060  }
41061  }
41062 
41063  } // if (do_it && boundary_receive_connections)
41064 
41065  // Remove node?
41066  if (do_it)
41067  {
41068  vector_bnd_vertices[i].resize(0);
41069  }
41070  } // if ((local_length / length_side) <= 1.3)
41071 
41072  } // if (area_constraint[i] >= 0)
41073 
41074  } // for (i < n_vertex-1)
41075 
41076  // Create a new (temporary) vector for the nodes, so that deleted nodes
41077  // are not stored
41078  Vector<Vector<double>> compact_vector;
41079 
41080  // Compact vector for target areas too
41081  Vector<double> compact_area_constraint;
41082 
41083  // Copy only the non deleted nodes
41084  for (unsigned i = 0; i < n_vertex; i++)
41085  {
41086  // If the entry was not deleted include it in the new vector
41087  if (vector_bnd_vertices[i].size() != 0)
41088  {
41089  compact_vector.push_back(vector_bnd_vertices[i]);
41090  }
41091  }
41092 
41093  // ------------------------------------------------------------------
41094  // The number of target areas
41095  unsigned n_area_constraint = area_constraint.size();
41096  if (n_area_constraint == 1)
41097  {
41098  // No node could be deleted then just copy the target area
41099  compact_area_constraint.push_back(area_constraint[0]);
41100  }
41101 
41102  // Copy the target areas
41103  for (unsigned i = 1; i < n_vertex; i += 2)
41104  {
41105  // If the entry was not deleted include the target areas of both
41106  // elements sharing the node
41107  if (vector_bnd_vertices[i].size() != 0)
41108  {
41109  compact_area_constraint.push_back(area_constraint[i - 1]);
41110  // To catch the case when working with even number of vertices
41111  if (i < n_area_constraint)
41112  {
41113  compact_area_constraint.push_back(area_constraint[i]);
41114  }
41115  }
41116  else
41117  {
41118  // If the node was deleted then compute the new target area as the
41119  // average of the target area of the elements sharing the node
41120  const double new_area_constraint =
41121  (area_constraint[i - 1] + area_constraint[i]) / 2.0;
41122  compact_area_constraint.push_back(new_area_constraint);
41123  }
41124  } // for (i < n_vertex)
41125 
41126  // If the size of the compact vector is different from the size of
41127  // the vector before applying the area length constraint then the
41128  // polyline was updated
41129  if (n_vertex != compact_vector.size())
41130  {
41131  unrefinement_applied = true;
41132  }
41133 
41134  // Copy back to the original vector
41135  n_vertex = compact_vector.size();
41136  vector_bnd_vertices.resize(n_vertex);
41137  for (unsigned i = 0; i < n_vertex; i++)
41138  {
41139  vector_bnd_vertices[i].resize(2);
41140  vector_bnd_vertices[i][0] = compact_vector[i][0];
41141  vector_bnd_vertices[i][1] = compact_vector[i][1];
41142  }
41143 
41144  // Copy back to the original vector of target areas
41145  unsigned ntarget_areas = compact_area_constraint.size();
41146  area_constraint.resize(ntarget_areas);
41147  for (unsigned i = 0; i < ntarget_areas; i++)
41148  {
41149  area_constraint[i] = compact_area_constraint[i];
41150  }
41151 
41152  } // if (n_vertex > 2)
41153 
41154  return unrefinement_applied;
41155  }
41156 
41157  //======================================================================
41158  /// Helper function that performs the refinement process
41159  /// on the specified boundary by using the provided vertices
41160  /// representation and the associated elements target area.
41161  /// NOTE: This is the version that applies refinement to shared
41162  /// boundaries
41163  //======================================================================
41164  template<class ELEMENT>
41167  Vector<Vector<double>>& vector_bnd_vertices,
41168  Vector<double>& area_constraint)
41169  {
41170  // Boolean that indicates whether an actual update of the vertex
41171  // coordinates was performed
41172  bool refinement_applied = false;
41173 
41174  // Return inmedately
41175  if (!Do_shared_boundary_refinement_constrained_by_target_areas)
41176  {
41177  return refinement_applied;
41178  }
41179 
41180  // Get the number of segments
41181  unsigned nsegments = vector_bnd_vertices.size() - 1;
41182 
41183  // Create a new (temporary) vector for the nodes, so that new nodes
41184  // can be stored
41185  Vector<Vector<double>> tmp_bnd_vertices;
41186 
41187  // Compute a constant value
41188  const double constant_value = 4.0 / sqrt(3.0);
41189 
41190  for (unsigned s = 0; s < nsegments; s++)
41191  {
41192  Vector<double> left_vertex = vector_bnd_vertices[s];
41193  Vector<double> right_vertex = vector_bnd_vertices[s + 1];
41194 
41195  // Initial and final point of the segment
41196  const double x1 = left_vertex[0];
41197  const double y1 = left_vertex[1];
41198  const double x2 = right_vertex[0];
41199  const double y2 = right_vertex[1];
41200 
41201  // Lenght of the segment
41202  const double segment_length =
41203  sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
41204 
41205  // Compute the distance for the new segments
41206  const double new_segment_length =
41207  sqrt(constant_value * area_constraint[s]);
41208 
41209  // How many segments should be introduced
41210  const double n_seg_double = new_segment_length / segment_length;
41211 
41212  // One segment initialy (the original one)
41213  unsigned nseg = 1;
41214  // How many more segments to introduce?
41215  nseg += static_cast<unsigned>(std::floor(1.0 / n_seg_double));
41216 
41217  // The left vertex must be always included, even though no new vertex
41218  // be added
41219  tmp_bnd_vertices.push_back(left_vertex);
41220 
41221  // Are there segments to introduce? There must be at least one
41222  // segment, the original one
41223  if (nseg > 0)
41224  {
41225  // Create intermediate vertices
41226  double incrementx = (right_vertex[0] - left_vertex[0]) / (double)(nseg);
41227  double incrementy = (right_vertex[1] - left_vertex[1]) / (double)(nseg);
41228  for (unsigned i = 1; i < nseg; i++)
41229  {
41230  Vector<double> tmp_vertex(2);
41231  tmp_vertex[0] = left_vertex[0] + incrementx * i;
41232  tmp_vertex[1] = left_vertex[1] + incrementy * i;
41233  tmp_bnd_vertices.push_back(tmp_vertex);
41234  } // for (i < nseg)
41235 
41236  } // if (nseg > 0)
41237 
41238  } // for (s < nsegments)
41239 
41240  // Add the last vertex
41241  tmp_bnd_vertices.push_back(vector_bnd_vertices[nsegments]);
41242 
41243  // If the new size of the vector (including the added nodes) is
41244  // different from the size of the vector before applying the
41245  // refinement then the polyline was updated
41246  nsegments = tmp_bnd_vertices.size() - 1;
41247  if (nsegments != vector_bnd_vertices.size() - 1)
41248  {
41249  refinement_applied = true;
41250 
41251  // Copy across
41252  vector_bnd_vertices.resize(nsegments + 1);
41253  for (unsigned i = 0; i < nsegments + 1; i++)
41254  {
41255  vector_bnd_vertices[i].resize(2);
41256  vector_bnd_vertices[i][0] = tmp_bnd_vertices[i][0];
41257  vector_bnd_vertices[i][1] = tmp_bnd_vertices[i][1];
41258  }
41259  }
41260 
41261  return refinement_applied;
41262  }
41263 
41264  //======================================================================
41265  /// Updates the polylines representation after restart
41266  //======================================================================
41267  template<class ELEMENT>
41269  TriangleMeshPolygon*& polygon_pt)
41270  {
41271  // **********************************************************************
41272  // 1) Collect the elements adjacet to the polyline boundary id and
41273  // update the polyline
41274  // **********************************************************************
41275 
41276  // (1.1) Get the face mesh representation
41277  Vector<Mesh*> face_mesh_pt;
41278  get_face_mesh_representation(polygon_pt, face_mesh_pt);
41279 
41280  // (1.2) Create vertices of the polylines by using the vertices of the
41281  // FaceElements
41282  Vector<double> vertex_coord(3); // zeta,x,y
41283  Vector<double> bound_left(1);
41284  Vector<double> bound_right(1);
41285 
41286  const unsigned n_polyline = polygon_pt->npolyline();
41287 
41288  // Go for each polyline
41289  for (unsigned p = 0; p < n_polyline; p++)
41290  {
41291  // Get the MeshAsGeomObject representation just once per polyline,
41292  // this object is only used by the
41293  // refine_boundary_constrained_by_target_area() method. We get it here
41294  // to ensure that all processors (in a distributed context) get this
41295  // representation just once, and because an AllToAll MPI communication
41296  // is used in this calling
41297  MeshAsGeomObject* mesh_geom_obj_pt =
41298  new MeshAsGeomObject(face_mesh_pt[p]);
41299 
41300  // Set of coordinates that are on the boundary
41301  // Set entries are ordered on first entry in vector which stores
41302  // the boundary coordinate so the vertices come out in order!
41303  std::set<Vector<double>> vertex_nodes;
41304 
41305  // Vector to store the vertices, transfer the sorted vertices from the
41306  // set to this vector, --- including the z-value ---
41307  Vector<Vector<double>> tmp_vector_vertex_node;
41308 
41309  // Vector to store the coordinates of the polylines, same as the
41310  // tmp_vector_vertex_node vector (after adding more nodes) but
41311  // --- without the z-value ---, used to re-generate the polylines
41312  Vector<Vector<double>> vector_vertex_node;
41313 
41314 #ifdef OOMPH_HAS_MPI
41315  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
41316  // Set of coordinates that are on the boundary (splitted boundary version)
41317  // The first vector is used to allocate the points for each sub-boundary
41318  // Set entries are ordered on first entry in vector which stores
41319  // the boundary coordinate so the vertices come out in order!
41320  Vector<std::set<Vector<double>>> sub_vertex_nodes;
41321 
41322  // Vector to store the vertices, transfer the sorted vertices from the
41323  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
41324  Vector<Vector<Vector<double>>> sub_tmp_vector_vertex_node;
41325 
41326  // Vector to store the coordinates of the polylines that will represent
41327  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
41328  // but --- without the z-value ---, used to generate the sub-polylines
41329  Vector<Vector<Vector<double>>> sub_vector_vertex_node;
41330  // --------- Stuff to deal with splitted boundaries ----------- End ------
41331 #endif
41332 
41333  // Get the boundary id
41334  unsigned bound = polygon_pt->curve_section_pt(p)->boundary_id();
41335 
41336  /// Use a vector of vector for vertices and target areas to
41337  /// deal with the cases when the boundaries are split by the
41338  /// distribution process
41339 
41340  // Loop over the face elements (ordered) and add their vertices
41341  const unsigned nface_element = face_mesh_pt[p]->nelement();
41342 
41343  // Store the non halo face elements, the ones from which we will
41344  // get the vertices
41345  Vector<FiniteElement*> non_halo_face_element_pt;
41346  // Map to store the index of the face element on a boundary
41347  std::map<FiniteElement*, unsigned> face_element_index_on_boundary;
41348 
41349  for (unsigned ef = 0; ef < nface_element; ++ef)
41350  {
41351  FiniteElement* ele_face_pt = face_mesh_pt[p]->finite_element_pt(ef);
41352  // Skip the halo elements
41353 #ifdef OOMPH_HAS_MPI
41354  if (this->is_mesh_distributed())
41355  {
41356  // Only work with non-halo elements
41357  if (ele_face_pt->is_halo())
41358  {
41359  continue;
41360  }
41361  }
41362 #endif
41363  // Add the face element to the vector
41364  non_halo_face_element_pt.push_back(ele_face_pt);
41365  face_element_index_on_boundary[ele_face_pt] = ef;
41366  }
41367 
41368  // Get the number of non halo face element
41369  const unsigned nnon_halo_face_element = non_halo_face_element_pt.size();
41370 
41371  // Map to know the already sorted face elements
41372  std::map<FiniteElement*, bool> face_element_done;
41373 
41374  // Number of done face elements
41375  unsigned nsorted_face_elements = 0;
41376 
41377 #ifdef OOMPH_HAS_MPI
41378  // Counter for sub_boundaries
41379  unsigned nsub_boundaries = 0;
41380 #endif // #ifdef OOMPH_HAS_MPI
41381 
41382  // Continue until all the face elements have been sorted
41383  // This while is to deal with the cases of splitted boundaries
41384  while (nsorted_face_elements < nnon_halo_face_element)
41385  {
41386  // Get and initial face element
41387  FiniteElement* ele_face_pt = 0;
41388 #ifdef PARANOID
41389  bool found_initial_face_element = false;
41390 #endif
41391 
41392  unsigned iface = 0;
41393  for (iface = 0; iface < nnon_halo_face_element; iface++)
41394  {
41395  ele_face_pt = non_halo_face_element_pt[iface];
41396  // If not done then take it as initial face element
41397  if (!face_element_done[ele_face_pt])
41398  {
41399 #ifdef PARANOID
41400  found_initial_face_element = true;
41401 #endif
41402  nsorted_face_elements++;
41403  iface++;
41404  break;
41405  }
41406  }
41407 
41408 #ifdef PARANOID
41409  if (!found_initial_face_element)
41410  {
41411  std::ostringstream error_message;
41412  error_message << "Could not find an initial face element for the "
41413  "current segment\n";
41414  // << "----- Possible memory leak -----\n";
41415  throw OomphLibError(
41416  error_message.str(),
41417  "RefineableTriangleMesh::update_polygon_after_restart()",
41418  OOMPH_EXCEPTION_LOCATION);
41419  }
41420 #endif
41421 
41422  // Local set of coordinates that are on the boundary
41423  // Set entries are ordered on first entry in vector which stores
41424  // the boundary coordinate so the vertices come out in order!
41425  std::set<Vector<double>> local_vertex_nodes;
41426 
41427  // Vector to store the vertices, transfer the sorted vertices from the
41428  // set (local) to this vector (local), --- including the z-value ---
41429  Vector<Vector<double>> local_tmp_vector_vertex_node;
41430 
41431  // ------------------------------------------------------------------
41432  // ------------------------------------------------------------------
41433  // -----------------------------------------------------------------
41434  // Add the vertices of the initial face element to the set of local
41435  // sorted vertices
41436  // -----------------------------------------------------------------
41437  unsigned nnode = ele_face_pt->nnode();
41438  // Add the left-hand node to the set:
41439  // Boundary coordinate
41440  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound, bound_left);
41441  vertex_coord[0] = bound_left[0];
41442 
41443  // Actual coordinates
41444  for (unsigned i = 0; i < 2; i++)
41445  {
41446  vertex_coord[i + 1] = ele_face_pt->node_pt(0)->x(i);
41447  }
41448  local_vertex_nodes.insert(vertex_coord);
41449 
41450  // Add the right-hand nodes to the set:
41451  // Boundary coordinate
41452  ele_face_pt->node_pt(nnode - 1)->get_coordinates_on_boundary(
41453  bound, bound_right);
41454  vertex_coord[0] = bound_right[0];
41455 
41456  // Actual coordinates
41457  for (unsigned i = 0; i < 2; i++)
41458  {
41459  vertex_coord[i + 1] = ele_face_pt->node_pt(nnode - 1)->x(i);
41460  }
41461  local_vertex_nodes.insert(vertex_coord);
41462 
41463  // The initial and final node on the set
41464  Node* first_node_pt = ele_face_pt->node_pt(0);
41465  Node* last_node_pt = ele_face_pt->node_pt(nnode - 1);
41466 
41467  // Mark the current face element as done
41468  face_element_done[ele_face_pt] = true;
41469 
41470  // ------------------------------------------------------------------
41471  // ------------------------------------------------------------------
41472  // ------------------------------------------------------------------
41473 
41474  // Continue iterating if a new face element has been added to the
41475  // list
41476  bool face_element_added = false;
41477 
41478  // While a new face element has been added to the set of sorted
41479  // face elements then re-iterate
41480  do
41481  {
41482  // Start from the next face elements since we have already added
41483  // the previous one as the initial face element (any previous face
41484  // element had to be added on previous iterations)
41485  for (unsigned iiface = iface; iiface < nnon_halo_face_element;
41486  iiface++)
41487  {
41488  face_element_added = false;
41489  ele_face_pt = non_halo_face_element_pt[iiface];
41490  if (!face_element_done[ele_face_pt])
41491  {
41492  // Get each individual node to check if they are contiguous
41493  nnode = ele_face_pt->nnode();
41494  Node* left_node_pt = ele_face_pt->node_pt(0);
41495  Node* right_node_pt = ele_face_pt->node_pt(nnode - 1);
41496 
41497  if (left_node_pt == first_node_pt)
41498  {
41499  first_node_pt = right_node_pt;
41500  face_element_added = true;
41501  }
41502  else if (left_node_pt == last_node_pt)
41503  {
41504  last_node_pt = right_node_pt;
41505  face_element_added = true;
41506  }
41507  else if (right_node_pt == first_node_pt)
41508  {
41509  first_node_pt = left_node_pt;
41510  face_element_added = true;
41511  }
41512  else if (right_node_pt == last_node_pt)
41513  {
41514  last_node_pt = left_node_pt;
41515  face_element_added = true;
41516  }
41517 
41518  if (face_element_added)
41519  {
41520  // Add the left-hand node to the set:
41521  // Boundary coordinate
41522  left_node_pt->get_coordinates_on_boundary(bound, bound_left);
41523  vertex_coord[0] = bound_left[0];
41524 
41525  // Actual coordinates
41526  for (unsigned i = 0; i < 2; i++)
41527  {
41528  vertex_coord[i + 1] = left_node_pt->x(i);
41529  }
41530  local_vertex_nodes.insert(vertex_coord);
41531 
41532  // Add the right-hand nodes to the set:
41533  // Boundary coordinate
41534  right_node_pt->get_coordinates_on_boundary(bound, bound_right);
41535  vertex_coord[0] = bound_right[0];
41536 
41537  // Actual coordinates
41538  for (unsigned i = 0; i < 2; i++)
41539  {
41540  vertex_coord[i + 1] = right_node_pt->x(i);
41541  }
41542  local_vertex_nodes.insert(vertex_coord);
41543 
41544  // Mark as done only if one of its nodes has been
41545  // added to the list
41546  face_element_done[ele_face_pt] = true;
41547  nsorted_face_elements++;
41548 
41549  break;
41550  }
41551 
41552  } // if (!edge_done[edge])
41553  } // for (iiedge < nedges)
41554  } while (face_element_added &&
41555  (nsorted_face_elements < nnon_halo_face_element));
41556 
41557  // -----------------------------------------------------------------
41558  // At this point we already have a sorted set of nodes and
41559  // can be used to peform the unrefinement and refinement procedures
41560  // -----------------------------------------------------------------
41561 
41562  // Get the number of nodes on the list
41563  const unsigned nlocal_nodes = local_vertex_nodes.size();
41564  // Change representation to vector for easy of handling ...
41565  local_tmp_vector_vertex_node.resize(nlocal_nodes);
41566 
41567  // Copy the vertices of the nodes
41568  unsigned counter = 0;
41569  std::set<Vector<double>>::iterator it_vertex;
41570  for (it_vertex = local_vertex_nodes.begin();
41571  it_vertex != local_vertex_nodes.end();
41572  it_vertex++)
41573  {
41574  local_tmp_vector_vertex_node[counter].resize(3);
41575  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
41576  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
41577  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
41578  counter++;
41579  }
41580 
41581  // *********************************************************************
41582  // 3) Create the vertices along the boundary using the target area to
41583  // define the distance among them
41584  // *********************************************************************
41585 
41586  // Clear the local containter to recover the nodes ordered using the
41587  // zeta value
41588  local_vertex_nodes.clear();
41589 
41590  // At the end of each unrefinement/refinement step store the new nodes
41591  // on the set that will give rise to the vertices of the new polyline
41592  // representation
41593  unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
41594  for (unsigned i = 0; i < nnew_nodes; i++)
41595  {
41596  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
41597  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
41598  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
41599  vertex_nodes.insert(vertex_coord); // Global container
41600  local_vertex_nodes.insert(vertex_coord);
41601  }
41602 
41603 #ifdef OOMPH_HAS_MPI
41604  if (this->is_mesh_distributed())
41605  {
41606  // Add the set of vertices for the boundary, this will help to detect
41607  // if we need to deal with sub_boundaries and sub_polylines represen.
41608  sub_vertex_nodes.push_back(local_vertex_nodes);
41609  // Increase the counter for sub_boundaries
41610  nsub_boundaries++;
41611  }
41612 #endif
41613 
41614  } // while(nsorted_face_elements < nnon_halo_face_element)
41615 
41616  // Now turn into vector for ease of handling...
41617  unsigned npoly_vertex = vertex_nodes.size();
41618  tmp_vector_vertex_node.resize(npoly_vertex);
41619  unsigned count = 0;
41620  std::set<Vector<double>>::iterator it;
41621  for (it = vertex_nodes.begin(); it != vertex_nodes.end(); ++it)
41622  {
41623  tmp_vector_vertex_node[count].resize(3);
41624  tmp_vector_vertex_node[count][0] = (*it)[0];
41625  tmp_vector_vertex_node[count][1] = (*it)[1];
41626  tmp_vector_vertex_node[count][2] = (*it)[2];
41627  ++count;
41628  }
41629 
41630 #ifdef OOMPH_HAS_MPI
41631  // --------- Stuff for the sub_boundaries ----- Begin section ---------
41632 #ifdef PARANOID
41633  unsigned nsub_boundaries_set = sub_vertex_nodes.size();
41634  if (nsub_boundaries_set != nsub_boundaries)
41635  {
41636  std::ostringstream error_message;
41637  error_message
41638  << "The number of found sub-boundaries and the number of counted\n"
41639  << "sub-boundaries are different:\n"
41640  << "Number of found sub-boundaries: (" << nsub_boundaries_set << ")\n"
41641  << "Number of counted sub-boundaries: (" << nsub_boundaries << ")\n";
41642  throw OomphLibError(
41643  error_message.str(),
41644  "RefineableTriangleMesh::update_polygon_after_restart()",
41645  OOMPH_EXCEPTION_LOCATION);
41646  }
41647 #endif
41648 
41649  // Verify if need to deal with sub_boundaries
41650  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41651  {
41652  // Mark the boundary as been splitted in the partition process
41653  this->Boundary_was_splitted[bound] = true;
41654  // Resize the vector to store the info. of sub-boundaries
41655  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
41656  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41657  {
41658  // Turn info. into vector for ease of handling...
41659  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
41660  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
41661  unsigned subcount = 0;
41662  std::set<Vector<double>>::iterator subit;
41663  for (subit = sub_vertex_nodes[isub].begin();
41664  subit != sub_vertex_nodes[isub].end();
41665  ++subit)
41666  {
41667  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
41668  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
41669  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
41670  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
41671  ++subcount;
41672  }
41673  }
41674  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
41675  // --------- Stuff for the sub_boundaries ----- End section ------------
41676 #endif // OOMPH_HAS_MPI
41677 
41678 
41679  // For further processing the three-dimensional vector
41680  // has to be reduced to a two-dimensional vector
41681  unsigned n_vertex = tmp_vector_vertex_node.size();
41682 
41683  // Resize the vector for vectices
41684  vector_vertex_node.resize(n_vertex);
41685  for (unsigned i = 0; i < n_vertex; i++)
41686  {
41687  vector_vertex_node[i].resize(2);
41688  vector_vertex_node[i][0] = tmp_vector_vertex_node[i][1];
41689  vector_vertex_node[i][1] = tmp_vector_vertex_node[i][2];
41690  }
41691 
41692 #ifdef OOMPH_HAS_MPI
41693  // --------- Stuff for the sub_boundaries ----- Begin section ----------
41694  // Verify if need to deal with sub_boundaries
41695  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41696  {
41697  // For further processing the three-dimensional vector
41698  // has to be reduced to a two-dimensional vector
41699  // Resize the vector to store the info. of sub-boundaries
41700  sub_vector_vertex_node.resize(nsub_boundaries);
41701  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41702  {
41703  const unsigned subn_vertex = sub_tmp_vector_vertex_node[isub].size();
41704  // Resize the vector for vectices
41705  sub_vector_vertex_node[isub].resize(subn_vertex);
41706  for (unsigned i = 0; i < subn_vertex; i++)
41707  {
41708  sub_vector_vertex_node[isub][i].resize(2);
41709  sub_vector_vertex_node[isub][i][0] =
41710  sub_tmp_vector_vertex_node[isub][i][1];
41711  sub_vector_vertex_node[isub][i][1] =
41712  sub_tmp_vector_vertex_node[isub][i][2];
41713  }
41714  }
41715  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
41716 
41717  // We already have the info. for the sub-boundaries (if necessary)
41718  // and then we can create the sub-boundaries representations to
41719  // ease the generation of the mesh by Triangle
41720 
41721  // --------- Stuff for the sub_boundaries ----- End section ------------
41722 #endif // OOMPH_HAS_MPI
41723 
41724  // *********************************************************************
41725  // 4) Check for contiguousness
41726  // *********************************************************************
41727 #ifdef OOMPH_HAS_MPI
41728  // Only perform this checking if the mesh is not distributed
41729  // When the mesh is distributed the polylines continuity is
41730  // addressed with the sort_polylines_helper() method
41731  if (!this->is_mesh_distributed())
41732 #endif
41733  {
41734  if (p > 0)
41735  {
41736  // Final end point of previous line
41737  Vector<double> final_vertex_of_previous_segment;
41738  unsigned n_prev_vertex =
41739  polygon_pt->curve_section_pt(p - 1)->nvertex();
41740  final_vertex_of_previous_segment =
41741  polygon_pt->polyline_pt(p - 1)->vertex_coordinate(n_prev_vertex -
41742  1);
41743 
41744  unsigned prev_seg_boundary_id =
41745  polygon_pt->curve_section_pt(p - 1)->boundary_id();
41746 
41747  // Find the error between the final vertex of the previous
41748  // line and the first vertex of the current line
41749  double error = 0.0;
41750  for (unsigned i = 0; i < 2; i++)
41751  {
41752  const double dist = final_vertex_of_previous_segment[i] -
41753  (*vector_vertex_node.begin())[i];
41754  error += dist * dist;
41755  }
41756  error = sqrt(error);
41757 
41758  // If the error is bigger than the tolerance then
41759  // we probably need to reverse, but better check
41760  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
41761  {
41762  // Find the error between the final vertex of the previous
41763  // line and the last vertex of the current line
41764  double rev_error = 0.0;
41765  for (unsigned i = 0; i < 2; i++)
41766  {
41767  const double dist = final_vertex_of_previous_segment[i] -
41768  (*--vector_vertex_node.end())[i];
41769  rev_error += dist * dist;
41770  }
41771  rev_error = sqrt(rev_error);
41772 
41773  if (rev_error >
41774  ToleranceForVertexMismatchInPolygons::Tolerable_error)
41775  {
41776  // It could be possible that the first segment be reversed and we
41777  // did not notice it because this check does not apply for the
41778  // first segment. We can verify if the first segment is reversed
41779  // by using the vertex number 1
41780  if (p == 1)
41781  {
41782  // Initial end point of previous line
41783  Vector<double> initial_vertex_of_previous_segment;
41784 
41785  initial_vertex_of_previous_segment =
41786  polygon_pt->polyline_pt(p - 1)->vertex_coordinate(0);
41787 
41788  unsigned prev_seg_boundary_id =
41789  polygon_pt->curve_section_pt(p - 1)->boundary_id();
41790 
41791  // Find the error between the initial vertex of the previous
41792  // line and the first vertex of the current line
41793  double error = 0.0;
41794  for (unsigned i = 0; i < 2; i++)
41795  {
41796  const double dist = initial_vertex_of_previous_segment[i] -
41797  (*vector_vertex_node.begin())[i];
41798  error += dist * dist;
41799  }
41800  error = sqrt(error); // Reversed only the previous one
41801 
41802  // If the error is bigger than the tolerance then
41803  // we probably need to reverse, but better check
41804  if (error >
41805  ToleranceForVertexMismatchInPolygons::Tolerable_error)
41806  {
41807  // Find the error between the final vertex of the previous
41808  // line and the last vertex of the current line
41809  double rev_error = 0.0;
41810  for (unsigned i = 0; i < 2; i++)
41811  {
41812  const double dist = initial_vertex_of_previous_segment[i] -
41813  (*--vector_vertex_node.end())[i];
41814  rev_error += dist * dist;
41815  }
41816  rev_error =
41817  sqrt(rev_error); // Reversed both the current one and
41818  // the previous one
41819 
41820  if (rev_error >
41821  ToleranceForVertexMismatchInPolygons::Tolerable_error)
41822  {
41823  std::ostringstream error_stream;
41824  error_stream
41825  << "The distance between the first node of the current\n"
41826  << "line segment (boundary " << bound
41827  << ") and either end of "
41828  << "the previous line segment\n"
41829  << "(boundary " << prev_seg_boundary_id
41830  << ") is bigger than "
41831  << "the desired tolerance "
41832  << ToleranceForVertexMismatchInPolygons::Tolerable_error
41833  << ".\n"
41834  << "This suggests that the polylines defining the "
41835  "polygonal\n"
41836  << "representation are not properly ordered.\n"
41837  << "Fail on last vertex of polyline: ("
41838  << prev_seg_boundary_id
41839  << ") and\nfirst vertex of polyline (" << bound
41840  << ").\nThis should have failed when first trying to"
41841  << " construct the\npolygon.\n";
41842  throw OomphLibError(
41843  error_stream.str(),
41844  "RefineableTriangleMesh::update_polygon_after_restart()",
41845  OOMPH_EXCEPTION_LOCATION);
41846  }
41847  else
41848  {
41849  // Reverse both
41850  // Reverse the current vector to line up with the previous
41851  // one
41852  std::reverse(vector_vertex_node.begin(),
41853  vector_vertex_node.end());
41854  polygon_pt->polyline_pt(p - 1)->reverse();
41855  }
41856  }
41857  else
41858  {
41859  // Reverse the previous one
41860  polygon_pt->polyline_pt(p - 1)->reverse();
41861  }
41862 
41863  } // if p == 1
41864  else
41865  {
41866  std::ostringstream error_stream;
41867  error_stream
41868  << "The distance between the first node of the current\n"
41869  << "line segment (boundary " << bound
41870  << ") and either end of "
41871  << "the previous line segment\n"
41872  << "(boundary " << prev_seg_boundary_id
41873  << ") is bigger than the "
41874  << "desired tolerance "
41875  << ToleranceForVertexMismatchInPolygons::Tolerable_error
41876  << ".\n"
41877  << "This suggests that the polylines defining the polygonal\n"
41878  << "representation are not properly ordered.\n"
41879  << "Fail on last vertex of polyline: ("
41880  << prev_seg_boundary_id << ") and\nfirst vertex of polyline ("
41881  << bound << ").\n"
41882  << "This should have failed when first trying to construct "
41883  "the\n"
41884  << "polygon.\n";
41885  throw OomphLibError(
41886  error_stream.str(),
41887  "RefineableTriangleMesh::update_polygon_after_restart()",
41888  OOMPH_EXCEPTION_LOCATION);
41889  }
41890  }
41891  else
41892  {
41893  // Reverse the current vector to line up with the previous one
41894  std::reverse(vector_vertex_node.begin(),
41895  vector_vertex_node.end());
41896  }
41897  } // error
41898  } // p > 0
41899  } // is mesh not distributed
41900 
41901  // *********************************************************************
41902  // 5) Update the polylines representation
41903  // *********************************************************************
41904  // if (applied_area_length_constraint)
41905  // If only applied when there is a change then it keeps the
41906  // previous polyline representation, it means, it does not delete
41907  // the boundaries that are not part of the domain. We must update
41908  // the boundary representation
41909  {
41910  n_vertex = vector_vertex_node.size();
41911 
41912  // Now update the polyline according to the new vertices
41913  // The new one representation
41914  TriangleMeshPolyLine* tmp_polyline_pt =
41915  new TriangleMeshPolyLine(vector_vertex_node, bound);
41916 
41917  // for (unsigned h = 0; h < vector_vertex_node.size(); h++)
41918  // {
41919  // DEBP(h);
41920  // DEBP(vector_vertex_node[h][0]);
41921  // DEBP(vector_vertex_node[h][1]);
41922  // }
41923 
41924  // Create a temporal "curve section" version of the recently created
41925  // polyline
41926  TriangleMeshCurveSection* tmp_curve_section_pt = tmp_polyline_pt;
41927 
41928  // Tolerance below which the middle point can be deleted
41929  // (ratio of deflection to element length)
41930  double unrefinement_tolerance =
41931  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
41932 
41933  // Tolerance to add points
41934  double refinement_tolerance =
41935  polygon_pt->polyline_pt(p)->refinement_tolerance();
41936 
41937  // Establish refinement and unrefinement tolerance
41938  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
41939  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
41940 
41941  // Establish the maximum length constraint
41942  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
41943  tmp_polyline_pt->set_maximum_length(maximum_length);
41944 
41945  if (n_vertex >= 2)
41946  {
41947  // Pass the connection information from the old polyline to the
41948  // new one
41949  this->copy_connection_information(polygon_pt->polyline_pt(p),
41950  tmp_curve_section_pt);
41951  }
41952 
41953  // Now update the polyline according to the new vertices but
41954  // first check if the object is allowed to delete the representation
41955  // or if it should be done by other object
41956  bool delete_it_on_destructor = false;
41957 
41958  std::set<TriangleMeshCurveSection*>::iterator it =
41959  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
41960 
41961  if (it != this->Free_curve_section_pt.end())
41962  {
41963  this->Free_curve_section_pt.erase(it);
41964  delete polygon_pt->curve_section_pt(p);
41965  delete_it_on_destructor = true;
41966  }
41967 
41968  // *****************************************************************
41969  // Copying the new representation
41970  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
41971 
41972  // Update the Boundary - Polyline map
41973  this->Boundary_curve_section_pt[bound] =
41974  polygon_pt->curve_section_pt(p);
41975 
41976  if (delete_it_on_destructor)
41977  {
41978  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
41979  }
41980 
41981 #ifdef OOMPH_HAS_MPI
41982  // --------- Stuff for the sub_boundaries ----- Begin section --------
41983  // Verify if need to deal with sub_boundaries
41984  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41985  {
41986  // Create temporary representations for the boundaries, only to
41987  // create the mesh when calling Triangle
41988  // Clear all previous stored data
41989  this->Boundary_subpolylines[bound].clear();
41990  // Now create storage for the sub-boundaries
41991  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
41992  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41993  {
41994  // Now update the polyline according to the sub set of
41995  // vertices, set the chunk number of the polyline
41996  TriangleMeshPolyLine* sub_tmp_polyline_pt =
41997  new TriangleMeshPolyLine(
41998  sub_vector_vertex_node[isub], bound, isub);
41999 
42000  // Add the sub-polyline to the container to represent the boundary
42001  // in parts
42002  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
42003 
42004  // No need to send the unrefinement/refinement and maximum
42005  // length constraints since these are only temporary
42006  // representations. These polylines can be deleted once the
42007  // new polygons that represent the distributed domain have
42008  // been created
42009 
42010  } // for (isub < nsub_boundaries)
42011 
42012  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42013  // --------- Stuff for the sub_boundaries ----- End section ---------
42014 #endif // OOMPH_HAS_MPI
42015 
42016  } // update polyline representation
42017 
42018  // Delete the allocated memory for the geometric object that
42019  // represents the curvilinear boundary
42020  delete mesh_geom_obj_pt;
42021 
42022  } // npolyline
42023 
42024  // Cleanup the face mesh
42025  for (unsigned p = 0; p < n_polyline; p++)
42026  {
42027  face_mesh_pt[p]->flush_node_storage();
42028  delete face_mesh_pt[p];
42029  }
42030  }
42031 
42032 
42033  //======================================================================
42034  /// Updates the open curve representation after restart
42035  //======================================================================
42036  template<class ELEMENT>
42038  TriangleMeshOpenCurve*& open_curve_pt)
42039  {
42040  // **********************************************************************
42041  // 1) Get the vertices along the boundaries ids of the polylines and
42042  // update them
42043  // **********************************************************************
42044 
42045  // (1.1) Get the face mesh representation
42046  Vector<Mesh*> face_mesh_pt;
42047  get_face_mesh_representation(open_curve_pt, face_mesh_pt);
42048 
42049  // (1.2) Create vertices of the polylines by using the vertices of the
42050  // FaceElements
42051  Vector<double> vertex_coord(3); // zeta,x,y
42052  Vector<double> bound_left(1);
42053  Vector<double> bound_right(1);
42054 
42055  const unsigned ncurve_section = open_curve_pt->ncurve_section();
42056  // Go for each curve section
42057  for (unsigned cs = 0; cs < ncurve_section; cs++)
42058  {
42059  // Get the MeshAsGeomObject representation just once per polyline,
42060  // this object is only used by the
42061  // refine_boundary_constrained_by_target_area() method. We get it here
42062  // to ensure that all processors (in a distributed context) get this
42063  // representation just once, and because an AllToAll MPI communication
42064  // is used in this calling
42065  MeshAsGeomObject* mesh_geom_obj_pt =
42066  new MeshAsGeomObject(face_mesh_pt[cs]);
42067 
42068  // Get the boundary id
42069  const unsigned bound = open_curve_pt->curve_section_pt(cs)->boundary_id();
42070 
42071  /// Use a vector of vector for vertices and target areas to deal
42072  /// with the cases when the boundaries are split bn the
42073  /// distribution process. Internal boundaries may be completely or
42074  /// partially overlapped by shared boundaries
42075 
42076  // Loop over the face elements and add their vertices (they are
42077  // automatically sorted because of the set)
42078  const unsigned nface_element = face_mesh_pt[cs]->nelement();
42079  // Store the non halo elements and the element at the other side of
42080  // the boundary (whatever it be halo or not), the first will be the
42081  // ones from which we will get the vertices (in even position)
42082  Vector<FiniteElement*> non_halo_doubled_face_element_pt;
42083 
42084  // Map to store the index of the face element on a boundary
42085  std::map<FiniteElement*, unsigned> face_element_index_on_boundary;
42086 
42087  // Map to know the already sorted face elements
42088  std::map<FiniteElement*, bool> face_element_done;
42089 
42090  for (unsigned ef = 0; ef < nface_element; ++ef)
42091  {
42092  FiniteElement* ele_face_pt = face_mesh_pt[cs]->finite_element_pt(ef);
42093 
42094  // Skip the halo elements (not used as base elements, only
42095  // include those elements which one of its counterparts -- at the
42096  // other side of the boundary -- is non halo)
42097 #ifdef OOMPH_HAS_MPI
42098  if (this->is_mesh_distributed())
42099  {
42100  // Only work with non-halo elements
42101  if (ele_face_pt->is_halo())
42102  {
42103  continue;
42104  }
42105  }
42106 #endif
42107 
42108  // Check if not already done
42109  if (!face_element_done[ele_face_pt])
42110  {
42111  // Add the element and look for the element at the other side
42112  // of the boundary to add it immediately after the new added
42113  // element
42114  non_halo_doubled_face_element_pt.push_back(ele_face_pt);
42115  // Create the map of the face element with the index
42116  face_element_index_on_boundary[ele_face_pt] = ef;
42117  // Mark the current element as done
42118  face_element_done[ele_face_pt] = true;
42119  // Get the number of nodes
42120  const unsigned nnodes = ele_face_pt->nnode();
42121  // Get the left and right node to look for the elements at the
42122  // other side of the boundary
42123  Node* left_node_pt = ele_face_pt->node_pt(0);
42124  Node* right_node_pt = ele_face_pt->node_pt(nnodes - 1);
42125 
42126 #ifdef PARANOID
42127  // Flag to know if the element at the other side of the
42128  // boundary was found
42129  bool found_other_side_face_ele = false;
42130 #endif
42131  for (unsigned iface = 0; iface < nface_element; iface++)
42132  {
42133  // Get the candidate face element
42134  FiniteElement* cele_face_pt =
42135  face_mesh_pt[cs]->finite_element_pt(iface);
42136  // Check if not already done
42137  if (!face_element_done[cele_face_pt])
42138  {
42139  Node* cleft_node_pt = cele_face_pt->node_pt(0);
42140  Node* cright_node_pt = cele_face_pt->node_pt(nnodes - 1);
42141 
42142  // Check if the nodes are the same
42143  if ((left_node_pt == cleft_node_pt &&
42144  right_node_pt == cright_node_pt) ||
42145  (left_node_pt == cright_node_pt &&
42146  right_node_pt == cleft_node_pt))
42147  {
42148  // Add the element to the storage
42149  non_halo_doubled_face_element_pt.push_back(cele_face_pt);
42150  // ... and mark the element as done
42151  face_element_done[cele_face_pt] = true;
42152  // Create the map of the face element with the index
42153  face_element_index_on_boundary[cele_face_pt] = iface;
42154 #ifdef PARANOID
42155  // Set the flag of found other side face element
42156  found_other_side_face_ele = true;
42157 #endif
42158  break;
42159  }
42160  }
42161  } // (iface < nface_element)
42162 
42163 #ifdef PARANOID
42164  if (!found_other_side_face_ele)
42165  {
42166  std::ostringstream error_message;
42167  error_message
42168  << "The face element at the other side of the boundary (" << bound
42169  << ") was not found!!\n"
42170  << "These are the nodes of the face element:\n"
42171  << "(" << left_node_pt->x(0) << ", " << left_node_pt->x(1) << ") "
42172  << "and (" << right_node_pt->x(0) << "," << right_node_pt->x(1)
42173  << ")\n\n";
42174  throw OomphLibError(
42175  error_message.str(),
42176  "RefineableTriangleMesh::update_open_curve_after_restart()",
42177  OOMPH_EXCEPTION_LOCATION);
42178  }
42179 #endif
42180  } // if (!face_ele_done[ele_face_pt])
42181 
42182  } // (ef < nface_element)
42183 
42184  // Clear the map of the already done face elements
42185  // This will now be used to sort the face elements
42186  face_element_done.clear();
42187 
42188  // Set of coordinates that are on the boundary
42189  // The entries are sorted on first entry in vector which stores
42190  // the boundary coordinate so the vertices come out in order!
42191  std::set<Vector<double>> vertex_nodes;
42192 
42193  // Vector to store the vertices, transfer the sorted vertices from the
42194  // set to this vector, --- including the z-value ---
42195  Vector<Vector<double>> tmp_vector_vertex_node;
42196 
42197  // Vector to store the coordinates of the polylines, same as the
42198  // tmp_vector_vertex_node vector (after adding more nodes) but
42199  // --- without the z-value ---, used to re-generate the polylines
42200  Vector<Vector<double>> vector_vertex_node;
42201 
42202 #ifdef OOMPH_HAS_MPI
42203  // Indicates if the set of vertices give rise to a internal
42204  // boundary that will be used as shared boundary or as normal
42205  // internal boundary -- Only used to deal with internal boundaries
42206  // in a distributed scheme
42207  std::vector<bool> internal_to_shared_boundary;
42208 
42209  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
42210  // Set of coordinates that are on the boundary (splitted boundary version)
42211  // The first vector is used to allocate the points for each sub-boundary
42212  // Set entries are ordered on first entry in vector which stores
42213  // the boundary coordinate so the vertices come out in order!
42214  Vector<std::set<Vector<double>>> sub_vertex_nodes;
42215 
42216  // Vector to store the vertices, transfer the sorted vertices from the
42217  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
42218  Vector<Vector<Vector<double>>> sub_tmp_vector_vertex_node;
42219 
42220  // Vector to store the coordinates of the polylines that will represent
42221  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
42222  // but --- without the z-value ---, used to generate the sub-polylines
42223  Vector<Vector<Vector<double>>> sub_vector_vertex_node;
42224 
42225  // --------- Stuff to deal with splitted boundaries ----------- End ------
42226 #endif
42227 
42228  // Sort face elements, separate those with both nonhalo face
42229  // elements from those with one halo and one nonhalo face element
42230 
42231  // Number of done face elements
42232  unsigned nsorted_face_elements = 0;
42233 
42234 #ifdef OOMPH_HAS_MPI
42235  // Counter for sub_boundaries
42236  unsigned nsub_boundaries = 0;
42237 #endif // #ifdef OOMPH_HAS_MPI
42238 
42239  // Total number of non halo double face element
42240  const unsigned nnon_halo_doubled_face_ele =
42241  non_halo_doubled_face_element_pt.size();
42242 
42243  // Continue until all the face elements have been sorted
42244  // This while is to deal with the cases of splitted boundaries
42245  while (nsorted_face_elements < nnon_halo_doubled_face_ele)
42246  {
42247  // Get and initial face element
42248  FiniteElement* ele_face_pt = 0;
42249  FiniteElement* repeated_ele_face_pt = 0;
42250 #ifdef PARANOID
42251  bool found_initial_face_element = false;
42252 #endif
42253 
42254  // Flag to know if we are working with a face element which the
42255  // face element at the other side of the boundary is also non
42256  // halo
42257  bool both_root_face_elements_are_nonhalo = false;
42258 
42259  unsigned iface = 0;
42260  for (iface = 0; iface < nnon_halo_doubled_face_ele; iface += 2)
42261  {
42262  ele_face_pt = non_halo_doubled_face_element_pt[iface];
42263  // If not done then take it as initial face element
42264  if (!face_element_done[ele_face_pt])
42265  {
42266  // Mark it as done
42267  face_element_done[ele_face_pt] = true;
42268  // Get the other side boundary face element
42269  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iface + 1];
42270  // ... also mark as done the repeated face element
42271  face_element_done[repeated_ele_face_pt] = true;
42272 
42273 #ifdef OOMPH_HAS_MPI
42274  if (!repeated_ele_face_pt->is_halo())
42275  {
42276  both_root_face_elements_are_nonhalo = true;
42277  }
42278 #endif // #ifdef OOMPH_HAS_MPI
42279 
42280  // Plus two because internal boundaries have
42281  // two face elements per each edge
42282  nsorted_face_elements += 2;
42283  iface += 2;
42284 #ifdef PARANOID
42285  // And set the flag to true
42286  found_initial_face_element = true;
42287 #endif
42288  break;
42289  }
42290  }
42291 
42292 #ifdef PARANOID
42293  if (!found_initial_face_element)
42294  {
42295  std::ostringstream error_message;
42296  error_message << "Could not find an initial face element for the "
42297  "current segment\n";
42298  // << "----- Possible memory leak -----\n";
42299  throw OomphLibError(error_message.str(),
42300  OOMPH_CURRENT_FUNCTION,
42301  OOMPH_EXCEPTION_LOCATION);
42302  }
42303 #endif
42304 
42305  // Local set of coordinates that are on the boundary Set entries
42306  // are ordered on first entry in vector which stores the boundary
42307  // coordinate so the vertices come out in order
42308  std::set<Vector<double>> local_vertex_nodes;
42309 
42310  // Vector to store the vertices, transfer the sorted vertices from the
42311  // set (local) to this vector (local), --- including the z-value ---
42312  Vector<Vector<double>> local_tmp_vector_vertex_node;
42313 
42314  // ------------------------------------------------------------------
42315  // ------------------------------------------------------------------
42316  // Add the vertices of the initial face element to the set of local
42317  // sorted vertices
42318  // ------------------------------------------------------------------
42319  // ------------------------------------------------------------------
42320  const unsigned nnode = ele_face_pt->nnode();
42321  // Add the left-hand node to the set:
42322  // Boundary coordinate
42323  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound, bound_left);
42324  vertex_coord[0] = bound_left[0];
42325 
42326  // Actual coordinates
42327  for (unsigned i = 0; i < 2; i++)
42328  {
42329  vertex_coord[i + 1] = ele_face_pt->node_pt(0)->x(i);
42330  }
42331  local_vertex_nodes.insert(vertex_coord);
42332 
42333  // Add the right-hand node to the set:
42334  // Boundary coordinate
42335  ele_face_pt->node_pt(nnode - 1)->get_coordinates_on_boundary(
42336  bound, bound_right);
42337  vertex_coord[0] = bound_right[0];
42338 
42339  // Actual coordinates
42340  for (unsigned i = 0; i < 2; i++)
42341  {
42342  vertex_coord[i + 1] = ele_face_pt->node_pt(nnode - 1)->x(i);
42343  }
42344  local_vertex_nodes.insert(vertex_coord);
42345 
42346  // The initial and final node on the set
42347  Node* first_node_pt = ele_face_pt->node_pt(0);
42348  Node* last_node_pt = ele_face_pt->node_pt(nnode - 1);
42349 
42350  // Continue iterating if a new face element has been added to the
42351  // list
42352  bool face_element_added = false;
42353 
42354  // While a new face element has been added to the set of sorted
42355  // face elements then re-iterate
42356  do
42357  {
42358  // Start from the next face elements since we have already
42359  // added the previous one as the initial face element (any
42360  // previous face element had to be added on previous
42361  // iterations)
42362  for (unsigned iiface = iface; iiface < nnon_halo_doubled_face_ele;
42363  iiface += 2)
42364  {
42365  face_element_added = false;
42366  ele_face_pt = non_halo_doubled_face_element_pt[iiface];
42367 
42368  // Check that the face element with which we are working has
42369  // the same conditions as the root face element (both faces
42370  // are nonhalo or one face is halo and the other nonhalo)
42371 
42372  // Get the face element at the other side of the boundary
42373  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface + 1];
42374  bool both_face_elements_are_nonhalo = false;
42375 
42376 #ifdef OOMPH_HAS_MPI
42377  if (!repeated_ele_face_pt->is_halo())
42378  {
42379  both_face_elements_are_nonhalo = true;
42380  }
42381 #endif // #ifdef OOMPH_HAS_MPI
42382 
42383  if (!face_element_done[ele_face_pt] &&
42384  (both_face_elements_are_nonhalo ==
42385  both_root_face_elements_are_nonhalo))
42386  {
42387  // Get each individual node to check if they are contiguous
42388  const unsigned nlnode = ele_face_pt->nnode();
42389  Node* left_node_pt = ele_face_pt->node_pt(0);
42390  Node* right_node_pt = ele_face_pt->node_pt(nlnode - 1);
42391 
42392  if (left_node_pt == first_node_pt)
42393  {
42394  first_node_pt = right_node_pt;
42395  face_element_added = true;
42396  }
42397  else if (left_node_pt == last_node_pt)
42398  {
42399  last_node_pt = right_node_pt;
42400  face_element_added = true;
42401  }
42402  else if (right_node_pt == first_node_pt)
42403  {
42404  first_node_pt = left_node_pt;
42405  face_element_added = true;
42406  }
42407  else if (right_node_pt == last_node_pt)
42408  {
42409  last_node_pt = left_node_pt;
42410  face_element_added = true;
42411  }
42412 
42413  if (face_element_added)
42414  {
42415  // Add the left-hand node to the set:
42416  // Boundary coordinate
42417  left_node_pt->get_coordinates_on_boundary(bound, bound_left);
42418  vertex_coord[0] = bound_left[0];
42419 
42420  // Actual coordinates
42421  for (unsigned i = 0; i < 2; i++)
42422  {
42423  vertex_coord[i + 1] = left_node_pt->x(i);
42424  }
42425  local_vertex_nodes.insert(vertex_coord);
42426 
42427  // Add the right-hand nodes to the set:
42428  // Boundary coordinate
42429  right_node_pt->get_coordinates_on_boundary(bound, bound_right);
42430  vertex_coord[0] = bound_right[0];
42431 
42432  // Actual coordinates
42433  for (unsigned i = 0; i < 2; i++)
42434  {
42435  vertex_coord[i + 1] = right_node_pt->x(i);
42436  }
42437  local_vertex_nodes.insert(vertex_coord);
42438 
42439  // Mark as done only if one of its nodes has been
42440  // added to the list
42441  face_element_done[ele_face_pt] = true;
42442  // .. also mark as done the face element at the othe side of
42443  // the boundary
42444  repeated_ele_face_pt =
42445  non_halo_doubled_face_element_pt[iiface + 1];
42446  face_element_done[repeated_ele_face_pt] = true;
42447  // ... and increase the number of sorted face elements
42448  nsorted_face_elements += 2;
42449 
42450  break;
42451  }
42452 
42453  } // if (!face_element_done[[ele_face_pt])
42454  } // for (iiface<nnon_halo_doubled_face_ele)
42455  } while (face_element_added &&
42456  (nsorted_face_elements < nnon_halo_doubled_face_ele));
42457 
42458  // -------------------------------------------------------------
42459  // At this point we already have a sorted set of nodes and can
42460  // be used to peform the unrefinement and refinement procedures
42461  // -------------------------------------------------------------
42462 
42463  // Get the number of nodes on the list
42464  const unsigned nlocal_nodes = local_vertex_nodes.size();
42465  // Change representation to vector for easy of handling ...
42466  local_tmp_vector_vertex_node.resize(nlocal_nodes);
42467 
42468  // Copy the vertices of the nodes
42469  unsigned counter = 0;
42470  std::set<Vector<double>>::iterator it_vertex;
42471  for (it_vertex = local_vertex_nodes.begin();
42472  it_vertex != local_vertex_nodes.end();
42473  it_vertex++)
42474  {
42475  local_tmp_vector_vertex_node[counter].resize(3);
42476  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
42477  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
42478  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
42479  counter++;
42480  }
42481 
42482  // The unrefinement and refinement process needs to be applied
42483  // from the bottom-left node since the internal open curve could
42484  // lie on the shared boundaries
42485  if (local_tmp_vector_vertex_node[nlocal_nodes - 1][2] <
42486  local_tmp_vector_vertex_node[0][2])
42487  {
42488  std::reverse(local_tmp_vector_vertex_node.begin(),
42489  local_tmp_vector_vertex_node.end());
42490  }
42491  else if (local_tmp_vector_vertex_node[nlocal_nodes - 1][2] ==
42492  local_tmp_vector_vertex_node[0][2])
42493  {
42494  if (local_tmp_vector_vertex_node[nlocal_nodes - 1][1] <
42495  local_tmp_vector_vertex_node[0][1])
42496  {
42497  std::reverse(local_tmp_vector_vertex_node.begin(),
42498  local_tmp_vector_vertex_node.end());
42499  }
42500  }
42501 
42502  // ****************************************************************
42503  // 3) Create the vertices along the boundary using the target
42504  // area to define the distance among them
42505  // ****************************************************************
42506 
42507  // Clear the local containter to recover the nodes ordered using
42508  // the zeta value
42509  local_vertex_nodes.clear();
42510 
42511  // At the end of each unrefinement/refinement step store the new
42512  // nodes on the set that will give rise to the vertices of the
42513  // new polyline representation
42514  const unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
42515  for (unsigned i = 0; i < nnew_nodes; i++)
42516  {
42517  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
42518  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
42519  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
42520  vertex_nodes.insert(vertex_coord); // Global container
42521  local_vertex_nodes.insert(vertex_coord);
42522  }
42523 
42524 #ifdef OOMPH_HAS_MPI
42525  if (this->is_mesh_distributed())
42526  {
42527  // Add the set of vertices for the boundary, this will help to
42528  // detect if we need to deal with sub_boundaries and
42529  // sub_polylines representations
42530  sub_vertex_nodes.push_back(local_vertex_nodes);
42531  // Increase the counter for sub_boundaries
42532  nsub_boundaries++;
42533 
42534  // Mark if the polyline created by these vertices will be used
42535  // as a shared boundary or as an internal boundary
42536  if (both_root_face_elements_are_nonhalo)
42537  {
42538  internal_to_shared_boundary.push_back(false);
42539  }
42540  else
42541  {
42542  internal_to_shared_boundary.push_back(true);
42543  }
42544  }
42545 #endif
42546 
42547  } // while(nsorted_face_elements < nnon_halo_doubled_face_ele)
42548  // This while is in charge of sorting all the face elements to
42549  // create the new representation of the polyline (also deals
42550  // with the sub-boundary cases)
42551 
42552  // Now turn into vector for ease of handling...
42553  const unsigned npoly_vertex = vertex_nodes.size();
42554  tmp_vector_vertex_node.resize(npoly_vertex);
42555  unsigned count = 0;
42556  std::set<Vector<double>>::iterator it;
42557  for (it = vertex_nodes.begin(); it != vertex_nodes.end(); ++it)
42558  {
42559  tmp_vector_vertex_node[count].resize(3);
42560  tmp_vector_vertex_node[count][0] = (*it)[0];
42561  tmp_vector_vertex_node[count][1] = (*it)[1];
42562  tmp_vector_vertex_node[count][2] = (*it)[2];
42563  ++count;
42564  }
42565 
42566 #ifdef OOMPH_HAS_MPI
42567  // Check that the number of set of vertices marked to be shared or
42568  // internal boundaries be the same as the total number of
42569  // sub-boundaries
42570 #ifdef PARANOID
42571  const unsigned nsub_boundaries_set = sub_vertex_nodes.size();
42572  const unsigned ninternal_to_shared_boundaries =
42573  internal_to_shared_boundary.size();
42574  if (nsub_boundaries_set != ninternal_to_shared_boundaries)
42575  {
42576  std::ostringstream error_message;
42577  error_message
42578  << "The number of found sub-boundaries and the number of marked "
42579  << "internal\nboundaries are different\n"
42580  << "Number of found sub-boundaries: (" << nsub_boundaries_set << ")\n"
42581  << "Number of marked internal boundaries: ("
42582  << ninternal_to_shared_boundaries << ")\n\n";
42583  throw OomphLibError(
42584  error_message.str(),
42585  "RefineableTriangleMesh::update_open_curve_after_restart()",
42586  OOMPH_EXCEPTION_LOCATION);
42587  }
42588 #endif
42589 
42590  // --------- Stuff for the sub_boundaries ----- Begin section -------
42591 #ifdef PARANOID
42592  if (nsub_boundaries_set != nsub_boundaries)
42593  {
42594  std::ostringstream error_message;
42595  error_message
42596  << "The number of found sub-boundaries and the number of counted\n"
42597  << "sub-boundaries are different:\n"
42598  << "Number of found sub-boundaries: (" << nsub_boundaries_set << ")\n"
42599  << "Number of counted sub-boundaries: (" << nsub_boundaries
42600  << ")\n\n";
42601  throw OomphLibError(
42602  error_message.str(),
42603  "RefineableTriangleMesh::update_open_curve_after_restart()",
42604  OOMPH_EXCEPTION_LOCATION);
42605  }
42606 #endif
42607 
42608  // Verify if need to deal with sub_boundaries
42609  if (this->is_mesh_distributed() && nsub_boundaries > 1)
42610  {
42611  // Mark the boundary as been splitted in the partition process
42612  this->Boundary_was_splitted[bound] = true;
42613  // Resize the vector to store the info. of sub-boundaries
42614  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
42615  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42616  {
42617  // Turn info. into vector for ease of handling...
42618  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
42619  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
42620  unsigned subcount = 0;
42621  std::set<Vector<double>>::iterator subit;
42622  for (subit = sub_vertex_nodes[isub].begin();
42623  subit != sub_vertex_nodes[isub].end();
42624  ++subit)
42625  {
42626  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
42627  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
42628  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
42629  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
42630  ++subcount;
42631  }
42632  }
42633  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42634  // --------- Stuff for the sub_boundaries ----- End section ----------
42635 #endif // OOMPH_HAS_MPI
42636 
42637  // For further processing the three-dimensional vector has to be
42638  // reduced to a two-dimensional vector
42639  unsigned n_vertex = tmp_vector_vertex_node.size();
42640 
42641  // Resize the vector for vectices
42642  vector_vertex_node.resize(n_vertex);
42643  for (unsigned i = 0; i < n_vertex; i++)
42644  {
42645  vector_vertex_node[i].resize(2);
42646  vector_vertex_node[i][0] = tmp_vector_vertex_node[i][1];
42647  vector_vertex_node[i][1] = tmp_vector_vertex_node[i][2];
42648  }
42649 
42650 #ifdef OOMPH_HAS_MPI
42651  // --------- Stuff for the sub_boundaries ----- Begin section ----------
42652  // Verify if need to deal with sub_boundaries
42653  if (this->is_mesh_distributed() && nsub_boundaries > 1)
42654  {
42655  // For further processing the three-dimensional vector
42656  // has to be reduced to a two-dimensional vector
42657  // Resize the vector to store the info. of sub-boundaries
42658  sub_vector_vertex_node.resize(nsub_boundaries);
42659  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42660  {
42661  const unsigned subn_vertex = sub_tmp_vector_vertex_node[isub].size();
42662  // Resize the vector for vectices
42663  sub_vector_vertex_node[isub].resize(subn_vertex);
42664  for (unsigned i = 0; i < subn_vertex; i++)
42665  {
42666  sub_vector_vertex_node[isub][i].resize(2);
42667  sub_vector_vertex_node[isub][i][0] =
42668  sub_tmp_vector_vertex_node[isub][i][1];
42669  sub_vector_vertex_node[isub][i][1] =
42670  sub_tmp_vector_vertex_node[isub][i][2];
42671  }
42672  }
42673  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42674 
42675  // We already have the info. for the sub-boundaries (if necessary) and
42676  // then we can create the sub-boundaries representations to ease the
42677  // generation of the mesh by Triangle
42678 
42679  // --------- Stuff for the sub_boundaries ----- End section ------------
42680 #endif // OOMPH_HAS_MPI
42681 
42682  // *********************************************************************
42683  // 4) Check for contiguousness
42684  // *********************************************************************
42685 #ifdef OOMPH_HAS_MPI
42686  // Only perform this checking if the mesh is not distributed
42687  // When the mesh is distributed the polylines continuity is
42688  // addressed with the sort_polylines_helper() method
42689  if (!this->is_mesh_distributed())
42690 #endif
42691  {
42692  if (cs > 0)
42693  {
42694  // Final end point of previous line
42695  Vector<double> final_vertex_of_previous_segment;
42696  unsigned n_prev_vertex =
42697  open_curve_pt->curve_section_pt(cs - 1)->nvertex();
42698  final_vertex_of_previous_segment =
42699  open_curve_pt->polyline_pt(cs - 1)->vertex_coordinate(
42700  n_prev_vertex - 1);
42701 
42702  unsigned prev_seg_boundary_id =
42703  open_curve_pt->curve_section_pt(cs - 1)->boundary_id();
42704 
42705  // Find the error between the final vertex of the previous
42706  // line and the first vertex of the current line
42707  double error = 0.0;
42708  for (unsigned i = 0; i < 2; i++)
42709  {
42710  const double dist = final_vertex_of_previous_segment[i] -
42711  (*vector_vertex_node.begin())[i];
42712  error += dist * dist;
42713  }
42714  error = sqrt(error);
42715 
42716  // If the error is bigger than the tolerance then
42717  // we probably need to reverse, but better check
42718  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
42719  {
42720  // Find the error between the final vertex of the previous
42721  // line and the last vertex of the current line
42722  double rev_error = 0.0;
42723  for (unsigned i = 0; i < 2; i++)
42724  {
42725  const double dist = final_vertex_of_previous_segment[i] -
42726  (*--vector_vertex_node.end())[i];
42727  rev_error += dist * dist;
42728  }
42729  rev_error = sqrt(rev_error);
42730 
42731  if (rev_error >
42732  ToleranceForVertexMismatchInPolygons::Tolerable_error)
42733  {
42734  // It could be possible that the first segment be reversed and we
42735  // did not notice it because this check does not apply for the
42736  // first segment. We can verify if the first segment is reversed
42737  // by using the vertex number 1
42738  if (cs == 1)
42739  {
42740  // Initial end point of previous line
42741  Vector<double> initial_vertex_of_previous_segment;
42742 
42743  initial_vertex_of_previous_segment =
42744  open_curve_pt->polyline_pt(cs - 1)->vertex_coordinate(0);
42745 
42746  unsigned prev_seg_boundary_id =
42747  open_curve_pt->curve_section_pt(cs - 1)->boundary_id();
42748 
42749  // Find the error between the initial vertex of the previous
42750  // line and the first vertex of the current line
42751  double error = 0.0;
42752  for (unsigned i = 0; i < 2; i++)
42753  {
42754  const double dist = initial_vertex_of_previous_segment[i] -
42755  (*vector_vertex_node.begin())[i];
42756  error += dist * dist;
42757  }
42758  error = sqrt(error); // Reversed only the previous one
42759 
42760  // If the error is bigger than the tolerance then
42761  // we probably need to reverse, but better check
42762  if (error >
42763  ToleranceForVertexMismatchInPolygons::Tolerable_error)
42764  {
42765  // Find the error between the final vertex of the previous
42766  // line and the last vertex of the current line
42767  double rev_error = 0.0;
42768  for (unsigned i = 0; i < 2; i++)
42769  {
42770  const double dist = initial_vertex_of_previous_segment[i] -
42771  (*--vector_vertex_node.end())[i];
42772  rev_error += dist * dist;
42773  }
42774  rev_error = sqrt(rev_error); // Reversed both the current
42775  // one and the previous one
42776 
42777  if (rev_error >
42778  ToleranceForVertexMismatchInPolygons::Tolerable_error)
42779  {
42780  std::ostringstream error_stream;
42781  error_stream
42782  << "The distance between the first node of the current\n"
42783  << "line segment (boundary " << bound
42784  << ") and either end of "
42785  << "the previous line segment\n"
42786  << "(boundary " << prev_seg_boundary_id
42787  << ") is bigger than"
42788  << " the desired tolerance "
42789  << ToleranceForVertexMismatchInPolygons::Tolerable_error
42790  << ".\n"
42791  << "This suggests that the polylines defining the "
42792  "polygonal\n"
42793  << "representation are not properly ordered.\n"
42794  << "Fail on last vertex of polyline: ("
42795  << prev_seg_boundary_id
42796  << ") and\nfirst vertex of polyline (" << bound
42797  << ").\nThis should have failed when first trying to "
42798  << "construct the\npolygon.\n";
42799  throw OomphLibError(error_stream.str(),
42800  "RefineableTriangleMesh::update_open_"
42801  "curve_after_restart()",
42802  OOMPH_EXCEPTION_LOCATION);
42803  }
42804  else
42805  {
42806  // Reverse both
42807  // Reverse the current vector to line up with the previous
42808  // one
42809  std::reverse(vector_vertex_node.begin(),
42810  vector_vertex_node.end());
42811  open_curve_pt->polyline_pt(cs - 1)->reverse();
42812  }
42813  }
42814  else
42815  {
42816  // Reverse the previous one
42817  open_curve_pt->polyline_pt(cs - 1)->reverse();
42818  }
42819 
42820  } // if (cs == 1)
42821  else
42822  {
42823  std::ostringstream error_stream;
42824  error_stream
42825  << "The distance between the first node of the current\n"
42826  << "line segment (boundary " << bound
42827  << ") and either end of "
42828  << "the previous line segment\n"
42829  << "(boundary " << prev_seg_boundary_id
42830  << ") is bigger than the "
42831  << "desired tolerance "
42832  << ToleranceForVertexMismatchInPolygons::Tolerable_error
42833  << ".\n"
42834  << "This suggests that the polylines defining the polygonal\n"
42835  << "representation are not properly ordered.\n"
42836  << "Fail on last vertex of polyline: ("
42837  << prev_seg_boundary_id << ") and\nfirst vertex of polyline ("
42838  << bound << ").\n"
42839  << "This should have failed when first trying to construct "
42840  "the\n"
42841  << "polygon.\n";
42842  throw OomphLibError(
42843  error_stream.str(),
42844  "RefineableTriangleMesh::update_open_curve_after_restart()",
42845  OOMPH_EXCEPTION_LOCATION);
42846  }
42847  }
42848  else
42849  {
42850  // Reverse the current vector to line up with the previous one
42851  std::reverse(vector_vertex_node.begin(),
42852  vector_vertex_node.end());
42853  }
42854  } // error
42855  } // (cs > 0)
42856  } // is mesh not distributed
42857 
42858  // DEBP(applied_area_length_constraint);
42859  // DEBP(p);
42860  // getchar();
42861  // *********************************************************************
42862  // 5) Update the polylines representation
42863  // *********************************************************************
42864  // if (applied_area_length_constraint)
42865  // If only applied when there is a change then it keeps the
42866  // previous polyline representation, it means, it does not delete
42867  // the boundaries that are not part of the domain. We must update
42868  // the boundary representation
42869  {
42870  n_vertex = vector_vertex_node.size();
42871 
42872  // Now update the polyline according to the new vertices
42873  // The new one representation
42874  TriangleMeshPolyLine* tmp_polyline_pt =
42875  new TriangleMeshPolyLine(vector_vertex_node, bound);
42876 
42877  // Create a temporal "curve section" version of the recently created
42878  // polyline
42879  TriangleMeshCurveSection* tmp_curve_section_pt = tmp_polyline_pt;
42880 
42881  // Tolerance below which the middle point can be deleted
42882  // (ratio of deflection to element length)
42883  double unrefinement_tolerance =
42884  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
42885 
42886  // Tolerance to add points
42887  double refinement_tolerance =
42888  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
42889 
42890  // Establish refinement and unrefinement tolerance
42891  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
42892  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
42893 
42894  // Establish the maximum length constraint
42895  double maximum_length =
42896  open_curve_pt->polyline_pt(cs)->maximum_length();
42897  tmp_polyline_pt->set_maximum_length(maximum_length);
42898 
42899  if (n_vertex >= 2)
42900  {
42901  // Pass the connection information from the old polyline to the
42902  // new one
42903  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
42904  tmp_curve_section_pt);
42905  }
42906 
42907  // Now update the polyline according to the new vertices but first
42908  // check if the object is allowed to delete the representation or
42909  // if it should be done by other object
42910  bool delete_it_on_destructor = false;
42911 
42912  std::set<TriangleMeshCurveSection*>::iterator it =
42913  this->Free_curve_section_pt.find(open_curve_pt->curve_section_pt(cs));
42914 
42915  if (it != this->Free_curve_section_pt.end())
42916  {
42917  this->Free_curve_section_pt.erase(it);
42918  delete open_curve_pt->curve_section_pt(cs);
42919  delete_it_on_destructor = true;
42920  }
42921 
42922  // *****************************************************************
42923  // Copying the new representation
42924  open_curve_pt->curve_section_pt(cs) = tmp_polyline_pt;
42925 
42926  // Update the Boundary - Polyline map
42927  this->Boundary_curve_section_pt[bound] =
42928  open_curve_pt->curve_section_pt(cs);
42929 
42930  if (delete_it_on_destructor)
42931  {
42932  this->Free_curve_section_pt.insert(
42933  open_curve_pt->curve_section_pt(cs));
42934  }
42935 
42936 #ifdef OOMPH_HAS_MPI
42937 
42938  // If there are not sub-boundaries mark the boundary if need to be
42939  // trated as shared or as internal boundary
42940  if (this->is_mesh_distributed() && nsub_boundaries == 1)
42941  {
42942  // Clear all previous stored data
42943  this->Boundary_marked_as_shared_boundary[bound].clear();
42944 
42945  // .. and store the flag for the boundary
42946  this->Boundary_marked_as_shared_boundary[bound].push_back(
42947  internal_to_shared_boundary[0]);
42948  }
42949  // --------- Stuff for the sub_boundaries ----- Begin section --------
42950  // Verify if need to deal with sub_boundaries
42951  else if (this->is_mesh_distributed() && nsub_boundaries > 1)
42952  {
42953  // Create temporary representations for the boundaries, only to
42954  // create the mesh when calling Triangle
42955  // Clear all previous stored data
42956  this->Boundary_subpolylines[bound].clear();
42957  // Now create storage for the sub-boundaries
42958  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
42959 
42960  // Clear all previous stored data
42961  this->Boundary_marked_as_shared_boundary[bound].clear();
42962  // Create storage to mark the internal boundaries as shared
42963  // boundaries
42964  this->Boundary_marked_as_shared_boundary[bound].resize(
42965  nsub_boundaries);
42966  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42967  {
42968  // Now update the polyline according to the sub set of
42969  // vertices, set the chunk number of the polyline
42970  TriangleMeshPolyLine* sub_tmp_polyline_pt =
42971  new TriangleMeshPolyLine(
42972  sub_vector_vertex_node[isub], bound, isub);
42973 
42974  // Add the sub-polyline to the container to represent the
42975  // boundary in parts
42976  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
42977 
42978  // Copy the flag that mark the boundary as internal or as
42979  // shared bound
42980  this->Boundary_marked_as_shared_boundary[bound][isub] =
42981  internal_to_shared_boundary[isub];
42982 
42983  // No need to send the unrefinement/refinement and maximum
42984  // length constraints since these are only temporary
42985  // representations
42986  }
42987 
42988  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42989  // --------- Stuff for the sub_boundaries ----- End section ---------
42990 #endif // OOMPH_HAS_MPI
42991 
42992  } // update polyline representation
42993 
42994  // Delete the allocated memory for the geometric object
42995  // that represents the curvilinear boundary
42996  delete mesh_geom_obj_pt;
42997 
42998  } // npolyline
42999 
43000  // Cleanup the face mesh
43001  for (unsigned p = 0; p < ncurve_section; p++)
43002  {
43003  face_mesh_pt[p]->flush_node_storage();
43004  delete face_mesh_pt[p];
43005  }
43006  }
43007 
43008 #ifdef OOMPH_HAS_MPI
43009  //======================================================================
43010  /// Updates the shared polylines representation after restart
43011  //======================================================================
43012  template<class ELEMENT>
43014  Vector<TriangleMeshPolyLine*>& vector_polyline_pt)
43015  {
43016  // Go through all the shared boundaries/polylines
43017  const unsigned npolylines = vector_polyline_pt.size();
43018  for (unsigned pp = 0; pp < npolylines; pp++)
43019  {
43020  // Get the boundary of the current polyline
43021  const unsigned b = vector_polyline_pt[pp]->boundary_id();
43022 
43023  // Get the edges of the shared boundary elements that create the
43024  // shared boundary and store the shared boundary elements from where
43025  // were created
43026  std::map<std::pair<Node*, Node*>, FiniteElement*> halo_edge_element_pt;
43027  std::map<std::pair<Node*, Node*>, FiniteElement*> nonhalo_edge_element_pt;
43028 
43029  // Store the nodes that define the edges
43030  Vector<Node*> halo_edge_nodes_pt;
43031  Vector<Node*> nonhalo_edge_nodes_pt;
43032 
43033  // Go through the shared boundary elements and store their edges
43034  const unsigned nshared_bound_ele = this->nshared_boundary_element(b);
43035  for (unsigned e = 0; e < nshared_bound_ele; e++)
43036  {
43037  // Get the shared boundary element
43038  FiniteElement* current_ele_pt = this->shared_boundary_element_pt(b, e);
43039 
43040  // Get the corner nodes, the first three nodes
43041  Node* first_node_pt = current_ele_pt->node_pt(0);
43042  Node* second_node_pt = current_ele_pt->node_pt(1);
43043  Node* third_node_pt = current_ele_pt->node_pt(2);
43044 
43045  // Check if the elements is halo
43046  if (!current_ele_pt->is_halo())
43047  {
43048  // Store the edges
43049  nonhalo_edge_nodes_pt.push_back(first_node_pt);
43050  nonhalo_edge_nodes_pt.push_back(second_node_pt);
43051 
43052  nonhalo_edge_nodes_pt.push_back(second_node_pt);
43053  nonhalo_edge_nodes_pt.push_back(third_node_pt);
43054 
43055  nonhalo_edge_nodes_pt.push_back(third_node_pt);
43056  nonhalo_edge_nodes_pt.push_back(first_node_pt);
43057 
43058  // Store the info. of the element used to create these edges
43059  std::pair<Node*, Node*> edge1 =
43060  std::make_pair(first_node_pt, second_node_pt);
43061  nonhalo_edge_element_pt[edge1] = current_ele_pt;
43062 
43063  std::pair<Node*, Node*> edge2 =
43064  std::make_pair(second_node_pt, third_node_pt);
43065  nonhalo_edge_element_pt[edge2] = current_ele_pt;
43066 
43067  std::pair<Node*, Node*> edge3 =
43068  std::make_pair(third_node_pt, first_node_pt);
43069  nonhalo_edge_element_pt[edge3] = current_ele_pt;
43070  }
43071  else
43072  {
43073  // Store the edges
43074  halo_edge_nodes_pt.push_back(first_node_pt);
43075  halo_edge_nodes_pt.push_back(second_node_pt);
43076 
43077  halo_edge_nodes_pt.push_back(second_node_pt);
43078  halo_edge_nodes_pt.push_back(third_node_pt);
43079 
43080  halo_edge_nodes_pt.push_back(third_node_pt);
43081  halo_edge_nodes_pt.push_back(first_node_pt);
43082 
43083  // Store the info. of the element used to create these edges
43084  std::pair<Node*, Node*> edge1 =
43085  std::make_pair(first_node_pt, second_node_pt);
43086  halo_edge_element_pt[edge1] = current_ele_pt;
43087 
43088  std::pair<Node*, Node*> edge2 =
43089  std::make_pair(second_node_pt, third_node_pt);
43090  halo_edge_element_pt[edge2] = current_ele_pt;
43091 
43092  std::pair<Node*, Node*> edge3 =
43093  std::make_pair(third_node_pt, first_node_pt);
43094  halo_edge_element_pt[edge3] = current_ele_pt;
43095  }
43096 
43097  } // for (e < nshared_bound_ele)
43098 
43099  // Filter the edges that give rise to a shared boundary
43100 
43101  // Mark the done edges
43102  std::map<std::pair<Node*, Node*>, bool> edge_done;
43103 
43104  // Storage for the edges shared by the elements
43105  Vector<std::pair<Node*, Node*>> unsorted_edges;
43106 
43107  // Storage for the elements that created the unsorted edges (two
43108  // elements, one at each side of the shared boundary)
43109  Vector<Vector<FiniteElement*>> unsorted_edges_elements_pt;
43110 
43111  const unsigned nnonhalo_edge_nodes = nonhalo_edge_nodes_pt.size();
43112  for (unsigned i = 0; i < nnonhalo_edge_nodes; i += 2)
43113  {
43114  Vector<Node*> currenti_edge(2);
43115  currenti_edge[0] = nonhalo_edge_nodes_pt[i];
43116  currenti_edge[1] = nonhalo_edge_nodes_pt[i + 1];
43117 
43118  // Create the edge (both nodes that make the edge)
43119  std::pair<Node*, Node*> new_edge =
43120  std::make_pair(currenti_edge[0], currenti_edge[1]);
43121 
43122  if (!edge_done[new_edge])
43123  {
43124  const unsigned nhalo_edge_nodes = halo_edge_nodes_pt.size();
43125  for (unsigned j = 0; j < nhalo_edge_nodes; j += 2)
43126  {
43127  Vector<Node*> currentj_edge(2);
43128  currentj_edge[0] = halo_edge_nodes_pt[j];
43129  currentj_edge[1] = halo_edge_nodes_pt[j + 1];
43130 
43131  // Comparing pointer of nodes
43132  if (currenti_edge[0] == currentj_edge[0] &&
43133  currenti_edge[1] == currentj_edge[1])
43134  {
43135  // Store the edge in the proper container
43136  unsorted_edges.push_back(new_edge);
43137 
43138  // Get the elements associated with the edges
43139  Vector<FiniteElement*> tmp_edge_element_pt;
43140 
43141  FiniteElement* nonhalo_ele_pt = nonhalo_edge_element_pt[new_edge];
43142  FiniteElement* halo_ele_pt = halo_edge_element_pt[new_edge];
43143 
43144  tmp_edge_element_pt.push_back(nonhalo_ele_pt);
43145  tmp_edge_element_pt.push_back(halo_ele_pt);
43146 
43147  // Store the elements associated with the edge
43148  unsorted_edges_elements_pt.push_back(tmp_edge_element_pt);
43149 
43150  // Mark the edge as done
43151  edge_done[new_edge] = true;
43152 
43153  // Break the loop for (j < nedge_node)
43154  break;
43155 
43156  } // equal edge
43157 
43158  // Comparing pointer of nodes (reversed)
43159  else if (currenti_edge[0] == currentj_edge[1] &&
43160  currenti_edge[1] == currentj_edge[0])
43161  {
43162  // Create the edge (both nodes that make the edge)
43163  std::pair<Node*, Node*> new_edge =
43164  std::make_pair(currenti_edge[0], currenti_edge[1]);
43165 
43166  // Store the edge in the proper container
43167  unsorted_edges.push_back(new_edge);
43168 
43169  // Create the (reversed) edge (both nodes that make the edge)
43170  std::pair<Node*, Node*> rev_new_edge =
43171  std::make_pair(currentj_edge[0], currentj_edge[1]);
43172 
43173  // Get the elements associated with the edge
43174  Vector<FiniteElement*> tmp_edge_element_pt;
43175 
43176  FiniteElement* nonhalo_ele_pt = nonhalo_edge_element_pt[new_edge];
43177  FiniteElement* halo_ele_pt = halo_edge_element_pt[rev_new_edge];
43178 
43179  tmp_edge_element_pt.push_back(nonhalo_ele_pt);
43180  tmp_edge_element_pt.push_back(halo_ele_pt);
43181 
43182  // Store the elements associated with the edge
43183  unsorted_edges_elements_pt.push_back(tmp_edge_element_pt);
43184 
43185  // Mark the edge as done
43186  edge_done[new_edge] = true;
43187 
43188  // Break the loop for (j < nedge_node)
43189  break;
43190 
43191  } // if (equal edge)
43192 
43193  } // for (j < nhalo_edge_nodes)
43194 
43195  } // if (!edge_done[new_edge])
43196 
43197  } // for (i < nnonhalo_edge_nodes)
43198 
43199  // We already have the edges that make the shared boundary (and the
43200  // elements)
43201  // Sort them to create a contiguous boundary
43202 
43203  // Mark the already sorted edges
43204  std::map<std::pair<Node*, Node*>, bool> edge_sorted;
43205 
43206  const unsigned nunsorted_edges = unsorted_edges.size();
43207 
43208 #ifdef PARANOID
43209  // The number of unsorted edges must be the same as the number of
43210  // shared_boundary element / 2
43211  if (nshared_bound_ele / 2 != nunsorted_edges)
43212  {
43213  std::ostringstream error_message;
43214  error_message
43215  << "The number of shared boundary elements (" << nshared_bound_ele
43216  << ") is not the double\nof the number of unsorted edges ("
43217  << nunsorted_edges << ") for the current boundary (" << b << ")\n\n";
43218  throw OomphLibError(
43219  error_message.str(),
43220  "RefineableTriangleMesh::update_shared_curve_after_restart()",
43221  OOMPH_EXCEPTION_LOCATION);
43222  }
43223 #endif
43224 
43225  unsigned nsorted_edges = 0;
43226 
43227  // Storing for the sorting nodes extracted from the edges, and
43228  // then used to update the polyline
43229  std::list<Node*> sorted_nodes;
43230 
43231  // Storing for the edges elements
43232  std::list<FiniteElement*> sorted_edges_elements_pt;
43233 
43234  // Get the root edge
43235  std::pair<Node*, Node*> edge = unsorted_edges[0];
43236  nsorted_edges++;
43237 
43238  // Mark edge as done
43239  edge_sorted[edge] = true;
43240 
43241  // The initial and final node on the list
43242  Node* first_node_pt = edge.first;
43243  Node* last_node_pt = edge.second;
43244 
43245  // Push back on the list the new edge (nodes)
43246  sorted_nodes.push_back(first_node_pt);
43247  sorted_nodes.push_back(last_node_pt);
43248 
43249  // Store the elements for the current edge
43250  sorted_edges_elements_pt.push_back(unsorted_edges_elements_pt[0][0]);
43251  sorted_edges_elements_pt.push_back(unsorted_edges_elements_pt[0][1]);
43252 
43253  // Iterate while the number of sorted edges be less than the number of
43254  // unsorted edges
43255  while (nsorted_edges < nunsorted_edges)
43256  {
43257  // Flag to indicate when a node was added
43258  bool node_added = false;
43259 
43260  // Start from the next edge since we have already added the
43261  // previous one as the initial edge
43262  for (unsigned iedge = 1; iedge < nunsorted_edges; iedge++)
43263  {
43264  edge = unsorted_edges[iedge];
43265 
43266  // If edge not done
43267  if (!edge_sorted[edge])
43268  {
43269  // Get each individual node
43270  Node* left_node_pt = edge.first;
43271  Node* right_node_pt = edge.second;
43272 
43273  if (left_node_pt == first_node_pt)
43274  {
43275  // Push front the new node
43276  sorted_nodes.push_front(right_node_pt);
43277  first_node_pt = right_node_pt;
43278  node_added = true;
43279 
43280  // Store the elements for the current edge
43281  sorted_edges_elements_pt.push_front(
43282  unsorted_edges_elements_pt[iedge][1]);
43283  sorted_edges_elements_pt.push_front(
43284  unsorted_edges_elements_pt[iedge][0]);
43285  }
43286  else if (left_node_pt == last_node_pt)
43287  {
43288  // Push back the new node
43289  sorted_nodes.push_back(right_node_pt);
43290  last_node_pt = right_node_pt;
43291  node_added = true;
43292 
43293  // Store the elements for the current edge
43294  sorted_edges_elements_pt.push_back(
43295  unsorted_edges_elements_pt[iedge][0]);
43296  sorted_edges_elements_pt.push_back(
43297  unsorted_edges_elements_pt[iedge][1]);
43298  }
43299  else if (right_node_pt == first_node_pt)
43300  {
43301  // Push front the new node
43302  sorted_nodes.push_front(left_node_pt);
43303  first_node_pt = left_node_pt;
43304  node_added = true;
43305 
43306  // Store the elements for the current edge
43307  sorted_edges_elements_pt.push_front(
43308  unsorted_edges_elements_pt[iedge][1]);
43309  sorted_edges_elements_pt.push_front(
43310  unsorted_edges_elements_pt[iedge][0]);
43311  }
43312  else if (right_node_pt == last_node_pt)
43313  {
43314  // Push back the new node
43315  sorted_nodes.push_back(left_node_pt);
43316  last_node_pt = left_node_pt;
43317  node_added = true;
43318 
43319  // Store the elements for the current edge
43320  sorted_edges_elements_pt.push_back(
43321  unsorted_edges_elements_pt[iedge][0]);
43322  sorted_edges_elements_pt.push_back(
43323  unsorted_edges_elements_pt[iedge][1]);
43324  }
43325 
43326  if (node_added)
43327  {
43328  // Mark as done only if one of its nodes has been
43329  // added to the list
43330  edge_sorted[edge] = true;
43331  nsorted_edges++;
43332 
43333  // Break the for
43334  break;
43335  }
43336 
43337  } // if (!edge_done[edge])
43338  } // for (iedge < nunsorted_edges)
43339  } // while (nsorted_edges < nunsorted_edges)
43340 
43341  // At this point we already have a sorted list of nodes, get the
43342  // vertices from them and store them in a vector container
43343 
43344  // Get the number of nodes on the list
43345  unsigned nvertex = sorted_nodes.size();
43346  // The vector to store the vertices (assign space)
43347  Vector<Vector<double>> polyline_vertices(nvertex);
43348 
43349  // Copy the vertices of the nodes
43350  unsigned counter = 0;
43351  for (std::list<Node*>::iterator it_nodes = sorted_nodes.begin();
43352  it_nodes != sorted_nodes.end();
43353  it_nodes++)
43354  {
43355  polyline_vertices[counter].resize(2);
43356  polyline_vertices[counter][0] = (*it_nodes)->x(0);
43357  polyline_vertices[counter][1] = (*it_nodes)->x(1);
43358  counter++;
43359  }
43360 
43361  // Before going to the unrefinement or refinement process check that
43362  // all processors start from the same vertex. Start from the bottom
43363  // left vertex
43364  if (polyline_vertices[nvertex - 1][1] < polyline_vertices[0][1])
43365  {
43366  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
43367  }
43368  else if (polyline_vertices[nvertex - 1][1] == polyline_vertices[0][1])
43369  {
43370  if (polyline_vertices[nvertex - 1][0] < polyline_vertices[0][0])
43371  {
43372  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
43373  }
43374  }
43375 
43376  // Create the polyline associated with this edge
43377  TriangleMeshPolyLine* new_polyline_pt =
43378  new TriangleMeshPolyLine(polyline_vertices, b);
43379 
43380  // Get the curve section representation
43381  TriangleMeshCurveSection* curve_section_pt = vector_polyline_pt[pp];
43382 
43383  // Copy the connection information from the old shared polyline
43384  // to the new one
43385  this->copy_connection_information(curve_section_pt, new_polyline_pt);
43386 
43387  // Now update the polyline according to the new vertices but first
43388  // check if the object is allowed to delete the representation
43389  // or if it should be done by other object
43390  bool delete_it_on_destructor = false;
43391 
43392  // Establish the element as being deleted by the destructor of
43393  // the class
43394  std::set<TriangleMeshCurveSection*>::iterator it =
43395  this->Free_curve_section_pt.find(curve_section_pt);
43396 
43397  if (it != this->Free_curve_section_pt.end())
43398  {
43399  this->Free_curve_section_pt.erase(it);
43400  delete curve_section_pt;
43401  delete_it_on_destructor = true;
43402  }
43403 
43404  // Copy the new representation
43405  vector_polyline_pt[pp] = new_polyline_pt;
43406 
43407  // Get the new curve section representation
43408  TriangleMeshCurveSection* new_curve_section_pt = vector_polyline_pt[pp];
43409 
43410  // Update the Boundary - Polyline map
43411  this->Boundary_curve_section_pt[b] = new_curve_section_pt;
43412 
43413  if (delete_it_on_destructor)
43414  {
43415  this->Free_curve_section_pt.insert(new_curve_section_pt);
43416  }
43417 
43418  } // for (pp < npoly)
43419  }
43420 
43421  //===================================================================
43422  // Fill the boundary elements structures when dealing with
43423  // shared boundaries that overlap internal boundaries. Document the
43424  // number of elements on the shared boundaries that go to internal
43425  // boundaries
43426  //===================================================================
43427  template<class ELEMENT>
43429  ELEMENT>::fill_boundary_elements_and_nodes_for_internal_boundaries()
43430  {
43431  // Dummy file
43432  std::ofstream some_file;
43433  fill_boundary_elements_and_nodes_for_internal_boundaries(some_file);
43434  }
43435 
43436  //===================================================================
43437  // Fill the boundary elements structures when dealing with
43438  // shared boundaries that overlap internal boundaries
43439  //===================================================================
43440  template<class ELEMENT>
43443  std::ofstream& outfile)
43444  {
43445  // Get the number of processors
43446  const unsigned nproc = this->communicator_pt()->nproc();
43447  // Get the rank of the current processor
43448  unsigned my_rank = this->communicator_pt()->my_rank();
43449 
43450  // Temporal name for the shared boundary overlaps structure
43451  std::map<unsigned, unsigned> shd_bnd_over_int_bnd =
43452  this->Shared_boundary_overlaps_internal_boundary;
43453 
43454  // Register the internal boundary elements that where found to be
43455  // overlapped by shared boundaries
43456  std::set<unsigned> internal_boundary_overlaped;
43457 
43458  // Document the number of elements and nodes associated to the
43459  // boundaries before filling elements and nodes
43460  if (outfile.is_open())
43461  {
43462  const unsigned nbound = this->nboundary();
43463  outfile << "Number of boundaries: " << nbound << "\n\n";
43464  outfile << "Number of elements and nodes associated to each "
43465  << "boundary before\nfilling elements and nodes\n\n";
43466  for (unsigned i = 0; i < nbound; i++)
43467  {
43468  outfile << "Boundary (" << i << ") Elements ("
43469  << this->nboundary_element(i) << ") "
43470  << "Nodes (" << this->nboundary_node(i) << ")\n";
43471  }
43472  }
43473 
43474  // Storage for the shared boundaries in this processor
43475  std::set<unsigned> shared_boundaries_in_this_processor;
43476 
43477  // Get the shared boundaries that this processor has with other
43478  // processors
43479  for (unsigned iproc = 0; iproc < nproc; iproc++)
43480  {
43481  // Work with other processors only
43482  if (iproc != my_rank)
43483  {
43484  // Get the number of boundaries shared with the "iproc"-th processor
43485  unsigned nshared_boundaries_with_iproc =
43486  this->nshared_boundaries(my_rank, iproc);
43487 
43488  if (nshared_boundaries_with_iproc > 0)
43489  {
43490  // Get the boundaries ids shared with "iproc"-th processor
43491  Vector<unsigned> bound_shared_with_iproc;
43492  bound_shared_with_iproc = this->shared_boundaries_ids(my_rank, iproc);
43493 
43494  // Loop over shared boundaries with "iproc"-th processor
43495  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
43496  {
43497  unsigned bnd_id = bound_shared_with_iproc[bs];
43498  shared_boundaries_in_this_processor.insert(bnd_id);
43499  }
43500  }
43501  }
43502  }
43503 
43504  // ------------------------------------------------------------------
43505  // Copy the boundary elements and nodes from the shared boundary to
43506  // the internal boundary it overlaps
43507  // ------------------------------------------------------------------
43508  // Go through the shared boundaries that overlap internal boundaries
43509  for (std::map<unsigned, unsigned>::iterator it =
43510  shd_bnd_over_int_bnd.begin();
43511  it != shd_bnd_over_int_bnd.end();
43512  it++)
43513  {
43514  // The shared boundary id that overlaps with an internal boundary
43515  const unsigned shd_bnd_id = (*it).first;
43516  // The internal boundary overlapped by the shared boundary
43517  const unsigned int_bnd_id = (*it).second;
43518 
43519  // Check if the shared boundary exist in this processor
43520  std::set<unsigned>::iterator it_set =
43521  shared_boundaries_in_this_processor.find(shd_bnd_id);
43522  if (it_set != shared_boundaries_in_this_processor.end())
43523  {
43524  internal_boundary_overlaped.insert(int_bnd_id);
43525 
43526  // -----------------------------------------------------------------
43527  // First work the nodes of the shared boundaries that should be
43528  // added to the internal boundaries
43529  const unsigned nbnd_node_shd_bnd = this->nboundary_node(shd_bnd_id);
43530 
43531  // Document the number of nodes that will be passed to the internal
43532  // boundary from the current shared boundary
43533  if (outfile.is_open())
43534  {
43535  outfile << "\nPass info. from shared (" << shd_bnd_id
43536  << ") to internal (" << int_bnd_id << ")\n";
43537  outfile << "Number of shared boundary nodes: " << nbnd_node_shd_bnd
43538  << "\n";
43539  }
43540 
43541  for (unsigned in = 0; in < nbnd_node_shd_bnd; in++)
43542  {
43543  // Get the boundary node
43544  Node* bnd_node_pt = this->boundary_node_pt(shd_bnd_id, in);
43545  // Add the node to the internal boundary
43546  this->add_boundary_node(int_bnd_id, bnd_node_pt);
43547  }
43548 
43549  // -----------------------------------------------------------------
43550  // Second work the boundary elements
43551  // Get the number of boundary elements that should be copied to the
43552  // internal boundary
43553  const unsigned nbnd_ele_shd_bnd = this->nboundary_element(shd_bnd_id);
43554 
43555  // Document the number of elements that will be passed to the
43556  // internal boundary from the current shared boundary
43557  if (outfile.is_open())
43558  {
43559  outfile << "Number of shared boundary elements: " << nbnd_ele_shd_bnd
43560  << "\n\n";
43561  }
43562 
43563  // Go through the boundary elements in the shrared boundary and add
43564  // them to the boundary elements of the internal boundary
43565  for (unsigned ie = 0; ie < nbnd_ele_shd_bnd; ie++)
43566  {
43567  // Get the boundary element
43568  FiniteElement* bnd_ele_pt = this->boundary_element_pt(shd_bnd_id, ie);
43569  // Add the element to the boundary elements storage of the
43570  // internal boundary
43571  Boundary_element_pt[int_bnd_id].push_back(bnd_ele_pt);
43572  // Get the face index of the boundary
43573  int face_index = this->face_index_at_boundary(shd_bnd_id, ie);
43574  // Add the face index to the storage of the boundary
43575  Face_index_at_boundary[int_bnd_id].push_back(face_index);
43576 
43577  } // for (ie < nbnd_ele_shd_bnd)
43578 
43579  // If there are regions we need to fill the storage for regions too
43580  const unsigned nregions = this->nregion();
43581  if (nregions > 1)
43582  {
43583  for (unsigned ir = 0; ir < nregions; ir++)
43584  {
43585  // Get the region attribute
43586  const unsigned region_id =
43587  static_cast<unsigned>(this->Region_attribute[ir]);
43588 
43589  // Loop over all elements on boundaries in region ir
43590  const unsigned nele_ir =
43591  this->nboundary_element_in_region(shd_bnd_id, region_id);
43592  for (unsigned ier = 0; ier < nele_ir; ier++)
43593  {
43594  // Get the boundary element in current region
43595  FiniteElement* bnd_ele_pt =
43596  this->boundary_element_in_region_pt(shd_bnd_id, region_id, ier);
43597  // Add the boundary element to the internal boundary in the
43598  // region
43599  this->Boundary_region_element_pt[int_bnd_id][region_id].push_back(
43600  bnd_ele_pt);
43601 
43602  // Get the face index of the boundary
43603  int face_index = this->face_index_at_boundary_in_region(
43604  shd_bnd_id, region_id, ier);
43605  // Add the face index to the storage of the boundary region
43606  this->Face_index_region_at_boundary[int_bnd_id][region_id]
43607  .push_back(face_index);
43608 
43609  } // for (ier < nele_ir)
43610 
43611  } // for (ir < nregions)
43612 
43613  } // if (nregions > 1)
43614 
43615  } // if (the shared boundary appears in the current processor)
43616 
43617  } // for (loop over the shared bound that overlap an internal bound)
43618 
43619  // Document the number of elements and nodes associated to the
43620  // boundaries after filling elements and nodes
43621  if (outfile.is_open())
43622  {
43623  const unsigned nbound = this->nboundary();
43624  outfile << "Number of boundaries: " << nbound << "\n\n";
43625  outfile << "Number of elements and nodes associated to each "
43626  << "boundary after\nfilling elements and nodes\n\n";
43627  for (unsigned i = 0; i < nbound; i++)
43628  {
43629  outfile << "Boundary (" << i << ") Elements ("
43630  << this->nboundary_element(i) << ")"
43631  << " Nodes (" << this->nboundary_node(i) << ")\n";
43632  }
43633  }
43634 
43635  // ------------------------------------------------------------------
43636  // Finally, re-setup the boundary coordinates for the new nodes on
43637  // the overlaped internal boundaries
43638  // ------------------------------------------------------------------
43639  for (std::set<unsigned>::iterator it = internal_boundary_overlaped.begin();
43640  it != internal_boundary_overlaped.end();
43641  it++)
43642  {
43643  const unsigned overlaped_internal_bnd_id = (*it);
43644 
43645  // Re-setup boundary coordinates
43646  this->template setup_boundary_coordinates<ELEMENT>(
43647  overlaped_internal_bnd_id);
43648  }
43649  }
43650 
43651 #endif // #ifdef OOMPH_HAS_MPI
43652 
43653  //======================================================================
43654  /// Move the boundary nodes onto the boundary defined by the old mesh
43655  //======================================================================
43656  template<class ELEMENT>
43658  RefineableTriangleMesh<ELEMENT>*& new_mesh_pt, const unsigned& b)
43659  {
43660  // Quick return
43661  if (!Boundary_coordinate_exists[b])
43662  {
43663  return;
43664  }
43665 
43666  // Firstly we set the boundary coordinates of the new nodes
43667  // In case the mapping between the geometric object's intrinsic coordinate
43668  // and the arc-length coordinate is nonlinear. This is only an
43669  // approximation, but it will ensure that the nodes that were input to
43670  // triangle will retain exactly the same boundary coordinates and then
43671  // linear interpolation is used between those values for any newly created
43672  // nodes.
43673 
43674  // We need to get the boundary nodes from the boundary face
43675  // elements since the "multi_domain" methods add nodes to the
43676  // "Boundary_node_pt" structure which have no boundary coordinates
43677  // assigned
43678  std::set<Node*> tmp_boundary_node_pt;
43679  const unsigned nboundary_ele = this->nboundary_element(b);
43680  for (unsigned e = 0; e < nboundary_ele; e++)
43681  {
43682  // Get the boundary bulk element
43683  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
43684 #ifdef OOMPH_HAS_MPI
43685  // Only work with nonhalo elements if the mesh is distributed
43686  if (!bulk_ele_pt->is_halo())
43687  {
43688 #endif
43689  // Get the face index
43690  int face_index = this->face_index_at_boundary(b, e);
43691  // Create the face element
43692  FiniteElement* face_ele_pt =
43693  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
43694 
43695  // Get the number of nodes on the face element
43696  const unsigned nnodes = face_ele_pt->nnode();
43697  for (unsigned i = 0; i < nnodes; i++)
43698  {
43699  // Get the nodes in the face elements
43700  Node* tmp_node_pt = face_ele_pt->node_pt(i);
43701  // Add the nodes to the set of boundary nodes
43702  tmp_boundary_node_pt.insert(tmp_node_pt);
43703  } // for (i < nnodes)
43704 
43705  // Free the memory allocated for the face element
43706  delete face_ele_pt;
43707  face_ele_pt = 0;
43708 #ifdef OOMPH_HAS_MPI
43709  } // if (!bulk_ele_pt->is_halo())
43710 #endif
43711 
43712  } // for (e < nboundary_ele)
43713 
43714  // Get the number of boundary nodes
43715  const unsigned long n_boundary_node = tmp_boundary_node_pt.size();
43716 
43717  // Quick return if there are no nodes
43718  if (n_boundary_node == 0)
43719  {
43720 #ifdef OOMPH_HAS_MPI
43721  // Check if we are working with a distributed mesh
43722  if (!this->is_mesh_distributed())
43723  {
43724 #endif
43725  return;
43726 #ifdef OOMPH_HAS_MPI
43727  }
43728  else // The mesh is distributed !!!
43729  {
43730  // Do not forget to participate in the communication
43731  Mesh* face_mesh_pt = new Mesh();
43732  create_unsorted_face_mesh_representation(b, face_mesh_pt);
43733  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
43734 
43735  // Delete the allocated memory for the geometric object and face mesh
43736  delete mesh_geom_obj_pt;
43737 
43738  // Flush the nodes from the face mesh to make sure we
43739  // don't delete them (the bulk mesh still needs them!)
43740  face_mesh_pt->flush_node_storage();
43741  delete face_mesh_pt;
43742  return;
43743  }
43744 #endif
43745  } // if (n_boundary_node==0)
43746 
43747  // Create a vector of existing boundary nodes with their boundary
43748  // coordinate as the first entry so that we can use standard sort algorithms
43749  Vector<double> node_coord(3);
43750  Vector<double> b_coord(1);
43751 
43752  Vector<Vector<double>> old_boundary_node(n_boundary_node);
43753  unsigned tmp_counter = 0;
43754  for (std::set<Node*>::iterator it_node = tmp_boundary_node_pt.begin();
43755  it_node != tmp_boundary_node_pt.end();
43756  it_node++, tmp_counter++)
43757  {
43758  Node* nod_pt = (*it_node);
43759  nod_pt->get_coordinates_on_boundary(b, b_coord);
43760  node_coord[0] = b_coord[0];
43761  node_coord[1] = nod_pt->x(0);
43762  node_coord[2] = nod_pt->x(1);
43763  old_boundary_node[tmp_counter] = node_coord;
43764  } // for (it_node != tmp_boundary_node_pt.end())
43765 
43766  // Sort the vector
43767  std::sort(old_boundary_node.begin(), old_boundary_node.end());
43768 
43769  // Set up an equivalent ordered vector for the new nodes, based on the
43770  // current coordinate which is the scaled arc-length.
43771  // Also provide storage for the original node index,
43772  // the mapped coordinate and a flag to indicate whether the mapped
43773  // coordinate has been assigned.
43774  // Get the nodes on the boundary but consider to which segment (which
43775  // may appear in a distributed mesh) they belong
43776  Vector<Vector<Node*>> segment_nodes_pt;
43777 
43778 #ifdef OOMPH_HAS_MPI
43779  // Get the number of segments
43780  const unsigned nsegments = new_mesh_pt->nboundary_segment(b);
43781 #else
43782  // The number of segments is one since the boundary is not split
43783  // over multiple processors
43784  const unsigned nsegments = 1;
43785 #endif // #ifdef OOMPH_HAS_MPI
43786 
43787 #ifdef OOMPH_HAS_MPI
43788  // Get the total number of nodes on the boundary
43789  const unsigned n_new_boundary_node = new_mesh_pt->nboundary_segment_node(b);
43790 
43791  // Check if we are working with a distributed mesh
43792  if (this->is_mesh_distributed())
43793  {
43794  // If that is the case we need to ensure that the new mesh has
43795  // nodes too, if that is not the case then return
43796  // Quick return if there are no nodes
43797  if (n_new_boundary_node == 0)
43798  {
43799  // Do not forget to participate in the communication
43800  Mesh* face_mesh_pt = new Mesh();
43801  create_unsorted_face_mesh_representation(b, face_mesh_pt);
43802  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
43803 
43804  // Delete the allocated memory for the geometric object and face mesh
43805  delete mesh_geom_obj_pt;
43806  // Flush the nodes from the face mesh to make sure we
43807  // don't delete them (the bulk mesh still needs them!)
43808  face_mesh_pt->flush_node_storage();
43809  delete face_mesh_pt;
43810  return;
43811  }
43812  }
43813 #endif // #ifdef OOMPH_HAS_MPI
43814 
43815  // Create a vector of boundary nodes that must be moved
43816  Vector<Vector<unsigned>> nodes_to_be_snapped(nsegments);
43817 
43818  // Go through all the segments to assign the snapped zeta coordinates
43819  // for the new nodes
43820  for (unsigned is = 0; is < nsegments; is++)
43821  {
43822 #ifdef OOMPH_HAS_MPI
43823  const unsigned n_new_boundary_segment_node =
43824  new_mesh_pt->nboundary_segment_node(b, is);
43825 #else
43826  const unsigned n_new_boundary_segment_node =
43827  new_mesh_pt->nboundary_node(b);
43828 #endif // #ifdef OOMPH_HAS_MPI
43829 
43830  Vector<Vector<double>> new_boundary_node(n_new_boundary_segment_node);
43831  // There will be six data associated with each node
43832  node_coord.resize(6, 0.0);
43833  for (unsigned n = 0; n < n_new_boundary_segment_node; n++)
43834  {
43835 #ifdef OOMPH_HAS_MPI
43836  Node* nod_pt = new_mesh_pt->boundary_segment_node_pt(b, is, n);
43837 #else
43838  Node* nod_pt = new_mesh_pt->boundary_node_pt(b, n);
43839 #endif // #ifdef OOMPH_HAS_MPI
43840  nod_pt->get_coordinates_on_boundary(b, b_coord);
43841  node_coord[0] = b_coord[0];
43842  node_coord[1] = nod_pt->x(0);
43843  node_coord[2] = nod_pt->x(1);
43844  node_coord[3] = n;
43845  new_boundary_node[n] = node_coord;
43846  } // for (n < n_new_boundary_segment_node)
43847 
43848  // Sort the new boundary nodes based on their arc-length coordinate
43849  std::sort(new_boundary_node.begin(), new_boundary_node.end());
43850 
43851  // We now have two sets of nodes ordered by a coordinate that acts in the
43852  // same direction and has the same limits.
43853 
43854  // Loop over the vector of new nodes and allocate exactly the same
43855  // coordinate as the old nodes at points of coincidence
43856  unsigned old_index = 0;
43857  for (unsigned n = 0; n < n_new_boundary_segment_node; ++n)
43858  {
43859  // Loop over the set of old nodes and if the x and y coordinates
43860  // coincide with the new node copy accross the new boundary coordinate
43861  for (unsigned m = old_index; m < n_boundary_node; ++m)
43862  {
43863  if ((std::fabs(old_boundary_node[m][1] - new_boundary_node[n][1]) <
43864  1.0e-14) &&
43865  (std::fabs(old_boundary_node[m][2] - new_boundary_node[n][2]) <
43866  1.0e-14))
43867  {
43868  // Store the boundary coordinate from the old mesh
43869  new_boundary_node[n][4] = old_boundary_node[m][0];
43870  // Say that it has been stored
43871  new_boundary_node[n][5] = 1.0;
43872  // For efficiency, we can start the iteration from here next
43873  // time round because both vectors are ordered
43874  old_index = m;
43875  break;
43876  }
43877  }
43878  }
43879 
43880  // Check that the end-points have new boundary coordinates allocated
43881 #ifdef PARANOID
43882  if ((new_boundary_node[0][5] == 0.0) ||
43883  (new_boundary_node[n_new_boundary_segment_node - 1][5] == 0.0))
43884  {
43885  std::ostringstream error_stream;
43886  error_stream
43887  << "New boundary coordinates not found for the first and/or last "
43888  << "nodes\n"
43889  << "on the boundary " << b << ". This should not happen because "
43890  << "these\nlimits should have been setup in the constructor\n";
43891  error_stream
43892  << "The distance between the new and old nodes is probably outside\n"
43893  << "our tolerance.\n";
43894  error_stream.precision(20);
43895  error_stream << "Old boundaries: \n";
43896  error_stream << old_boundary_node[0][1] << " "
43897  << old_boundary_node[0][2] << " : "
43898  << old_boundary_node[n_boundary_node - 1][1] << " "
43899  << old_boundary_node[n_boundary_node - 1][2] << "\n";
43900  error_stream << "New boundaries: \n"
43901  << new_boundary_node[0][1] << " "
43902  << new_boundary_node[0][2] << " : "
43903  << new_boundary_node[n_new_boundary_segment_node - 1][1]
43904  << " "
43905  << new_boundary_node[n_new_boundary_segment_node - 1][2]
43906  << "\n";
43907  OomphLibWarning(error_stream.str(),
43908  "RefineableTriangleMesh::snap_nodes_onto_boundary()",
43909  OOMPH_EXCEPTION_LOCATION);
43910  }
43911 #endif
43912 
43913  // This is only true if the boundary is not splitted among the
43914  // processors
43915  if (!this->is_mesh_distributed())
43916  {
43917  // The end points should always be present, so we
43918  // can (and must) always add them in exactly
43919  new_boundary_node[0][4] = new_boundary_node[0][0];
43920 
43921  /// Correct!? Because assigned again below
43922  new_boundary_node[n_new_boundary_segment_node - 1][4] =
43923  new_boundary_node[0][5] = 1.0;
43924 
43925  new_boundary_node[n_new_boundary_segment_node - 1][4] =
43926  new_boundary_node[n_new_boundary_segment_node - 1][0];
43927  new_boundary_node[n_new_boundary_segment_node - 1][5] = 1.0;
43928  }
43929 
43930  // Now loop over the interior nodes again and
43931  // use linear interpolation to fill in any unassigned coordiantes
43932  for (unsigned n = 1; n < n_new_boundary_segment_node - 1; ++n)
43933  {
43934  // If the new boundary coordinate has NOT been allocated
43935  if (new_boundary_node[n][5] == 0.0)
43936  {
43937  // Add its (unsorted) node number to the list
43938  nodes_to_be_snapped[is].push_back(
43939  static_cast<unsigned>(new_boundary_node[n][3]));
43940 
43941  // We assume that the previous nodal value has been assigned
43942  // and read out the old and new boundary coordinates
43943  double zeta_old_low = new_boundary_node[n - 1][0];
43944  double zeta_new_low = new_boundary_node[n - 1][4];
43945 
43946  // Loop over the nodes above the current node until
43947  // we find the next one that has been allocated
43948  for (unsigned m = n + 1; m < n_new_boundary_segment_node; ++m)
43949  {
43950  if (new_boundary_node[m][5] == 1.0)
43951  {
43952  // Read out the old boundary coordinate
43953  double zeta_old_high = new_boundary_node[m][0];
43954  double zeta_new_high = new_boundary_node[m][4];
43955  // Use linear interpolation to assign the new boundary coordinate
43956  double frac = (new_boundary_node[n][0] - zeta_old_low) /
43957  (zeta_old_high - zeta_old_low);
43958  new_boundary_node[n][4] =
43959  zeta_new_low + frac * (zeta_new_high - zeta_new_low);
43960  new_boundary_node[n][5] = 1.0;
43961  break;
43962  }
43963  }
43964  }
43965  }
43966 
43967  // Loop over all the nodes and set the new boundary coordinate
43968  for (unsigned n = 0; n < n_new_boundary_segment_node; ++n)
43969  {
43970  if (new_boundary_node[n][5] == 0)
43971  {
43972  throw OomphLibError(
43973  "New boundary coordinate not assigned\n",
43974  "RefineableTriangleMesh::snap_nodes_onto_boundary()",
43975  OOMPH_EXCEPTION_LOCATION);
43976  }
43977 
43978 #ifdef OOMPH_HAS_MPI
43979  // get the old coordinate
43980  new_mesh_pt
43982  b, is, static_cast<unsigned>(new_boundary_node[n][3]))
43983  ->get_coordinates_on_boundary(b, b_coord);
43984  // Set the new coordinate
43985  b_coord[0] = new_boundary_node[n][4];
43986  new_mesh_pt
43988  b, is, static_cast<unsigned>(new_boundary_node[n][3]))
43989  ->set_coordinates_on_boundary(b, b_coord);
43990 #else
43991  // get the old coordinate
43992  new_mesh_pt
43993  ->boundary_node_pt(b, static_cast<unsigned>(new_boundary_node[n][3]))
43994  ->get_coordinates_on_boundary(b, b_coord);
43995  // Set the new coordinate
43996  b_coord[0] = new_boundary_node[n][4];
43997  new_mesh_pt
43998  ->boundary_node_pt(b, static_cast<unsigned>(new_boundary_node[n][3]))
43999  ->set_coordinates_on_boundary(b, b_coord);
44000 #endif // #ifdef OOMPH_HAS_MPI
44001  }
44002 
44003  } // for (is < nsegments)
44004 
44005  Mesh* face_mesh_pt = new Mesh();
44006  create_unsorted_face_mesh_representation(b, face_mesh_pt);
44007 
44008  // Now that the coordinates have been set up we can do the snapping
44009  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
44010 
44011  // Now assign the new nodes positions based on the old meshes
44012  // potentially curvilinear boundary (its geom object incarnation)
44013  Vector<double> new_x(2);
44014 
44015  // Loop over the nodes that need to be snapped
44016  for (unsigned is = 0; is < nsegments; is++)
44017  {
44018  const unsigned nnodes_to_snap = nodes_to_be_snapped[is].size();
44019 
44020  for (unsigned in = 0; in < nnodes_to_snap; in++)
44021  {
44022  // Read out the boundary node number
44023  unsigned n = nodes_to_be_snapped[is][in];
44024 #ifdef OOMPH_HAS_MPI
44025  // Get the boundary coordinate of all new nodes
44026  Node* const nod_pt = new_mesh_pt->boundary_segment_node_pt(b, is, n);
44027 #else
44028  // Get the boundary coordinate of all new nodes
44029  Node* const nod_pt = new_mesh_pt->boundary_node_pt(b, n);
44030 #endif // #ifdef OOMPH_HAS_MPI
44031 
44032  nod_pt->get_coordinates_on_boundary(b, b_coord);
44033  // Let's find boundary coordinates of the new node
44034  mesh_geom_obj_pt->position(b_coord, new_x);
44035 
44036  // Now snap to the boundary
44037  for (unsigned i = 0; i < 2; i++)
44038  {
44039  nod_pt->x(i) = new_x[i];
44040  }
44041  }
44042  }
44043 
44044  // Delete the allocated memory for the geometric object and face mesh
44045  delete mesh_geom_obj_pt;
44046  // Flush the nodes from the face mesh to make sure we
44047  // don't delete them (the bulk mesh still needs them!)
44048  face_mesh_pt->flush_node_storage();
44049  delete face_mesh_pt;
44050 
44051  // Fix up the elements adjacent to the boundary
44052 
44053  // Dummy six node element for sorting out bubble node for
44054  // seven node enriched quadratic triangles
44055  TElement<2, 3> dummy_six_node_element;
44056  for (unsigned j = 0; j < 6; j++)
44057  {
44058  dummy_six_node_element.construct_node(j);
44059  }
44060 
44061  // This should definitely become a triangular element member function
44062  // Loop over elements
44063  unsigned n_bound_el = new_mesh_pt->nboundary_element(b);
44064  for (unsigned e = 0; e < n_bound_el; e++)
44065  {
44066  FiniteElement* el_pt = new_mesh_pt->boundary_element_pt(b, e);
44067 
44068  // Deal with different numbers of nodes separately
44069  unsigned nnod = el_pt->nnode();
44070 
44071  // #ifdef PARANOID
44072  // // Flag to indicate if we successully classified/dealt with the
44073  // element bool success=false;
44074  // #endif
44075 
44076  // Simplex element: Nothing to be done other than error checking
44077  if (nnod == 3)
44078  {
44079 #ifdef PARANOID
44080  // Try to cast to a simplex element
44081  TElement<2, 2>* t_el_pt = dynamic_cast<TElement<2, 2>*>(el_pt);
44082  if (t_el_pt == 0)
44083  {
44084  throw OomphLibError(
44085  "Have a three-noded element that's not a TElement<2,2>",
44086  OOMPH_CURRENT_FUNCTION,
44087  OOMPH_EXCEPTION_LOCATION);
44088  }
44089  // If I get there I must not have thrown :)
44090  // success=true;
44091 #endif
44092  }
44093  // Quadratic element (or enriched quadratic)
44094 
44095  else if ((nnod == 6) || (nnod == 7))
44096  {
44097 #ifdef PARANOID
44098  // Try to cast to a quadratic element
44099  TElement<2, 3>* t_el_pt = dynamic_cast<TElement<2, 3>*>(el_pt);
44100  if (t_el_pt == 0)
44101  {
44102  if (nnod == 6)
44103  {
44104  throw OomphLibError(
44105  "Have a six-noded element that's not a TElement<2,3>",
44106  OOMPH_CURRENT_FUNCTION,
44107  OOMPH_EXCEPTION_LOCATION);
44108  }
44109  else
44110  {
44111  throw OomphLibError(
44112  "Have a seven-noded element that's not a TElement<2,3>",
44113  OOMPH_CURRENT_FUNCTION,
44114  OOMPH_EXCEPTION_LOCATION);
44115  }
44116  }
44117  // If I get there I must not have thrown :)
44118  // success=true;
44119 #endif
44120  // Deal with six noded stuff for all (normal and enriched) elements
44121 
44122  /// ----------------------------------------------------------------
44123  /// Repositioning of mid-side nodes
44124  /// ----------------------------------------------------------------
44125 
44126  // Side between 0 and 1
44127  if (el_pt->node_pt(3)->is_on_boundary(b))
44128  {
44129  // Make sure that the node I'm about to move is NOT on
44130  // a boundary
44131  if (!el_pt->node_pt(5)->is_on_boundary())
44132  {
44133  // Reset the internal nodes
44134  for (unsigned i = 0; i < 2; i++)
44135  {
44136  el_pt->node_pt(5)->x(i) =
44137  0.5 * (el_pt->node_pt(0)->x(i) + el_pt->node_pt(2)->x(i));
44138  }
44139  }
44140  // Make sure that the node I'm about to move is NOT on
44141  // a boundary
44142  if (!el_pt->node_pt(4)->is_on_boundary())
44143  {
44144  // Reset the internal nodes
44145  for (unsigned i = 0; i < 2; i++)
44146  {
44147  el_pt->node_pt(4)->x(i) =
44148  0.5 * (el_pt->node_pt(1)->x(i) + el_pt->node_pt(2)->x(i));
44149  }
44150  }
44151  }
44152 
44153  // Side between 1 and 2
44154  if (el_pt->node_pt(4)->is_on_boundary(b))
44155  {
44156  // Make sure that the node I'm about to move is NOT on
44157  // a boundary
44158  if (!el_pt->node_pt(5)->is_on_boundary())
44159  {
44160  // Reset the internal nodes
44161  for (unsigned i = 0; i < 2; i++)
44162  {
44163  el_pt->node_pt(5)->x(i) =
44164  0.5 * (el_pt->node_pt(0)->x(i) + el_pt->node_pt(2)->x(i));
44165  }
44166  }
44167  // Make sure that the node I'm about to move is NOT on
44168  // a boundary
44169  if (!el_pt->node_pt(3)->is_on_boundary())
44170  {
44171  // Reset the internal nodes
44172  for (unsigned i = 0; i < 2; i++)
44173  {
44174  el_pt->node_pt(3)->x(i) =
44175  0.5 * (el_pt->node_pt(0)->x(i) + el_pt->node_pt(1)->x(i));
44176  }
44177  }
44178  }
44179 
44180  // Side between 0 and 2
44181  if (el_pt->node_pt(5)->is_on_boundary(b))
44182  {
44183  // Make sure that the node I'm about to move is NOT on
44184  // a boundary
44185  if (!el_pt->node_pt(4)->is_on_boundary())
44186  {
44187  // Reset the internal nodes
44188  for (unsigned i = 0; i < 2; i++)
44189  {
44190  el_pt->node_pt(4)->x(i) =
44191  0.5 * (el_pt->node_pt(1)->x(i) + el_pt->node_pt(2)->x(i));
44192  }
44193  }
44194  // Make sure that the node I'm about to move is NOT on
44195  // a boundary
44196  if (!el_pt->node_pt(3)->is_on_boundary())
44197  {
44198  // Reset the internal nodes
44199  for (unsigned i = 0; i < 2; i++)
44200  {
44201  el_pt->node_pt(3)->x(i) =
44202  0.5 * (el_pt->node_pt(0)->x(i) + el_pt->node_pt(1)->x(i));
44203  }
44204  }
44205  }
44206 
44207  // If it's seven noded it's likely to be an enriched one: Deal with
44208  // the central (bubble) node
44209  if (nnod == 7)
44210  {
44211  // Try to cast to an enriched quadratic element
44212  TBubbleEnrichedElement<2, 3>* t_el_pt =
44213  dynamic_cast<TBubbleEnrichedElement<2, 3>*>(el_pt);
44214  if (t_el_pt == 0)
44215  {
44216  throw OomphLibError("Have seven-noded element that's not a "
44217  "TBubbleEnrichedElement<2,3>",
44218  OOMPH_CURRENT_FUNCTION,
44219  OOMPH_EXCEPTION_LOCATION);
44220  }
44221 
44222  // Assign the new non-bubble coordinates to the six noded dummy
44223  // element
44224  for (unsigned j = 0; j < 6; j++)
44225  {
44226  for (unsigned i = 0; i < 2; i++)
44227  {
44228  dummy_six_node_element.node_pt(j)->x(i) = el_pt->node_pt(j)->x(i);
44229  }
44230  }
44231 
44232  // Local coordinate of enriched node
44233  unsigned j_enriched = 6;
44234  Vector<double> s(2);
44235  el_pt->local_coordinate_of_node(j_enriched, s);
44236 
44237  // Get its position from non-enriched element
44238  Vector<double> x(2);
44239  dummy_six_node_element.interpolated_x(s, x);
44240  el_pt->node_pt(j_enriched)->x(0) = x[0];
44241  el_pt->node_pt(j_enriched)->x(1) = x[1];
44242  }
44243  }
44244  // Any other case cannot be dealt with at the moment
44245 
44246  else
44247  {
44248  std::ostringstream error_stream;
44249  error_stream << "Cannot deal with this particular " << nnod
44250  << "-noded element yet.\n"
44251  << "Please implement this yourself.\n";
44252  throw OomphLibError(
44253  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
44254  }
44255  }
44256 
44257  // Cleanup
44258  for (unsigned j = 0; j < 6; j++)
44259  {
44260  delete dummy_six_node_element.node_pt(j);
44261  }
44262  }
44263 
44264 
44265 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB
44266 
44267 } // namespace oomph
44268 
44269 #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