triangle_mesh.template.h
Go to the documentation of this file.
1 //LIC// ====================================================================
2 //LIC// This file forms part of oomph-lib, the object-oriented,
3 //LIC// multi-physics finite-element library, available
4 //LIC// at http://www.oomph-lib.org.
5 //LIC//
6 //LIC// Version 1.0; svn revision $LastChangedRevision$
7 //LIC//
8 //LIC// $LastChangedDate$
9 //LIC//
10 //LIC// Copyright (C) 2006-2016 Matthias Heil and Andrew Hazel
11 //LIC//
12 //LIC// This library is free software; you can redistribute it and/or
13 //LIC// modify it under the terms of the GNU Lesser General Public
14 //LIC// License as published by the Free Software Foundation; either
15 //LIC// version 2.1 of the License, or (at your option) any later version.
16 //LIC//
17 //LIC// This library is distributed in the hope that it will be useful,
18 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 //LIC// Lesser General Public License for more details.
21 //LIC//
22 //LIC// You should have received a copy of the GNU Lesser General Public
23 //LIC// License along with this library; if not, write to the Free Software
24 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 //LIC// 02110-1301 USA.
26 //LIC//
27 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
28 //LIC//
29 //LIC//====================================================================
30 #ifndef OOMPH_TRIANGLE_MESH_HEADER
31 #define OOMPH_TRIANGLE_MESH_HEADER
32 // Config header generated by autoconfig
33 #ifdef HAVE_CONFIG_H
34 #include <oomph-lib-config.h>
35 #endif
36 
37 #ifdef OOMPH_HAS_MPI
38 
39 // MPI headers
40 #include <mpi.h>
41 #endif
42 
43 //Standards
44 #include<float.h>
45 #include <iostream>
46 #include <fstream>
47 #include <string.h>
48 #include <iomanip>
49 
50 #include "../generic/problem.h"
51 #include "../generic/triangle_scaffold_mesh.h"
52 #include "../generic/triangle_mesh.h"
53 #include "../generic/refineable_mesh.h"
54 #include "../rigid_body/immersed_rigid_body_elements.h"
55 
56 namespace oomph
57 {
58 
59 #ifdef OOMPH_HAS_TRIANGLE_LIB
60 
61 // Interface to triangulate function
62  extern "C" {
63  void triangulate(char *triswitches, struct oomph::TriangulateIO *in,
64  struct oomph::TriangulateIO *out,
65  struct oomph::TriangulateIO *vorout);
66  }
67 
68 #endif
69 
70 
71 
72 
73 ////////////////////////////////////////////////////////////////////////
74 ////////////////////////////////////////////////////////////////////////
75 ////////////////////////////////////////////////////////////////////////
76 ////////////////////////////////////////////////////////////////////////
77 ////////////////////////////////////////////////////////////////////////
78 
79 
80 
81 
82 //=========================================================================
83 /// \short Helper object for dealing with the parameters used for the
84 /// TriangleMesh objects
85 //=========================================================================
87  {
88 
89  public:
90 
91  /// Constructor: Only takes the outer boundary, all the other parameters
92  /// are stated with the specific parameters
93  TriangleMeshParameters(Vector<TriangleMeshClosedCurve *>&outer_boundary_pt)
94  : Outer_boundary_pt(outer_boundary_pt),
95  Element_area(0.2),
96  Use_attributes(false),
97  Boundary_refinement(true),
100  Comm_pt(0)
101  { }
102 
103  /// Constructor: Only takes the outer boundary, all the other parameters
104  /// are stated with the specific parameters
105  TriangleMeshParameters(TriangleMeshClosedCurve *outer_boundary_pt)
106  : Element_area(0.2),
107  Use_attributes(false),
108  Boundary_refinement(true),
111  Comm_pt(0)
112  {
113  Outer_boundary_pt.resize(1);
115  }
116 
117  /// Constructor: Takes nothing and initializes the other parameters to
118  /// the default ones
120  : Element_area(0.2),
121  Use_attributes(false),
122  Boundary_refinement(true),
125  Comm_pt(0)
126  { }
127 
128  /// Empty destructor
130 
131  /// Helper function for getting the outer boundary
132  Vector<TriangleMeshClosedCurve *> outer_boundary_pt() const
133  {return Outer_boundary_pt;}
134 
135  /// Helper function for getting access to the outer boundary
136  Vector<TriangleMeshClosedCurve*> &outer_boundary_pt()
137  {return Outer_boundary_pt;}
138 
139  /// Helper function for getting the i-th outer boundary
140  TriangleMeshClosedCurve *outer_boundary_pt(const unsigned &i) const
141  {return Outer_boundary_pt[i];}
142 
143  /// Helper function for getting access to the i-th outer boundary
144  TriangleMeshClosedCurve* &outer_boundary_pt(const unsigned &i)
145  {return Outer_boundary_pt[i];}
146 
147  /// Helper function for getting the internal closed boundaries
148  Vector<TriangleMeshClosedCurve*> internal_closed_curve_pt() const
149  {return Internal_closed_curve_pt;}
150 
151  /// \short Helper function for getting access to the internal
152  /// closed boundaries
153  Vector<TriangleMeshClosedCurve*> &internal_closed_curve_pt()
154  {return Internal_closed_curve_pt;}
155 
156  /// Helper function for getting the internal open boundaries
157  Vector<TriangleMeshOpenCurve*> internal_open_curves_pt() const
158  {return Internal_open_curves_pt;}
159 
160  /// \short Helper function for getting access to the internal
161  /// open boundaries
162  Vector<TriangleMeshOpenCurve*> &internal_open_curves_pt()
163  {return Internal_open_curves_pt;}
164 
165  /// Helper function for getting the element area
166  double element_area() const {return Element_area;}
167 
168  /// Helper function for getting access to the element area
169  double &element_area(){return Element_area;}
170 
171  /// Helper function for getting the extra holes
172  Vector<Vector<double> > extra_holes_coordinates() const
173  {return Extra_holes_coordinates;}
174 
175  /// Helper function for getting access to the extra holes
176  Vector<Vector<double> > &extra_holes_coordinates()
177  {return Extra_holes_coordinates;}
178 
179  /// Helper function for getting the extra regions
180  void add_region_coordinates(const unsigned &i,
181  Vector<double> &region_coordinates)
182  {
183  // Verify if not using the default region number (zero)
184  if (i == 0)
185  {
186  std::ostringstream error_message;
187  error_message << "Please use another region id different from zero.\n"
188  << "It is internally used as the default region number.\n";
189  throw OomphLibError(error_message.str(),
190  OOMPH_CURRENT_FUNCTION,
191  OOMPH_EXCEPTION_LOCATION);
192  }
193 
194  // First check if the region with the specified id does not already exist
195  std::map<unsigned, Vector<double> >::iterator it;
196  it = Regions_coordinates.find(i);
197 
198  // If it is already a region defined with that id throw an error
199  if (it != Regions_coordinates.end())
200  {
201  std::ostringstream error_message;
202  error_message << "The region id ("<<i<<") that you are using for"
203  << "defining\n"
204  << "your region is already in use. Use another\n"
205  << "region id and verify that you are not re-using\n"
206  <<" previously defined regions ids\n"<<std::endl;
207  OomphLibWarning(error_message.str(),
208  OOMPH_CURRENT_FUNCTION,
209  OOMPH_EXCEPTION_LOCATION);
210  }
211 
212  // If it does not exist then create the map
213  Regions_coordinates[i] = region_coordinates;
214 
215  // Automatically set the using of attributes to enable
217  }
218 
219  /// Helper function for getting access to the regions coordinates
220  std::map<unsigned, Vector<double> >&regions_coordinates()
221  {return Regions_coordinates;}
222 
223  /// Helper function to specify target area for region
224  void set_target_area_for_region(const unsigned &i, const double& area)
225  {
226  Regions_areas[i] = area;
227  }
228 
229  /// Helper function for getting access to the region's target areas
230  std::map<unsigned, double >&target_area_for_region()
231  {return Regions_areas;}
232 
233  /// \short Helper function for enabling the use of attributes
235 
236  /// \short Helper function for disabling the use of attributes
238 
239  /// \short Helper function for getting the status of use_attributes
240  /// variable
241  bool is_use_attributes() const {return Use_attributes;}
242 
243  /// \short Helper function for enabling the use of boundary refinement
245 
246  /// Boolean to indicate if Mesh has been distributed
247  bool is_mesh_distributed() const {return (Comm_pt!=0);}
248 
249  /// Function to set communicator (mesh is then assumed to be distributed)
250  void set_communicator_pt(OomphCommunicator* comm_pt)
251  {Comm_pt=comm_pt;}
252 
253  /// Read-only access fct to communicator (Null if mesh is not distributed)
254  OomphCommunicator* communicator_pt() const
255  {return Comm_pt;}
256 
257  /// \short Helper function for disabling the use of boundary refinement
259 
260  /// \short Helper function for getting the status of boundary refinement
262 
263  /// \short Helper function for enabling the use of boundary refinement
266 
267  /// \short Helper function for disabling the use of boundary refinement
270 
271  /// \short Helper function for getting the status of boundary refinement
274 
275  /// Enables the creation of points (by Triangle) on the outer and
276  /// internal boundaries
278  {
280  }
281 
282  /// Disables the creation of points (by Triangle) on the outer and
283  /// internal boundaries
285  {
287  }
288 
289  /// Returns the status of the variable
290  /// Allow_automatic_creation_of_vertices_on_boundaries
292  {
294  }
295 
296  protected:
297 
298  /// The outer boundary
299  Vector<TriangleMeshClosedCurve*> Outer_boundary_pt;
300 
301  /// Internal closed boundaries
302  Vector<TriangleMeshClosedCurve*> Internal_closed_curve_pt;
303 
304  /// Internal boundaries
305  Vector<TriangleMeshOpenCurve*> Internal_open_curves_pt;
306 
307  /// The element are when calling triangulate external routine
308  double Element_area;
309 
310  /// Store the coordinates for defining extra holes
311  Vector<Vector<double> > Extra_holes_coordinates;
312 
313  /// \short Store the coordinates for defining extra regions
314  /// The key on the map is the region id
315  std::map<unsigned, Vector<double> > Regions_coordinates;
316 
317  /// \short Target areas for regions; defaults to 0.0 which (luckily)
318  /// implies "no specific target area" for triangle!
319  std::map<unsigned, double> Regions_areas;
320 
321  /// Define the use of attributes (regions)
323 
324  /// Do not allow refinement of nodes on the boundary
326 
327  /// Do not allow refinement of nodes on the internal boundary
329 
330  /// Allows automatic creation of vertices along boundaries by
331  /// Triangle
333 
334  /// Pointer to communicator -- set to NULL if mesh is not distributed
335  /// Required to pass it to new distributed meshes created at the
336  /// adaptation stage
337  OomphCommunicator* Comm_pt;
338 
339  };
340 
341 
342 ////////////////////////////////////////////////////////////////////////
343 ////////////////////////////////////////////////////////////////////////
344 ////////////////////////////////////////////////////////////////////////
345 ////////////////////////////////////////////////////////////////////////
346 ////////////////////////////////////////////////////////////////////////
347 
348 
349 //============start_of_triangle_class===================================
350 /// Triangle mesh build with the help of the scaffold mesh coming
351 /// from the triangle mesh generator Triangle.
352 /// http://www.cs.cmu.edu/~quake/triangle.html
353 //======================================================================
354  template<class ELEMENT>
355  class TriangleMesh : public virtual TriangleMeshBase
356  {
357  public:
358 
359  /// \short Empty constructor
361  {
362 #ifdef OOMPH_HAS_TRIANGLE_LIB
363  // Using this constructor no Triangulateio object is built
364  Triangulateio_exists=false;
365  // By default allow the automatic creation of vertices along the
366  // boundaries by Triangle
368 #ifdef OOMPH_HAS_MPI
369  // Initialize the flag to indicate this is the first time to
370  // compute the holes left by the halo elements
371  First_time_compute_holes_left_by_halo_elements = true;
372 #endif // #ifdef OOMPH_HAS_MPI
373 
374 #endif
375 
376  // Mesh can only be built with 2D Telements.
377  MeshChecker::assert_geometric_element<TElementGeometricBase,ELEMENT>(2);
378  }
379 
380  /// \short Constructor with the input files
381  TriangleMesh(const std::string& node_file_name,
382  const std::string& element_file_name,
383  const std::string& poly_file_name,
384  TimeStepper* time_stepper_pt=
385  &Mesh::Default_TimeStepper,
386  const bool &allow_automatic_creation_of_vertices_on_boundaries=true)
387  {
388  // Mesh can only be built with 2D Telements.
389  MeshChecker::assert_geometric_element<TElementGeometricBase,ELEMENT>(2);
390 
391  // Initialize the value for allowing creation of points on boundaries
393  allow_automatic_creation_of_vertices_on_boundaries;
394 
395 #ifdef OOMPH_HAS_MPI
396  // Initialize the flag to indicate this is the first time to
397  // compute the holes left by the halo elements
398  First_time_compute_holes_left_by_halo_elements=true;
399 #endif // #ifdef OOMPH_HAS_MPI
400 
401  // Store Timestepper used to build elements
402  Time_stepper_pt=time_stepper_pt;
403 
404  // Check if we should use attributes. This is set to true if the .poly file
405  // specifies regions
406  bool should_use_attributes=false;
407 
408 #ifdef OOMPH_HAS_TRIANGLE_LIB
409  // Using this constructor build the triangulatio
410  TriangleHelper::create_triangulateio_from_polyfiles(node_file_name,
411  element_file_name,
412  poly_file_name,
413  Triangulateio,
414  should_use_attributes);
415 
416  // Record that the triangulateio object has been created
417  Triangulateio_exists=true;
418 #endif
419 
420  // Store the attributes
421  Use_attributes=should_use_attributes;
422 
423  // Build scaffold
424  this->Tmp_mesh_pt= new
425  TriangleScaffoldMesh(node_file_name,
426  element_file_name,
427  poly_file_name);
428 
429  // Convert mesh from scaffold to actual mesh
430  build_from_scaffold(time_stepper_pt,should_use_attributes);
431 
432  // kill the scaffold
433  delete this->Tmp_mesh_pt;
434  this->Tmp_mesh_pt=0;
435 
436  // Setup boundary coordinates for boundaries
437  unsigned nb=nboundary();
438  for (unsigned b=0;b<nb;b++)
439  {
440  this->template setup_boundary_coordinates<ELEMENT>(b);
441  }
442  }
443 
444  protected:
445 
446 #ifdef OOMPH_HAS_TRIANGLE_LIB
447 
448  public:
449 
450  /// \short Build mesh, based on the specifications on
451  /// TriangleMeshParameters
452  TriangleMesh(TriangleMeshParameters &triangle_mesh_parameters,
453  TimeStepper* time_stepper_pt=&Mesh::Default_TimeStepper)
454  {
455 
456  // Store the region target areas
457  Regions_areas=triangle_mesh_parameters.target_area_for_region();
458 
459  // Mesh can only be built with 2D Telements.
460  MeshChecker::assert_geometric_element<TElementGeometricBase,ELEMENT>(2);
461 
462  // Initialize the value for allowing creation of points on boundaries
465 
466  // Store Timestepper used to build elements
467  Time_stepper_pt=time_stepper_pt;
468 
469 #ifdef OOMPH_HAS_MPI
470  // Initialize the flag to indicate this is the first time to
471  // compute the holes left by the halo elements
472  First_time_compute_holes_left_by_halo_elements = true;
473 #endif // #ifdef OOMPH_HAS_MPI
474 
475  // ********************************************************************
476  // First part - Get polylines representations
477  // ********************************************************************
478 
479  // Create the polyline representation of all the boundaries and
480  // then create the mesh by calling to "generic_constructor()"
481 
482  // Initialise highest boundary id
483  unsigned max_boundary_id = 0;
484 
485  // *****************************************************************
486  // Part 1.1 - Outer boundary
487  // *****************************************************************
488  // Get the representation of the outer boundaries from the
489  // TriangleMeshParameters object
490  Vector<TriangleMeshClosedCurve *> outer_boundary_pt =
491  triangle_mesh_parameters.outer_boundary_pt();
492 
493 #ifdef PARANOID
494  // Verify that the outer_boundary_object_pt has been set
495  if (outer_boundary_pt.size()==0)
496  {
497  std::stringstream error_message;
498  error_message
499  << "There are no outer boundaries defined.\n"
500  << "Verify that you have specified the outer boundaries in the\n"
501  << "Triangle_mesh_parameter object\n\n";
502  throw OomphLibError(error_message.str(),
503  OOMPH_CURRENT_FUNCTION,
504  OOMPH_EXCEPTION_LOCATION);
505  } // if (outer_boundary_pt!=0)
506 #endif
507 
508  // Find the number of outer closed curves
509  unsigned n_outer_boundaries = outer_boundary_pt.size();
510 
511  // Create the storage for the polygons that define the outer
512  // boundaries
513  Vector<TriangleMeshPolygon*> outer_boundary_polygon_pt(n_outer_boundaries);
514 
515  // Loop over the number of outer boundaries
516  for(unsigned i=0;i<n_outer_boundaries;++i)
517  {
518  // Get the polygon representation and compute the max boundary_id on
519  // each outer polygon. Does nothing (i.e. just returns a pointer to
520  // the outer boundary that was input) if the outer boundary is
521  // already a polygon
522  outer_boundary_polygon_pt[i] =
523  closed_curve_to_polygon_helper(outer_boundary_pt[i], max_boundary_id);
524  }
525 
526  // *****************************************************************
527  // Part 1.2 - Internal closed boundaries (possible holes)
528  // *****************************************************************
529  // Get the representation of the internal closed boundaries from the
530  // TriangleMeshParameters object
531  Vector<TriangleMeshClosedCurve *> internal_closed_curve_pt =
532  triangle_mesh_parameters.internal_closed_curve_pt();
533 
534  // Find the number of internal closed curves
535  unsigned n_internal_closed_curves = internal_closed_curve_pt.size();
536 
537  // Create the storage for the polygons that define the internal closed
538  // boundaries (again nothing happens (as above) if an internal closed
539  // curve is already a polygon)
540  Vector<TriangleMeshPolygon*> internal_polygon_pt(n_internal_closed_curves);
541 
542  // Loop over the number of internal closed curves
543  for(unsigned i=0;i<n_internal_closed_curves;++i)
544  {
545  // Get the polygon representation and compute the max boundary_id on
546  // each internal polygon
547  internal_polygon_pt[i] =
548  closed_curve_to_polygon_helper(
549  internal_closed_curve_pt[i], max_boundary_id);
550  }
551 
552  // *****************************************************************
553  // Part 1.3 - Internal open boundaries
554  // *****************************************************************
555  // Get the representation of open boundaries from the
556  // TriangleMeshParameteres object
557  Vector<TriangleMeshOpenCurve*> internal_open_curve_pt =
558  triangle_mesh_parameters.internal_open_curves_pt();
559 
560  //Find the number of internal open curves
561  unsigned n_internal_open_curves = internal_open_curve_pt.size();
562 
563  // Create the storage for the polylines that define the open boundaries
564  Vector<TriangleMeshOpenCurve*> internal_open_curve_poly_pt(
565  n_internal_open_curves);
566 
567  // Loop over the number of internal open curves
568  for (unsigned i = 0; i < n_internal_open_curves; i++)
569  {
570  // Get the open polyline representation and compute the max boundary_id
571  // on each open polyline (again, nothing happens if there are curve
572  // sections on the current internal open curve)
573  internal_open_curve_poly_pt[i] =
574  create_open_curve_with_polyline_helper(
575  internal_open_curve_pt[i], max_boundary_id);
576  }
577 
578  // ********************************************************************
579  // Second part - Get associated geom objects and coordinate limits
580  // ********************************************************************
581 
582  // ***************************************************************
583  // Part 2.1 Outer boundary
584  // ***************************************************************
585  for (unsigned i = 0; i < n_outer_boundaries; i++)
586  {
587  set_geom_objects_and_coordinate_limits_for_close_curve(
588  outer_boundary_pt[i]);
589  }
590 
591  // ***************************************************************
592  // Part 2.2 - Internal closed boundaries (possible holes)
593  // ***************************************************************
594  for (unsigned i = 0; i < n_internal_closed_curves; i++)
595  {
596  set_geom_objects_and_coordinate_limits_for_close_curve(
597  internal_closed_curve_pt[i]);
598  }
599 
600  // ********************************************************************
601  // Part 2.3 - Internal open boundaries
602  // ********************************************************************
603  for (unsigned i = 0; i < n_internal_open_curves; i++)
604  {
605  set_geom_objects_and_coordinate_limits_for_open_curve(
606  internal_open_curve_pt[i]);
607  }
608 
609  // ********************************************************************
610  // Third part - Creates the TriangulateIO object by calling the
611  // "generic_constructor()" function
612  // ********************************************************************
613  // Get all the other parameters from the TriangleMeshParameters object
614  // The maximum element area
615  const double element_area =
616  triangle_mesh_parameters.element_area();
617 
618  // The holes coordinates
619  Vector<Vector<double> > extra_holes_coordinates =
620  triangle_mesh_parameters.extra_holes_coordinates();
621 
622  // The regions coordinates
623  std::map<unsigned, Vector<double> > regions =
624  triangle_mesh_parameters.regions_coordinates();
625 
626  // If we use regions then we use attributes
627  const bool use_attributes = triangle_mesh_parameters.is_use_attributes();
628 
629  const bool refine_boundary =
630  triangle_mesh_parameters.is_boundary_refinement_allowed();
631 
632  const bool refine_internal_boundary =
633  triangle_mesh_parameters.is_internal_boundary_refinement_allowed();
634 
635  if(!refine_internal_boundary && refine_boundary)
636  {
637  std::ostringstream error_stream;
638  error_stream
639  <<
640  "You have specified that Triangle may refine the outer boundary, but\n"
641  <<
642  "not internal boundaries. Triangle does not support this combination.\n"
643  <<
644  "If you do not want Triangle to refine internal boundaries, it can't\n"
645  <<
646  "refine outer boundaries either!\n"
647  << "Please either disable all boundary refinement\n"
648  << "(call TriangleMeshParameters::disable_boundary_refinement()\n"
649  << "or enable internal boundary refinement (the default)\n";
650 
651  throw OomphLibError(error_stream.str().c_str(),
652  OOMPH_CURRENT_FUNCTION,
653  OOMPH_EXCEPTION_LOCATION);
654  }
655 
656  this->generic_constructor(outer_boundary_polygon_pt,
657  internal_polygon_pt,
658  internal_open_curve_poly_pt,
659  element_area,
660  extra_holes_coordinates,
661  regions,
662  triangle_mesh_parameters.target_area_for_region(),
663  time_stepper_pt,
664  use_attributes,
665  refine_boundary,
666  refine_internal_boundary);
667 
668  // Setup boundary coordinates for boundaries
669  unsigned nb=nboundary();
670 
671 #ifdef OOMPH_HAS_MPI
672  // Before calling setup boundary coordinates check if the mesh is
673  // marked as distrbuted
674  if (triangle_mesh_parameters.is_mesh_distributed())
675  {
676  // Set the mesh as distributed by passing the communicator
677  this->set_communicator_pt(triangle_mesh_parameters.communicator_pt());
678  }
679 #endif
680 
681  for (unsigned b=0;b<nb;b++)
682  {
683  this->template setup_boundary_coordinates<ELEMENT>(b);
684  }
685 
686  // Snap it!
687  this->snap_nodes_onto_geometric_objects();
688  }
689 
690  /// \short Build mesh from poly file, with specified target
691  /// area for all elements.
692  TriangleMesh(const std::string& poly_file_name,
693  const double& element_area,
694  TimeStepper* time_stepper_pt=
695  &Mesh::Default_TimeStepper,
696  const bool &allow_automatic_creation_of_vertices_on_boundaries=true)
697  {
698  // Mesh can only be built with 2D Telements.
699  MeshChecker::assert_geometric_element<TElementGeometricBase,ELEMENT>(2);
700 
701  // Initialize the value for allowing creation of points on boundaries
703  allow_automatic_creation_of_vertices_on_boundaries;
704 
705 #ifdef OOMPH_HAS_MPI
706  // Initialize the flag to indicate this is the first time to
707  // compute the holes left by the halo elements
708  First_time_compute_holes_left_by_halo_elements=true;
709 #endif // #ifdef OOMPH_HAS_MPI
710 
711  // Disclaimer
712  std::string message=
713  "This constructor hasn't been tested since last cleanup.\n";
714  OomphLibWarning(message,
715  "TriangleMesh::TriangleMesh()",
716  OOMPH_EXCEPTION_LOCATION);
717 
718  // Store Timestepper used to build elements
719  Time_stepper_pt=time_stepper_pt;
720 
721  // Create the data structures required to call the triangulate function
722  TriangulateIO triangle_in;
723 
724  // Input string for triangle
725  std::stringstream input_string_stream;
726 
727  // MH: Like everything else, this hasn't been tested!
728  // used to be input_string_stream<<"-pA -a" << element_area << "q30";
729  input_string_stream<< "-pA -a -a" << element_area << "q30";
730 
731  // Verify if creation of new points on boundaries is allowed
732  if (!this->is_creation_of_vertices_on_boundaries_allowed())
733  {
734  input_string_stream<<" -YY";
735  }
736 
737  // Convert to a *char required by the triangulate function
738  char triswitches[100];
739  sprintf(triswitches,"%s",input_string_stream.str().c_str());
740 
741  // Create a boolean to decide whether or not to use attributes.
742  // The value of this will only be changed in build_triangulateio
743  // depending on whether or not the .poly file contains regions
744  bool use_attributes=false;
745 
746  // Build the input triangulateio object from the .poly file
747  build_triangulateio(poly_file_name,triangle_in,use_attributes);
748 
749  //Store the attributes flag
750  Use_attributes=use_attributes;
751 
752  // Build the triangulateio out object
753  triangulate(triswitches,&triangle_in,&Triangulateio,0);
754 
755  // Build scaffold
756  this->Tmp_mesh_pt=new TriangleScaffoldMesh(Triangulateio);
757 
758  // Convert mesh from scaffold to actual mesh
759  build_from_scaffold(time_stepper_pt,use_attributes);
760 
761  // Kill the scaffold
762  delete this->Tmp_mesh_pt;
763  this->Tmp_mesh_pt=0;
764 
765  // Cleanup but leave hole alone
766  bool clear_hole_data=false;
767  TriangleHelper::clear_triangulateio(triangle_in,clear_hole_data);
768 
769  // Setup boundary coordinates for boundaries
770  unsigned nb=nboundary();
771  for (unsigned b=0;b<nb;b++)
772  {
773  this->template setup_boundary_coordinates<ELEMENT>(b);
774  }
775  }
776 
777 #endif
778 
779  /// Broken copy constructor
780  TriangleMesh(const TriangleMesh& dummy)
781  {
782  BrokenCopy::broken_copy("TriangleMesh");
783  }
784 
785  /// Broken assignment operator
786  void operator=(const TriangleMesh&)
787  {
788  BrokenCopy::broken_assign("TriangleMesh");
789  }
790 
791  /// Destructor
792  virtual ~TriangleMesh()
793  {
794 #ifdef OOMPH_HAS_TRIANGLE_LIB
795  if (Triangulateio_exists)
796  {
797  TriangleHelper::clear_triangulateio(Triangulateio);
798  }
799 
800  std::set<TriangleMeshCurveSection*>::iterator it_polyline;
801  for (it_polyline = Free_curve_section_pt.begin();
802  it_polyline != Free_curve_section_pt.end();
803  it_polyline++)
804  {
805  delete (*it_polyline);
806  }
807 
808  std::set<TriangleMeshPolygon*>::iterator it_polygon;
809  for (it_polygon = Free_polygon_pt.begin();
810  it_polygon != Free_polygon_pt.end();
811  it_polygon++)
812  {
813  delete (*it_polygon);
814  }
815 
816  std::set<TriangleMeshOpenCurve*>::iterator it_open_polyline;
817  for (it_open_polyline = Free_open_curve_pt.begin();
818  it_open_polyline != Free_open_curve_pt.end();
819  it_open_polyline++)
820  {
821  delete (*it_open_polyline);
822  }
823 
824 #endif
825  }
826 
827  /// \short Overload set_mesh_level_time_stepper so that the stored
828  /// time stepper now corresponds to the new timestepper
829  void set_mesh_level_time_stepper(TimeStepper* const &time_stepper_pt,
830  const bool &preserve_existing_data)
831  {
832  this->Time_stepper_pt = time_stepper_pt;
833  }
834 
835 #ifdef OOMPH_HAS_MPI
836 
837  /// \short Compute the boundary segments connectivity for those
838  /// boundaries that were splited during the distribution process
839  void compute_boundary_segments_connectivity_and_initial_zeta_values(
840  const unsigned& b);
841 
842  /// \short Re-assign the boundary segments initial zeta (arclength)
843  /// value for those internal boundaries that were splited during the
844  /// distribution process. Those boundaries that have one face element
845  /// at each side of the boundary
846  void re_assign_initial_zeta_values_for_internal_boundary(
847  const unsigned& b,
848  Vector<std::list<FiniteElement*> > &old_segment_sorted_ele_pt,
849  std::map<FiniteElement*, bool> &old_is_inverted);
850 
851  /// \short Re-scale the re-assigned zeta values for the boundary
852  /// nodes, apply only for internal boundaries
853  void re_scale_re_assigned_initial_zeta_values_for_internal_boundary(
854  const unsigned& b);
855 
856  /// \short Identify the segments from the old mesh (original mesh)
857  /// in the new mesh (this) and assign initial and final boundary
858  /// coordinates for the segments that create the boundary. (This is
859  /// the version called from the original mesh to identify its own
860  /// segments)
861  void identify_boundary_segments_and_assign_initial_zeta_values(
862  const unsigned& b, Vector<FiniteElement*> &input_face_ele_pt,
863  const bool &is_internal_boundary,
864  std::map<FiniteElement*,FiniteElement*> &face_to_bulk_element_pt);
865 
866  /// \short Identify the segments from the old mesh (original mesh)
867  /// in the new mesh (this) and assign initial and final boundary
868  /// coordinates for the segments that create the boundary
869  void identify_boundary_segments_and_assign_initial_zeta_values(
870  const unsigned& b, TriangleMesh<ELEMENT>* original_mesh_pt);
871 
872  /// \short In charge of sinchronize the boundary coordinates for
873  /// internal boundaries that were split as part of the distribution
874  /// process. Called after setup_boundary_coordinates() for the
875  /// original mesh only
876  void synchronize_boundary_coordinates(const unsigned& b);
877 
878  /// \short Select face element from boundary using the criteria to
879  /// decide which of the two face elements should be used on internal
880  /// boundaries
881  void select_boundary_face_elements(
882  Vector<FiniteElement*> &face_el_pt, const unsigned &b,
883  bool &is_internal_boundary,
884  std::map<FiniteElement*,FiniteElement*> &face_to_bulk_element_pt);
885 
886  /// \short Return direct access to nodes associated with a boundary but
887  /// sorted in segments
888  Vector<Vector<Node*> > &boundary_segment_node_pt(const unsigned &b)
889  {return Boundary_segment_node_pt[b];}
890 
891  /// \short Return direct access to nodes associated with a segment of
892  /// a given boundary
893  Vector<Node*> &boundary_segment_node_pt(const unsigned &b,const unsigned &s)
894  {return Boundary_segment_node_pt[b][s];}
895 
896  /// Return pointer to node n on boundary b
897  Node* &boundary_segment_node_pt(const unsigned &b, const unsigned &s,
898  const unsigned &n)
899  {return Boundary_segment_node_pt[b][s][n];}
900 
901 #endif // OOMPH_HAS_MPI
902 
903 #ifdef OOMPH_HAS_TRIANGLE_LIB
904 
905  /// \short Update the TriangulateIO object to the current nodal position
906  /// and the centre hole coordinates.
907  void update_triangulateio(Vector<Vector<double> >&internal_point)
908  {
909  // Move the hole center
910  // Get number of holes
911  unsigned nhole=Triangulateio.numberofholes;
912  unsigned count_coord=0;
913  for(unsigned ihole=0;ihole<nhole;ihole++)
914  {
915  Triangulateio.holelist[count_coord]+=internal_point[ihole][0];
916  Triangulateio.holelist[count_coord+1]+=internal_point[ihole][1];
917 
918  // Increment counter
919  count_coord+=2;
920  }
921 
922  // Do the update
923  update_triangulateio();
924  }
925 
926  /// \short Update the triangulateio object to the current nodal positions
928  {
929  // Get number of points
930  unsigned nnode = Triangulateio.numberofpoints;
931  double new_x=0;
932  double new_y=0;
933 
934  // Loop over the points
935  for(unsigned inod=0;inod<nnode;inod++)
936  {
937  // Get the node Id to be updated
938  unsigned count=Oomph_vertex_nodes_id[inod];
939 
940  // Update vertices using the vertex_node_id giving for the TriangulateIO
941  // vertex enumeration the corresponding oomphlib mesh enumeration
942  Node* mesh_node_pt=this->node_pt(inod);
943  new_x=mesh_node_pt->x(0);
944  new_y=mesh_node_pt->x(1);
945  Triangulateio.pointlist[count*2] = new_x;
946  Triangulateio.pointlist[(count*2)+1] = new_y;
947  }
948  }
949 
950 #ifdef OOMPH_HAS_MPI
951  /// Used to dump info. related with distributed triangle meshes
952  void dump_distributed_info_for_restart(std::ostream &dump_file);
953 
954  const unsigned read_unsigned_line_helper(std::istream &read_file)
955  {
956  std::string input_string;
957 
958  // Read line up to termination sign
959  getline(read_file,input_string,'#');
960 
961  // Ignore rest of line
962  read_file.ignore(200,'\n');
963 
964  // Convert
965  return std::atoi(input_string.c_str());
966  }
967 
968  /// Used to read info. related with distributed triangle meshes
969  void read_distributed_info_for_restart(std::istream &restart_file);
970 
971  /// Virtual function used to re-establish any additional info. related with
972  /// the distribution after a re-starting for triangle meshes
974  OomphCommunicator* comm_pt, std::istream &restart_file)
975  {
976  std::ostringstream error_stream;
977  error_stream << "Empty default reestablish disributed info method "
978  << "called.\n";
979  error_stream << "This should be overloaded in a specific "
980  << "RefineableTriangleMesh\n";
981  throw OomphLibError(error_stream.str(),
982  OOMPH_CURRENT_FUNCTION,
983  OOMPH_EXCEPTION_LOCATION);
984  }
985 
986 #endif // #ifdef OOMPH_HAS_MPI
987 
988  /// \short Completely regenerate the mesh from the trianglateio structure
990  {
991  //Remove all the boundary node information
992  this->remove_boundary_nodes();
993 
994  //Delete exisiting nodes
995  unsigned n_node = this->nnode();
996  for(unsigned n=n_node;n>0;--n)
997  {
998  delete this->Node_pt[n-1];
999  this->Node_pt[n-1] = 0;
1000  }
1001  //Delete exisiting elements
1002  unsigned n_element = this->nelement();
1003  for(unsigned e=n_element;e>0;--e)
1004  {
1005  delete this->Element_pt[e-1];
1006  this->Element_pt[e-1] = 0;
1007  }
1008  //Flush the storage
1009  this->flush_element_and_node_storage();
1010 
1011  //Delete all boundary element information
1012  //ALH: Kick up the object hierarchy?
1013  this->Boundary_element_pt.clear();
1014  this->Face_index_at_boundary.clear();
1015  this->Region_element_pt.clear();
1016  this->Region_attribute.clear();
1017  this->Boundary_region_element_pt.clear();
1018  this->Face_index_region_at_boundary.clear();
1019  this->Boundary_curve_section_pt.clear();
1020  this->Polygonal_vertex_arclength_info.clear();
1021 
1022 #ifdef OOMPH_HAS_MPI
1023  // Delete Halo(ed) information in the old mesh
1024  if (this->is_mesh_distributed())
1025  {
1026  this->Halo_node_pt.clear();
1027  this->Root_halo_element_pt.clear();
1028 
1029  this->Haloed_node_pt.clear();
1030  this->Root_haloed_element_pt.clear();
1031 
1032  this->External_halo_node_pt.clear();
1033  this->External_halo_element_pt.clear();
1034 
1035  this->External_haloed_node_pt.clear();
1036  this->External_haloed_element_pt.clear();
1037  }
1038 #endif
1039 
1040  unsigned nbound=nboundary();
1041  Boundary_coordinate_exists.resize(nbound,false);
1042 
1043  //Now build the new scaffold
1044  this->Tmp_mesh_pt= new TriangleScaffoldMesh(this->Triangulateio);
1045 
1046  // Triangulation has been created -- remember to wipe it!
1047  Triangulateio_exists=true;
1048 
1049  // Convert mesh from scaffold to actual mesh
1050  build_from_scaffold(this->Time_stepper_pt,this->Use_attributes);
1051 
1052  // Kill the scaffold
1053  delete this->Tmp_mesh_pt;
1054  this->Tmp_mesh_pt=0;
1055 
1056 #ifdef OOMPH_HAS_MPI
1057  if (!this->is_mesh_distributed())
1058  {
1059  nbound = this->nboundary(); // The original number of boundaries
1060  }
1061  else
1062  {
1063  nbound = this->initial_shared_boundary_id();
1064  // NOTE: The total number of boundaries is the number of
1065  // original bondaries plus the number of shared boundaries, but
1066  // here we only establish boundary coordinates for the original
1067  // boundaries. Once all the info. related with the distribution
1068  // has been established then the number of boundaries is reset
1069  // to the correct one (after reset the halo/haloed scheme)
1070  }
1071 #else
1072  nbound = this->nboundary(); // The original number of boundaries
1073 #endif
1074 
1075  // Setup boundary coordinates for boundaries
1076  for (unsigned b=0;b<nbound;b++)
1077  {
1078  this->template setup_boundary_coordinates<ELEMENT>(b);
1079  }
1080 
1081  // Snap nodes only if the mesh is not distributed, if the mesh is
1082  // distributed it will be called after the re-establishment of the
1083  // halo/haloed scheme, and the proper identification of the segments
1084  // in the boundary
1085  if (!this->is_mesh_distributed())
1086  {
1087  //Deform the boundary onto any geometric objects
1088  this->snap_nodes_onto_geometric_objects();
1089  }
1090  }
1091 
1092  /// Boolean defining if Triangulateio object has been built or not
1094  {
1095  return Triangulateio_exists;
1096  }
1097 
1098 #endif
1099 
1100  /// \short Return the vector that contains the oomph-lib node number
1101  /// for all vertex nodes in the TriangulateIO representation of the mesh
1102  Vector<unsigned> oomph_vertex_nodes_id()
1103  {
1104  return Oomph_vertex_nodes_id;
1105  }
1106 
1107  /// Timestepper used to build elements
1108  TimeStepper* Time_stepper_pt;
1109 
1110  /// Boolean flag to indicate whether to use attributes or not (required
1111  /// for multidomain meshes)
1113 
1114  protected:
1115 
1116  /// \short Target areas for regions; defaults to 0.0 which (luckily)
1117  /// implies "no specific target area" for triangle!
1118  std::map<unsigned, double> Regions_areas;
1119 
1120  /// Build mesh from scaffold
1121  void build_from_scaffold(TimeStepper* time_stepper_pt,
1122  const bool &use_attributes);
1123 
1124 #ifdef OOMPH_HAS_TRIANGLE_LIB
1125 
1126  /// \short Helper function to create TriangulateIO object (return in
1127  /// triangulate_io) from the .poly file
1128  void build_triangulateio(const std::string& poly_file_name,
1129  TriangulateIO& triangulate_io,
1130  bool& use_attributes);
1131 
1132  /// \short A general-purpose construction function that builds the
1133  /// mesh once the different specific constructors have assembled the
1134  /// appropriate information.
1135  void generic_constructor(Vector<TriangleMeshPolygon*> &outer_boundary_pt,
1136  Vector<TriangleMeshPolygon*> &internal_polygon_pt,
1137  Vector<TriangleMeshOpenCurve*>
1138  &open_polylines_pt,
1139  const double &element_area,
1140  Vector<Vector<double> > &extra_holes_coordinates,
1141  std::map<unsigned, Vector<double> >
1143  std::map<unsigned, double >
1144  &regions_areas,
1145  TimeStepper* time_stepper_pt,
1146  const bool &use_attributes,
1147  const bool &refine_boundary,
1148  const bool &refine_internal_boundary)
1149  {
1150  // Mesh can only be built with 2D Telements.
1151  MeshChecker::assert_geometric_element<TElementGeometricBase,ELEMENT>(2);
1152 
1153 #ifdef PARANOID
1154  if (element_area < 10e-14)
1155  {
1156  std::ostringstream warning_message;
1157  warning_message
1158  << "The current elements area was stated to (" << element_area
1159  << ").\nThe current precision to generate the input to triangle "
1160  << "is fixed to 14 digits\n\n";
1161  OomphLibWarning(warning_message.str(),
1162  OOMPH_CURRENT_FUNCTION,
1163  OOMPH_EXCEPTION_LOCATION);
1164  }
1165 #endif
1166 
1167  //Store the attribute flag
1168  Use_attributes = use_attributes;
1169 
1170  // Store Timestepper used to build elements
1171  Time_stepper_pt=time_stepper_pt;
1172 
1173  // Store outer polygon
1175 
1176  // Store internal polygons by copy constructor
1177  Internal_polygon_pt=internal_polygon_pt;
1178 
1179  // Store internal polylines by copy constructor
1180  Internal_open_curve_pt = open_polylines_pt;
1181 
1182  // Store the extra holes coordinates
1184 
1185  // Store the extra regions coordinates
1187 
1188  // Create the data structures required to call the triangulate function
1189  TriangulateIO triangulate_io;
1190 
1191  // Initialize TriangulateIO structure
1192  TriangleHelper::initialise_triangulateio(triangulate_io);
1193 
1194  // Convert TriangleMeshPolyLine and TriangleMeshClosedCurvePolyLine
1195  // to a triangulateio object
1196  UnstructuredTwoDMeshGeometryBase::build_triangulateio(outer_boundary_pt,
1197  internal_polygon_pt,
1198  open_polylines_pt,
1201  regions_areas,
1202  triangulate_io);
1203 
1204  // Initialize TriangulateIO structure
1205  TriangleHelper::initialise_triangulateio(Triangulateio);
1206 
1207  // Triangulation has been created -- remember to wipe it!
1208  Triangulateio_exists=true;
1209 
1210  // Input string for triangle
1211  std::stringstream input_string_stream;
1212  input_string_stream.precision(14);
1213  input_string_stream.setf(std::ios_base::fixed,
1214  std::ios_base::floatfield);
1215 
1216  // MH: Used to be:
1217  // input_string_stream<<"-pA -a" << element_area << " -q30" << std::fixed;
1218  // The repeated -a allows the specification of areas for different
1219  // regions (if any)
1220  input_string_stream <<"-pA -a -a" << element_area << " -q30" << std::fixed;
1221 
1222  // Verify if creation of new points on boundaries is allowed
1224  {input_string_stream<<" -YY";}
1225 
1226  //Suppress insertion of additional points on outer boundary
1227  if(refine_boundary==false)
1228  {
1229  input_string_stream << "-Y";
1230  //Add the extra flag to suppress additional points on interior segments
1231  if(refine_internal_boundary==false) {input_string_stream << "Y";}
1232  }
1233 
1234  // Convert the Input string in *char required by the triangulate function
1235  char triswitches[100];
1236  sprintf(triswitches,"%s",input_string_stream.str().c_str());
1237 
1238  // Build the mesh using triangulate function
1239  triangulate(triswitches, &triangulate_io, &Triangulateio, 0);
1240 
1241  // Build scaffold
1242  this->Tmp_mesh_pt= new TriangleScaffoldMesh(Triangulateio);
1243 
1244  //If we have filled holes then we must use the attributes
1245  if(!regions_coordinates.empty())
1246  {
1247  // Convert mesh from scaffold to actual mesh
1248  build_from_scaffold(time_stepper_pt,true);
1249  //Record the attribute flag
1250  Use_attributes=true;
1251  }
1252  //Otherwise use what was asked
1253  else
1254  {
1255  // Convert mesh from scaffold to actual mesh
1256  build_from_scaffold(time_stepper_pt,use_attributes);
1257  }
1258 
1259  // Kill the scaffold
1260  delete this->Tmp_mesh_pt;
1261  this->Tmp_mesh_pt=0;
1262 
1263  // Cleanup but leave hole and regions alone since it's still used
1264  bool clear_hole_data=false;
1265  TriangleHelper::clear_triangulateio(triangulate_io,clear_hole_data);
1266  }
1267 
1268  /// Boolean defining if Triangulateio object has been built or not
1270 
1271 #endif // OOMPH_HAS_TRIANGLE_LIB
1272 
1273  /// Temporary scaffold mesh
1274  TriangleScaffoldMesh* Tmp_mesh_pt;
1275 
1276  /// \short Vector storing oomph-lib node number
1277  /// for all vertex nodes in the TriangulateIO representation of the mesh
1278  Vector<unsigned> Oomph_vertex_nodes_id;
1279 
1280 #ifdef OOMPH_HAS_MPI
1281 
1282  public:
1283 
1284  /// The initial boundary id for shared boundaries
1286  {return Initial_shared_boundary_id;}
1287 
1288  /// The final boundary id for shared boundaries
1289  const unsigned final_shared_boundary_id()
1290  {return Final_shared_boundary_id;}
1291 
1292 
1293  protected:
1294 
1295  /// Get the shared boundaries ids living in the current processor
1297  Vector<unsigned> &shared_boundaries_in_this_processor)
1298  {
1299 #ifdef PARANOID
1300  // Used to check if there are repeated shared boundaries
1301  std::set<unsigned> shared_boundaries_in_this_processor_set;
1302 #endif
1303  // Get the number of processors
1304  const unsigned n_proc = this->communicator_pt()->nproc();
1305  // Get the current processor
1306  const unsigned my_rank = this->communicator_pt()->my_rank();
1307  // Loop over all the processor and get the shared boundaries ids
1308  // associated with each processor
1309  for (unsigned iproc = 0; iproc < n_proc; iproc++)
1310  {
1311  // Work with other processors only
1312  if (iproc != my_rank)
1313  {
1314  // Get the number of boundaries shared with the "iproc"-th
1315  // processor
1316  const unsigned nshared_boundaries_with_iproc =
1317  this->nshared_boundaries(my_rank, iproc);
1318 
1319  // If there are shared boundaries associated with the current
1320  // processor then add them
1321  if (nshared_boundaries_with_iproc > 0)
1322  {
1323  // Get the boundaries ids shared with "iproc"-th processor
1324  Vector<unsigned> bound_ids_shared_with_iproc;
1325  bound_ids_shared_with_iproc =
1326  this->shared_boundaries_ids(my_rank, iproc);
1327 
1328  // Loop over shared boundaries with "iproc"-th processor
1329  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
1330  {
1331  const unsigned bnd_id = bound_ids_shared_with_iproc[bs];
1332 #ifdef PARANOID
1333  // Check that the current shared boundary id has not been
1334  // previously added
1335  std::set<unsigned>::iterator it =
1336  shared_boundaries_in_this_processor_set.find(bnd_id);
1337  if (it != shared_boundaries_in_this_processor_set.end())
1338  {
1339  std::stringstream error;
1340  error
1341  << "The current shared boundary (" << bnd_id << ") was\n"
1342  << "already added by other pair of processors\n."
1343  << "This means that there are repeated shared boundaries ids\n";
1344  throw OomphLibError(error.str(),
1345  OOMPH_CURRENT_FUNCTION,
1346  OOMPH_EXCEPTION_LOCATION);
1347  } // if (it != shared_boundaries_in_this_processor_set.end())
1348  shared_boundaries_in_this_processor_set.insert(bnd_id);
1349 #endif
1350  shared_boundaries_in_this_processor.push_back(bnd_id);
1351  } // for (bs < nshared_boundaries_with_iproc)
1352 
1353  } // if (nshared_boundaries_with_iproc > 0)
1354 
1355  } // if (iproc != my_rank)
1356 
1357  } // for (iproc < nproc)
1358 
1359  }
1360 
1361  /// Access functions to boundaries shared with processors
1362  const unsigned nshared_boundaries(const unsigned &p,
1363  const unsigned &q) const
1364  {return Shared_boundaries_ids[p][q].size();}
1365 
1366  Vector<Vector<Vector<unsigned> > > shared_boundaries_ids() const
1367  {return Shared_boundaries_ids;}
1368 
1369  Vector<Vector<Vector<unsigned> > > &shared_boundaries_ids()
1370  {return Shared_boundaries_ids;}
1371 
1372  Vector<Vector<unsigned> > shared_boundaries_ids(const unsigned &p) const
1373  {return Shared_boundaries_ids[p];}
1374 
1375  Vector<Vector<unsigned> > &shared_boundaries_ids(const unsigned &p)
1376  {return Shared_boundaries_ids[p];}
1377 
1378  Vector<unsigned> shared_boundaries_ids(const unsigned &p,
1379  const unsigned &q) const
1380  {return Shared_boundaries_ids[p][q];}
1381 
1382  Vector<unsigned> &shared_boundaries_ids(const unsigned &p, const unsigned &q)
1383  {return Shared_boundaries_ids[p][q];}
1384 
1385  const unsigned shared_boundaries_ids(const unsigned &p,
1386  const unsigned &q,
1387  const unsigned &i) const
1388  {return Shared_boundaries_ids[p][q][i];}
1389 
1390  const unsigned nshared_boundary_curves(const unsigned &p) const
1391  {return Shared_boundary_polyline_pt[p].size();}
1392 
1393  const unsigned nshared_boundary_polyline(const unsigned &p,
1394  const unsigned &c) const
1395  {return Shared_boundary_polyline_pt[p][c].size();}
1396 
1397  Vector<TriangleMeshPolyLine*> &shared_boundary_polyline_pt(const unsigned &p,
1398  const unsigned &c)
1399  {return Shared_boundary_polyline_pt[p][c];}
1400 
1401  TriangleMeshPolyLine *shared_boundary_polyline_pt(const unsigned &p,
1402  const unsigned &c,
1403  const unsigned &i) const
1404  {return Shared_boundary_polyline_pt[p][c][i];}
1405 
1406  const unsigned nshared_boundaries() const
1407  {return Shared_boundary_element_pt.size();}
1408 
1409  const unsigned nshared_boundary_element(const unsigned &b)
1410  {
1411  // First check if the boundary exist
1412  std::map<unsigned, Vector<FiniteElement*> >::iterator it =
1413  Shared_boundary_element_pt.find(b);
1414  if (it != Shared_boundary_element_pt.end())
1415  {
1416  return Shared_boundary_element_pt[b].size();
1417  }
1418  else
1419  {
1420  std::ostringstream error_stream;
1421  error_stream
1422  << "The shared boundary ("<< b << ") does not exist!!!\n\n";
1423  throw OomphLibError(error_stream.str(),
1424  OOMPH_CURRENT_FUNCTION,
1425  OOMPH_EXCEPTION_LOCATION);
1426  }
1427  }
1428 
1430  {Shared_boundary_element_pt.clear();}
1431 
1432  void flush_shared_boundary_element(const unsigned &b)
1433  {
1434  // First check if the boundary exist
1435  std::map<unsigned, Vector<FiniteElement*> >::iterator it =
1436  Shared_boundary_element_pt.find(b);
1437  if (it != Shared_boundary_element_pt.end())
1438  {
1439  Shared_boundary_element_pt[b].clear();
1440  }
1441  else
1442  {
1443  std::ostringstream error_stream;
1444  error_stream
1445  << "The shared boundary ("<< b << ") does not exist!!!\n\n";
1446  throw OomphLibError(error_stream.str(),
1447  OOMPH_CURRENT_FUNCTION,
1448  OOMPH_EXCEPTION_LOCATION);
1449  }
1450  }
1451 
1452  void add_shared_boundary_element(const unsigned &b,
1453  FiniteElement* ele_pt)
1454  {Shared_boundary_element_pt[b].push_back(ele_pt);}
1455 
1456  FiniteElement* shared_boundary_element_pt(const unsigned &b,
1457  const unsigned &e)
1458  {
1459  // First check if the boundary exist
1460  std::map<unsigned, Vector<FiniteElement*> >::iterator it =
1461  Shared_boundary_element_pt.find(b);
1462  if (it != Shared_boundary_element_pt.end())
1463  {
1464  return Shared_boundary_element_pt[b][e];
1465  }
1466  else
1467  {
1468  std::ostringstream error_stream;
1469  error_stream
1470  << "The shared boundary ("<< b << ") does not exist!!!\n\n";
1471  throw OomphLibError(error_stream.str(),
1472  OOMPH_CURRENT_FUNCTION,
1473  OOMPH_EXCEPTION_LOCATION);
1474  }
1475  }
1476 
1478  {Face_index_at_shared_boundary.clear();}
1479 
1480  void add_face_index_at_shared_boundary(const unsigned &b,
1481  const unsigned &i)
1482  {Face_index_at_shared_boundary[b].push_back(i);}
1483 
1484  int face_index_at_shared_boundary(const unsigned &b,
1485  const unsigned &e)
1486  {
1487  // First check if the boundary exist
1488  std::map<unsigned, Vector<int> >::iterator it =
1489  Face_index_at_shared_boundary.find(b);
1490  if (it != Face_index_at_shared_boundary.end())
1491  {
1492  return Face_index_at_shared_boundary[b][e];
1493  }
1494  else
1495  {
1496  std::ostringstream error_stream;
1497  error_stream
1498  << "The shared boundary ("<< b << ") does not exist!!!\n\n";
1499  throw OomphLibError(error_stream.str(),
1500  OOMPH_CURRENT_FUNCTION,
1501  OOMPH_EXCEPTION_LOCATION);
1502  }
1503  }
1504 
1505  const unsigned nshared_boundary_node(const unsigned &b)
1506  {
1507  // First check if the boundary exist
1508  std::map<unsigned, Vector<Node*> >::iterator it =
1509  Shared_boundary_node_pt.find(b);
1510  if (it != Shared_boundary_node_pt.end())
1511  {
1512  return Shared_boundary_node_pt[b].size();
1513  }
1514  else
1515  {
1516  std::ostringstream error_stream;
1517  error_stream
1518  << "The shared boundary ("<< b << ") does not exist!!!\n\n";
1519  throw OomphLibError(error_stream.str(),
1520  OOMPH_CURRENT_FUNCTION,
1521  OOMPH_EXCEPTION_LOCATION);
1522  }
1523  }
1524 
1525  /// Flush ALL the shared boundary nodes
1527  {Shared_boundary_node_pt.clear();}
1528 
1529  /// Flush the boundary nodes associated to the shared boundary b
1530  void flush_shared_boundary_node(const unsigned &b)
1531  {Shared_boundary_node_pt[b].clear();}
1532 
1533  /// Add the node the shared boundary
1534  void add_shared_boundary_node(const unsigned &b, Node* node_pt)
1535  {
1536  //Get the size of the Shared_boundary_node_pt vector
1537  const unsigned nbound_node=Shared_boundary_node_pt[b].size();
1538  bool node_already_on_this_boundary=false;
1539  //Loop over the vector
1540  for (unsigned n=0; n<nbound_node; n++)
1541  {
1542  // is the current node here already?
1543  if (node_pt==Shared_boundary_node_pt[b][n])
1544  {
1545  node_already_on_this_boundary=true;
1546  }
1547  }
1548 
1549  //Add the base node pointer to the vector if it's not there already
1550  if (!node_already_on_this_boundary)
1551  {
1552  Shared_boundary_node_pt[b].push_back(node_pt);
1553  }
1554 
1555  }
1556 
1557  Node* shared_boundary_node_pt(const unsigned &b, const unsigned &n)
1558  {
1559  // First check if the boundary exist
1560  std::map<unsigned, Vector<Node*> >::iterator it =
1561  Shared_boundary_node_pt.find(b);
1562  if (it != Shared_boundary_node_pt.end())
1563  {
1564  return Shared_boundary_node_pt[b][n];
1565  }
1566  else
1567  {
1568  std::ostringstream error_stream;
1569  error_stream
1570  << "The shared boundary ("<< b << ") does not exist!!!\n\n";
1571  throw OomphLibError(error_stream.str(),
1572  OOMPH_CURRENT_FUNCTION,
1573  OOMPH_EXCEPTION_LOCATION);
1574  }
1575  }
1576 
1577  /// Is the node on the shared boundary
1578  bool is_node_on_shared_boundary(const unsigned &b, Node* const &node_pt)
1579  {
1580  // First check if the boundary exist
1581  std::map<unsigned, Vector<Node*> >::iterator it =
1582  Shared_boundary_node_pt.find(b);
1583  if (it != Shared_boundary_node_pt.end())
1584  {
1585  // Now check if the node lives on the shared boundary
1586  Vector<Node*>::iterator it_shd_nodes =
1587  std::find(Shared_boundary_node_pt[b].begin(),
1588  Shared_boundary_node_pt[b].end(),
1589  node_pt);
1590  //If the node is on this boundary
1591  if(it_shd_nodes!=Shared_boundary_node_pt[b].end())
1592  {return true;}
1593  else // The node is not on the boundary
1594  {return false;}
1595  }
1596  else
1597  {
1598  std::ostringstream error_stream;
1599  error_stream
1600  << "The shared boundary ("<< b << ") does not exist!!!\n\n";
1601  throw OomphLibError(error_stream.str(),
1602  OOMPH_CURRENT_FUNCTION,
1603  OOMPH_EXCEPTION_LOCATION);
1604  }
1605  }
1606 
1607  /// Return the association of the shared boundaries with the processors
1608  std::map<unsigned, Vector<unsigned> > &shared_boundary_from_processors()
1609  {return Shared_boundary_from_processors;}
1610 
1611  Vector<unsigned> &shared_boundary_from_processors(const unsigned &b)
1612  {
1613  std::map<unsigned, Vector<unsigned> >::iterator it =
1614  Shared_boundary_from_processors.find(b);
1615 #ifdef PARANOID
1616  if (it == Shared_boundary_from_processors.end())
1617  {
1618  std::ostringstream error_message;
1619  error_message
1620  <<"The boundary ("<<b<<") seems not to be shared by any processors,\n"
1621  <<"it is possible that the boundary was created by the user an not\n"
1622  <<"automatically by the common interfaces between processors-domains\n";
1623  throw OomphLibError(error_message.str(),
1624  OOMPH_CURRENT_FUNCTION,
1625  OOMPH_EXCEPTION_LOCATION);
1626  }
1627 #endif
1628  return (*it).second;
1629  }
1630 
1631  /// \short Get the number of shared boundaries overlaping internal
1632  /// boundaries
1634  {
1635  return Shared_boundary_overlaps_internal_boundary.size();
1636  }
1637 
1638  /// \short Checks if the shared boundary overlaps an internal boundary
1640  const unsigned &shd_bnd_id)
1641  {
1642  std::map<unsigned, unsigned>::iterator it =
1643  Shared_boundary_overlaps_internal_boundary.find(shd_bnd_id);
1644  if (it != Shared_boundary_overlaps_internal_boundary.end())
1645  {
1646  return true;
1647  }
1648  return false;
1649  }
1650 
1651  /// \short Gets the boundary id of the internal boundary that the
1652  /// shared boundary lies on
1654  const unsigned &shd_bnd_id)
1655  {
1656  std::map<unsigned, unsigned>::iterator it =
1657  Shared_boundary_overlaps_internal_boundary.find(shd_bnd_id);
1658 #ifdef PARANOID
1659  if (it == Shared_boundary_overlaps_internal_boundary.end())
1660  {
1661  std::ostringstream error_message;
1662  error_message
1663  <<"The shared boundary ("<<shd_bnd_id<<") does not lie on an internal "
1664  << "boundary!!!.\n"
1665  << "Make sure to call this method just for shared boundaries that lie "
1666  << "on an internal boundary.\n\n";
1667  throw OomphLibError(error_message.str(),
1668  OOMPH_CURRENT_FUNCTION,
1669  OOMPH_EXCEPTION_LOCATION);
1670  }
1671 #endif
1672  return (*it).second;
1673  }
1674 
1675  /// \short Gets the shared boundaries ids that overlap the given
1676  /// internal boundary
1678  const unsigned &internal_bnd_id,
1679  Vector<unsigned> &shd_bnd_ids)
1680  {
1681  // Clear any data in the output storage
1682  shd_bnd_ids.clear();
1683  // Loop over the map and store in the output vector the shared
1684  // boundaries ids that overlap the internal boundary
1685  std::map<unsigned, unsigned>::iterator it =
1686  Shared_boundary_overlaps_internal_boundary.begin();
1687  for (; it !=Shared_boundary_overlaps_internal_boundary.end(); it++)
1688  {
1689  // If the second entry is the internal boundary, then add the
1690  // first entry to the output vector
1691  if ((*it).second == internal_bnd_id)
1692  {
1693  // Add the first entry
1694  shd_bnd_ids.push_back((*it).first);
1695  }
1696  } // loop over the map entries
1697 
1698 #ifdef PARANOID
1699  if (shd_bnd_ids.size() == 0)
1700  {
1701  std::ostringstream error_message;
1702  error_message
1703  <<" The internal boundary (" << internal_bnd_id << ") has no shared "
1704  << "boundaries overlapping it\n"
1705  << "Make sure to call this method just for internal boundaries that "
1706  << "are marked to as being\noverlaped by shared boundaries\n";
1707  throw OomphLibError(error_message.str(),
1708  OOMPH_CURRENT_FUNCTION,
1709  OOMPH_EXCEPTION_LOCATION);
1710  }
1711 #endif
1712 
1713  }
1714 
1715  /// \short Gets the storage that indicates if a shared boundary is part
1716  /// of an internal boundary
1717  std::map<unsigned, unsigned> &shared_boundary_overlaps_internal_boundary()
1718  {return Shared_boundary_overlaps_internal_boundary;}
1719 
1720  /// \short Helper function to verify if a given boundary was splitted
1721  /// in the distribution process
1722  const bool boundary_was_splitted(const unsigned &b)
1723  {
1724  std::map<unsigned, bool>::iterator it;
1725  it = Boundary_was_splitted.find(b);
1726  if (it == Boundary_was_splitted.end())
1727  {
1728  return false;
1729  }
1730  else
1731  {
1732  return (*it).second;
1733  }
1734  }
1735 
1736  /// \short Gets the number of subpolylines that create the boundarya
1737  /// (useful only when the boundary is marked as split)
1738  const unsigned nboundary_subpolylines(const unsigned &b)
1739  {
1740  std::map<unsigned, Vector<TriangleMeshPolyLine*> >::iterator it;
1741  it = Boundary_subpolylines.find(b);
1742 #ifdef PARANOID
1743  if (it == Boundary_subpolylines.end())
1744  {
1745  std::ostringstream error_message;
1746  error_message
1747  <<"The boundary ("<<b<<") was marked as been splitted but there\n"
1748  <<"are not registered polylines to represent the boundary.\n"
1749  <<"The new polylines were not set up when the boundary was found to\n"
1750  <<"be splitted or the polylines have been explicitly deleted before\n"
1751  <<"being used.";
1752  throw OomphLibError(error_message.str(),
1753  OOMPH_CURRENT_FUNCTION,
1754  OOMPH_EXCEPTION_LOCATION);
1755  }
1756 #endif
1757  return (*it).second.size();
1758  }
1759 
1760  /// \short Gets the vector of auxiliar polylines that will represent
1761  /// the given boundary (useful only when the boundaries were
1762  /// split)
1763  Vector<TriangleMeshPolyLine*> &boundary_subpolylines(const unsigned &b)
1764  {
1765  std::map<unsigned, Vector<TriangleMeshPolyLine*> >::iterator it;
1766  it = Boundary_subpolylines.find(b);
1767  if (it == Boundary_subpolylines.end())
1768  {
1769  std::ostringstream error_message;
1770  error_message
1771  <<"The boundary ("<<b<<") was marked as been splitted but there\n"
1772  <<"are not registered polylines to represent the boundary.\n"
1773  <<"The new polylines were not set up when the boundary was found to\n"
1774  <<"be splitted or the polylines have been explicitly deleted before\n"
1775  <<"being used.";
1776  throw OomphLibError(error_message.str(),
1777  OOMPH_CURRENT_FUNCTION,
1778  OOMPH_EXCEPTION_LOCATION);
1779  }
1780  return (*it).second;
1781  }
1782 
1783  /// \short Returns the value that indicates if a subpolyline of a
1784  /// given boundary continues been used as internal boundary or should
1785  /// be changed as shared boundary
1786  const bool boundary_marked_as_shared_boundary(const unsigned &b,
1787  const unsigned &isub)
1788  {
1789  std::map<unsigned, std::vector<bool> >::iterator it;
1790  it = Boundary_marked_as_shared_boundary.find(b);
1791  if (it == Boundary_marked_as_shared_boundary.end())
1792  {
1793  // If no info. was found for the shared boundary then it may be
1794  // a non internal boundary, so no shared boundaries are
1795  // overlaping it
1796  return false;
1797  }
1798  return (*it).second[isub];
1799  }
1800 
1801  /// The initial boundary id for shared boundaries
1803 
1804  /// The final boundary id for shared boundaries
1806 
1807  /// \short Stores the boundaries ids created by the interaction of two processors
1808  /// Shared_boundaries_ids[iproc][jproc] = Vector of shared boundaries ids
1809  /// "iproc" processor shares boundaries with "jproc" processor
1810  Vector<Vector<Vector<unsigned> > > Shared_boundaries_ids;
1811 
1812  /// \short Stores the processors involved in the generation of a shared
1813  /// boundary, in 2D two processors give rise to the creation of a
1814  /// shared boundary
1815  std::map<unsigned, Vector<unsigned> >Shared_boundary_from_processors;
1816 
1817  /// \short Stores information about those shared boundaries that lie over or
1818  /// over a segment of an internal boundary (only used when using
1819  /// internal boundaries in the domain)
1820  std::map<unsigned, unsigned> Shared_boundary_overlaps_internal_boundary;
1821 
1822  /// \short Stores the polyline representation of the shared boundaries
1823  /// Shared_boundary_polyline_pt[iproc][ncurve][npolyline] = polyline_pt
1824  Vector<Vector<Vector<TriangleMeshPolyLine*> > > Shared_boundary_polyline_pt;
1825 
1827  {Shared_boundary_polyline_pt.clear();}
1828 
1829  ///\short Stores the boundary elements adjacent to the shared boundaries, these
1830  /// elements are a subset of the halo and haloed elements
1831  std::map<unsigned, Vector<FiniteElement*> > Shared_boundary_element_pt;
1832 
1833  /// \short For the e-th finite element on shared boundary b, this is
1834  /// the index of the face that lies along that boundary
1835  std::map<unsigned, Vector<int> > Face_index_at_shared_boundary;
1836 
1837  /// \short Stores the boundary nodes adjacent to the shared boundaries, these
1838  /// nodes are a subset of the halo and haloed nodes
1839  std::map<unsigned, Vector<Node*> > Shared_boundary_node_pt;
1840 
1841  /// \short Flag to indicate if a polyline has been splitted during the distribution
1842  /// process, the boundary id of the polyline is used to indicate if spplited
1843  std::map<unsigned, bool> Boundary_was_splitted;
1844 
1845  /// \short The polylines that will temporary represent the boundary that was
1846  /// splitted in the distribution process. Used to ease the sending of
1847  /// info. to Triangle during the adaptation process.
1848  std::map<unsigned, Vector<TriangleMeshPolyLine*> > Boundary_subpolylines;
1849 
1850  ///\short Flag to indicate if an internal boundary will be used as shared boundary
1851  /// because there is overlapping of the internal boundary with the shared
1852  /// boundary
1853  std::map<unsigned, std::vector<bool> > Boundary_marked_as_shared_boundary;
1854 
1855  /// \short Creates the distributed domain representation. Joins the
1856  /// original boundaires, shared boundaries and creates connections among
1857  /// them to create the new polygons that represent the distributed
1858  /// domain
1859  void create_distributed_domain_representation(Vector<TriangleMeshPolygon *>
1860  &polygons_pt,
1861  Vector<TriangleMeshOpenCurve*>
1862  &open_curves_pt);
1863 
1864  /// \short Sorts the polylines so they be continuous and then we can
1865  /// create a closed or open curve from them
1866  void sort_polylines_helper(Vector<TriangleMeshPolyLine *>
1867  &unsorted_polylines_pt,
1868  Vector<Vector<TriangleMeshPolyLine *> >
1869  &sorted_polylines_pt);
1870 
1871  /// \short Take the polylines from the shared boundaries and create
1872  /// temporary polygon representations of the domain
1873  void create_tmp_polygons_helper(Vector<Vector<TriangleMeshPolyLine *> >
1874  &polylines_pt,
1875  Vector<TriangleMeshPolygon *> &polygons_pt);
1876 
1877  ///\short Take the polylines from the original open curves and created
1878  ///new temporaly representations of open curves with the bits of
1879  ///original curves not overlapped by shared boundaries
1880  void create_tmp_open_curves_helper(Vector<Vector<TriangleMeshPolyLine *> >
1881  &sorted_open_curves_pt,
1882  Vector<TriangleMeshPolyLine*>
1883  &unsorted_shared_to_internal_poly_pt,
1884  Vector<TriangleMeshOpenCurve *>
1885  &open_curves_pt);
1886 
1887  /// \short Flag to know if it is the first time we are going to compute the
1888  /// holes left by the halo elements
1890 
1891  /// Backup the original extra holes coordinates
1892  Vector<Vector<double> > Original_extra_holes_coordinates;
1893 
1894  /// \short Compute the holes left by the halo elements, those
1895  /// adjacent to the shared boundaries
1896  void compute_holes_left_by_halo_elements_helper(
1897  Vector<Vector<double> > &output_holes_coordinates);
1898 
1899  /// \short Keeps those vertices that define a hole, those that are
1900  /// inside closed internal boundaries in the new polygons that define the
1901  /// domain. Delete those outside/inside the outer polygons (this is
1902  /// required since Triangle can not deal with vertices that define
1903  /// holes outside the new outer polygons of the domain)
1904  void update_holes_information_helper(
1905  Vector<TriangleMeshPolygon *> &polygons_pt,
1906  Vector<Vector<double> > &output_holes_coordinates);
1907 
1908  /// \short Check for any possible connections that the array of
1909  /// sorted nodes have with any previous boundaries or with
1910  /// itself. Return -1 if no connection was found, return -2 if the
1911  /// connection is with the same polyline, return the boundary id of
1912  /// the boundary to which the connection is performed
1913  const int check_connections_of_polyline_nodes(
1914  std::set<FiniteElement*> &element_in_processor_pt,
1915  const int &root_edge_bnd_id,
1916  std::map<std::pair<Node*,Node*>, bool> &overlapped_face,
1917  std::map<unsigned, std::map<Node*, bool> >
1918  &node_on_bnd_not_overlapped_by_shd_bnd,
1919  std::list<Node*> &current_polyline_nodes,
1920  std::map<unsigned, std::list<Node*> >
1921  &shared_bnd_id_to_sorted_list_node_pt,
1922  const unsigned &node_degree,
1923  Node* &new_node_pt,
1924  const bool called_from_load_balance=false);
1925 
1926  /// \short Establish the connections of the polylines previously marked
1927  /// as having connections. This connections were marked in the function
1928  /// TriangleMesh::create_polylines_from_halo_elements_helper().
1929  void create_shared_polylines_connections();
1930 
1931  /// \short Creates the shared boundaries
1932  void create_shared_boundaries(OomphCommunicator* comm_pt,
1933  const Vector<unsigned> &element_domain,
1934  const Vector<GeneralisedElement*>
1935  &backed_up_el_pt,
1936  const Vector<FiniteElement*>
1937  &backed_up_f_el_pt,
1938  std::map<Data*,std::set<unsigned> >
1939  &processors_associated_with_data,
1940  const bool&
1941  overrule_keep_as_halo_element_status);
1942 
1943  /// \short Creates the halo elements on all processors
1944  /// Gets the halo elements on all processors, these elements are then used
1945  /// on the function that computes the shared boundaries among the processors
1946  void get_halo_elements_on_all_procs(const unsigned &nproc,
1947  const Vector<unsigned>
1948  &element_domain,
1949  const Vector<GeneralisedElement*>
1950  &backed_up_el_pt,
1951  std::map<Data*,std::set<unsigned> >
1952  &processors_associated_with_data,
1953  const bool&
1954  overrule_keep_as_halo_element_status,
1955  std::map<GeneralisedElement*, unsigned>
1956  &element_to_global_index,
1957  Vector<Vector<
1958  Vector<GeneralisedElement*> > >&
1959  output_halo_elements_pt);
1960 
1961  /// \short Get the element edges (pair of nodes, edges) that lie
1962  /// on a boundary (used to mark shared boundaries that lie on
1963  /// internal boundaries)
1964  void get_element_edges_on_boundary(std::map<std::pair<Node*,Node*>,
1965  unsigned> &element_edges_on_boundary);
1966 
1967  /// \short Creates polylines from the intersection of halo elements
1968  /// on all processors. The new polylines define the shared boundaries
1969  /// in the domain This get the polylines on ALL processors, that is
1970  /// why the three dimensions
1971  /// output_polylines_pt[iproc][ncurve][npolyline]
1972  void create_polylines_from_halo_elements_helper(
1973  const Vector<unsigned> &element_domain,
1974  std::map<GeneralisedElement*, unsigned> &element_to_global_index,
1975  std::set<FiniteElement*> &element_in_processor_pt,
1976  Vector<Vector<Vector<GeneralisedElement*> > > &input_halo_elements,
1977  std::map<std::pair<Node*,Node*>, unsigned> &elements_edges_on_boundary,
1978  Vector<Vector<Vector<TriangleMeshPolyLine *> > > &output_polylines_pt);
1979 
1980  /// \short Break any possible loop created by the sorted list of
1981  /// nodes that is used to create a new shared polyline
1982  void break_loops_on_shared_polyline_helper(
1983  const unsigned &initial_shd_bnd_id,
1984  std::list<Node*> &input_nodes,
1985  Vector<FiniteElement*> &input_boundary_element_pt,
1986  Vector<int> &input_face_index_element,
1987  const int &input_connect_to_the_left,
1988  const int &input_connect_to_the_right,
1989  Vector<std::list<Node*> > &output_sorted_nodes_pt,
1990  Vector<Vector<FiniteElement*> > &output_boundary_element_pt,
1991  Vector<Vector<int> > &output_face_index_element,
1992  Vector<int> &output_connect_to_the_left,
1993  Vector<int> &output_connect_to_the_right);
1994 
1995  /// \short Break any possible loop created by the sorted list of
1996  /// nodes that is used to create a new shared polyline (modified
1997  /// version for load balance)
1998  void break_loops_on_shared_polyline_load_balance_helper(
1999  const unsigned &initial_shd_bnd_id,
2000  std::list<Node*> &input_nodes,
2001  Vector<FiniteElement*> &input_boundary_element_pt,
2002  Vector<FiniteElement*> &input_boundary_face_element_pt,
2003  Vector<int> &input_face_index_element,
2004  const int &input_connect_to_the_left,
2005  const int &input_connect_to_the_right,
2006  Vector<std::list<Node*> > &output_sorted_nodes_pt,
2007  Vector<Vector<FiniteElement*> > &output_boundary_element_pt,
2008  Vector<Vector<FiniteElement*> > &output_boundary_face_element_pt,
2009  Vector<Vector<int> > &output_face_index_element,
2010  Vector<int> &output_connect_to_the_left,
2011  Vector<int> &output_connect_to_the_right);
2012 
2013  /// \short Create the shared polyline and fill the data structured
2014  /// that keep all the information associated with the creationg of the
2015  /// shared boundary
2016  void create_shared_polyline(const unsigned &my_rank,
2017  const unsigned &shd_bnd_id,
2018  const unsigned &iproc,
2019  const unsigned &jproc,
2020  std::list<Node*> &sorted_nodes,
2021  const int &root_edge_bnd_id,
2022  Vector<FiniteElement*>
2023  &bulk_bnd_ele_pt,
2024  Vector<int> &face_index_ele,
2025  Vector<Vector<TriangleMeshPolyLine *> >
2026  &unsorted_polylines_pt,
2027  const int &connect_to_the_left_flag,
2028  const int &connect_to_the_right_flag);
2029 
2030  public:
2031 
2032  /// Virtual function to perform the load balance routines
2033  virtual void load_balance(const Vector<unsigned>&
2034  target_domain_for_local_non_halo_element)
2035  {
2036  std::ostringstream error_stream;
2037  error_stream << "Empty default load balancing function called.\n";
2038  error_stream << "This should be overloaded in a specific "
2039  << "RefineableTriangleMesh\n";
2040  throw OomphLibError(error_stream.str(),
2041  OOMPH_CURRENT_FUNCTION,
2042  OOMPH_EXCEPTION_LOCATION);
2043  }
2044 
2045  /// Virtual function to perform the reset boundary elements info
2046  /// routines. Generally used after load balance.
2047  virtual void reset_boundary_element_info(
2048  Vector<unsigned> &ntmp_boundary_elements,
2049  Vector<Vector<unsigned> > &ntmp_boundary_elements_in_region,
2050  Vector<FiniteElement*> &deleted_elements);
2051 
2052 #endif // #ifdef OOMPH_HAS_MPI
2053 
2054 
2055  public:
2056 
2057  /// Output the nodes on the boundary and their respective boundary
2058  /// coordinates(into separate tecplot zones)
2059  void output_boundary_coordinates(const unsigned &b,
2060  std::ostream &outfile);
2061 
2062 
2063  private:
2064 
2065  // Reference :
2066  // http://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#C.2B.2B
2067 
2068  // Monotone chain 2D convex hull algorithm.
2069  // Asymptotic complexity: O(n log n).
2070  // Practical performance: 0.5-1.0 seconds for n=1000000 on a 1GHz machine.
2071  typedef double coord_t; // coordinate type
2072  typedef double coord2_t; // must be big enough to hold 2*max(|coordinate|)^2
2073 
2074  struct Point {
2075  coord_t x, y;
2076 
2077  bool operator <(const Point &p) const {
2078  return x < p.x || (x == p.x && y < p.y);
2079  }
2080  };
2081 
2082  /// \short 2D cross product of OA and OB vectors, i.e. z-component of their 3D
2083  /// cross product.
2084  /// Returns a positive value, if OAB makes a counter-clockwise turn,
2085  /// negative for clockwise turn, and zero if the points are collinear.
2086  coord2_t cross(const Point &O, const Point &A, const Point &B)
2087  {
2088  return (A.x - O.x) * (B.y - O.y) - (A.y - O.y) * (B.x - O.x);
2089  }
2090 
2091  /// \short Returns a list of points on the convex hull in counter-clockwise order.
2092  /// Note: the last point in the returned list is the same as the first one.
2093  std::vector<Point> convex_hull(std::vector<Point> P)
2094  {
2095  int n = P.size(), k = 0;
2096  std::vector<Point> H(2*n);
2097 
2098  // Sort points lexicographically
2099  std::sort(P.begin(), P.end());
2100 
2101  // Build lower hull
2102  for (int i = 0; i < n; ++i) {
2103  while (k >= 2 && cross(H[k-2], H[k-1], P[i]) <= 0) k--;
2104  H[k++] = P[i];
2105  }
2106 
2107  // Build upper hull
2108  for (int i = n-2, t = k+1; i >= 0; i--) {
2109  while (k >= t && cross(H[k-2], H[k-1], P[i]) <= 0) k--;
2110  H[k++] = P[i];
2111  }
2112 
2113  H.resize(k);
2114  return H;
2115  }
2116 
2117  };
2118 
2119 
2120 //////////////////////////////////////////////////////////////////////
2121 //////////////////////////////////////////////////////////////////////
2122 //////////////////////////////////////////////////////////////////////
2123 
2124 
2125 //=========================================================================
2126 /// Unstructured refineable Triangle Mesh
2127 //=========================================================================
2128 // Temporary flag to enable full annotation of RefineableTriangleMesh
2129 // comms
2130 //#define ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
2131  template<class ELEMENT>
2133  public virtual RefineableMeshBase
2134  {
2135 
2136  public:
2137 
2138  /// \short Function pointer to function that updates the
2139  /// mesh following the snapping of boundary nodes to the
2140  /// boundaries (e.g. to move boundary nodes very slightly
2141  /// to satisfy volume constraints)
2142  typedef void (*MeshUpdateFctPt)(Mesh* mesh_pt);
2143 
2144  /// \short Function pointer to a function that can generate
2145  /// a point within the ihole-th hole, so that this can be
2146  /// overloaded by the user if they have a better way of
2147  /// doing it than our clunky default. The function
2148  /// should update the components of the
2149  /// Vector poly_pt->internal_point()
2150  typedef void (*InternalHolePointUpdateFctPt)(
2151  const unsigned &ihole, TriangleMeshPolygon* poly_pt);
2152 
2153 #ifdef OOMPH_HAS_TRIANGLE_LIB
2154 
2155  /// \short Build mesh, based on the specifications on
2156  /// TriangleMeshParameters
2158  TimeStepper* time_stepper_pt=
2159  &Mesh::Default_TimeStepper)
2160  : TriangleMesh<ELEMENT>(triangle_mesh_parameters,
2161  time_stepper_pt)
2162  {
2163  // Initialise the data associated with adaptation
2164  initialise_adaptation_data();
2165 
2166  // Initialise the data associated with boundary refinements
2167  initialise_boundary_refinement_data();
2168  }
2169 
2170 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB
2171 
2172  /// \short Build mesh, based on the polyfiles
2173  RefineableTriangleMesh(const std::string& node_file_name,
2174  const std::string& element_file_name,
2175  const std::string& poly_file_name,
2176  TimeStepper* time_stepper_pt=
2177  &Mesh::Default_TimeStepper,
2178  const bool &allow_automatic_creation_of_vertices_on_boundaries=true)
2179  : TriangleMesh<ELEMENT>(node_file_name,
2180  element_file_name,
2181  poly_file_name,
2182  time_stepper_pt,
2183  allow_automatic_creation_of_vertices_on_boundaries)
2184  {
2185  // Create and fill the data structures to give rise to polylines so that
2186  // the mesh can use the adapt methods
2187  create_polylines_from_polyfiles(node_file_name, poly_file_name);
2188 
2189  // Initialise the data associated with adaptation
2190  initialise_adaptation_data();
2191 
2192  // Initialise the data associated with boundary refinements
2193  initialise_boundary_refinement_data();
2194  }
2195 
2196  protected:
2197 
2198 #ifdef OOMPH_HAS_TRIANGLE_LIB
2199 
2200  /// \short Build mesh from specified triangulation and
2201  /// associated target areas for elements in it
2202  /// NOTE: This is used ONLY during adaptation and should not be used
2203  /// as a method of constructing a TriangleMesh object in demo drivers!
2204  RefineableTriangleMesh(const Vector<double> &target_area,
2205  TriangulateIO& triangulate_io,
2206  TimeStepper* time_stepper_pt=
2207  &Mesh::Default_TimeStepper,
2208  const bool &use_attributes=false,
2209  const bool
2210  &allow_automatic_creation_of_vertices_on_boundaries=true,
2211  OomphCommunicator* comm_pt = 0)
2212  {
2213  // Initialise the data associated with adaptation
2214  initialise_adaptation_data();
2215 
2216  // Initialise the data associated with boundary refinements
2217  initialise_boundary_refinement_data();
2218 
2219  // Store Timestepper used to build elements
2220  this->Time_stepper_pt=time_stepper_pt;
2221 
2222  // Create triangulateio object to refine
2223  TriangulateIO triangle_refine;
2224 
2225  // Initialize triangulateio structure
2226  TriangleHelper::initialise_triangulateio(this->Triangulateio);
2227 
2228  // Triangulation has been created -- remember to wipe it!
2229  this->Triangulateio_exists=true;
2230 
2231  // Create refined TriangulateIO structure based on target areas
2232  this->refine_triangulateio(triangulate_io,
2233  target_area,
2234  triangle_refine);
2235 
2236  // Input string for triangle
2237  std::stringstream input_string_stream;
2238  input_string_stream<<"-pq30-ra";
2239 
2240  // Verify if creation of new points on boundaries is allowed
2241  if (!allow_automatic_creation_of_vertices_on_boundaries)
2242  {input_string_stream<<" -YY";}
2243 
2244  // Copy the allowing of creation of points on the boundaries status
2246  allow_automatic_creation_of_vertices_on_boundaries;
2247 
2248  //Store the attribute flag
2249  this->Use_attributes=use_attributes;
2250 
2251  // Convert to a *char required by the triangulate function
2252  char triswitches[100];
2253  sprintf(triswitches,"%s",input_string_stream.str().c_str());
2254 
2255  // Build triangulateio refined object
2256  triangulate(triswitches,&triangle_refine,&this->Triangulateio,0);
2257 
2258  // Build scaffold
2259  this->Tmp_mesh_pt=new TriangleScaffoldMesh(this->Triangulateio);
2260 
2261  // Convert mesh from scaffold to actual mesh
2262  this->build_from_scaffold(time_stepper_pt,use_attributes);
2263 
2264  // Kill the scaffold
2265  delete this->Tmp_mesh_pt;
2266  this->Tmp_mesh_pt=0;
2267 
2268  // Cleanup but leave hole alone as it's still used
2269  bool clear_hole_data=false;
2270  TriangleHelper::clear_triangulateio(triangle_refine,clear_hole_data);
2271 
2272 #ifdef OOMPH_HAS_MPI
2273  // Before calling setup boundary coordinates check if the mesh
2274  // should be treated as a distributed mesh
2275  if (comm_pt!=0)
2276  {
2277  // Set the communicator which will mark the mesh as distributed
2278  this->set_communicator_pt(comm_pt);
2279  }
2280 #endif
2281 
2282  // Setup boundary coordinates for boundaries
2283  unsigned nb=nboundary();
2284  for (unsigned b=0;b<nb;b++)
2285  {
2286  this->template setup_boundary_coordinates<ELEMENT>(b);
2287  }
2288  }
2289 
2290  public:
2291 
2292 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB
2293 
2294  /// Empty Destructor
2296 
2297  /// \short Enables info. and timings for tranferring of target
2298  /// areas
2300  {Print_timings_transfering_target_areas=true;}
2301 
2302  /// \short Disables info. and timings for tranferring of target
2303  /// areas
2305  {Print_timings_transfering_target_areas=false;}
2306 
2307  /// \short Enables the solution projection step during adaptation
2309  {Disable_projection=false;}
2310 
2311  /// \short Disables the solution projection step during adaptation
2313  {Disable_projection=true;}
2314 
2315  /// \short Enables info. and timings for projection
2317  {Print_timings_projection=true;}
2318 
2319  /// \short Disables info. and timings for projection
2321  {Print_timings_projection=false;}
2322 
2323  /// \short Read/write access to number of bins in the x-direction
2324  /// when transferring target areas by bin method. Only used if we
2325  /// don't have CGAL!
2326  unsigned& nbin_x_for_area_transfer(){return Nbin_x_for_area_transfer;}
2327 
2328  /// \short Read/write access to number of bins in the y-direction
2329  /// when transferring target areas by bin method. Only used if we
2330  /// don't have CGAL!
2331  unsigned& nbin_y_for_area_transfer(){return Nbin_y_for_area_transfer;}
2332 
2333  /// \short Read/write access to number of sample points from which
2334  /// we try to locate zeta by Newton method when transferring target areas
2335  /// using cgal-based sample point container. If Newton method doesn't
2336  /// converge from any of these we use the nearest sample point.
2338  {
2339  return Max_sample_points_for_limited_locate_zeta_during_target_area_transfer;
2340  }
2341 
2342  /// Max element size allowed during adaptation
2343  double& max_element_size(){return Max_element_size;}
2344 
2345  /// Min element size allowed during adaptation
2346  double& min_element_size(){return Min_element_size;}
2347 
2348  /// Min angle before remesh gets triggered
2349  double& min_permitted_angle(){return Min_permitted_angle;}
2350 
2351  // Returns the status of using an iterative solver for the
2352  // projection problem
2354  {return Use_iterative_solver_for_projection;}
2355 
2356  /// Enables the use of an iterative solver for the projection
2357  /// problem
2359  {Use_iterative_solver_for_projection=true;}
2360 
2361  /// Enables the use of an iterative solver for the projection
2362  /// problem
2364  {Use_iterative_solver_for_projection=false;}
2365 
2366  /// Enables printing of timings for adaptation
2367  void enable_print_timings_adaptation(const unsigned &print_level=1)
2368  {set_print_level_timings_adaptation(print_level);}
2369 
2370  /// Disables printing of timings for adaptation
2372  {Print_timings_level_adaptation=0;}
2373 
2374  /// Sets the printing level of timings for adaptation
2375  void set_print_level_timings_adaptation(const unsigned &print_level)
2376  {
2377  const unsigned max_print_level = 3;
2378  // If printing level is greater than max. printing level
2379  if (print_level > max_print_level)
2380  {
2381  Print_timings_level_adaptation=max_print_level;
2382  }
2383  else
2384  {
2385  Print_timings_level_adaptation=print_level;
2386  }
2387  }
2388 
2389  /// Enables printing of timings for load balance
2390  void enable_print_timings_load_balance(const unsigned &print_level=1)
2391  {set_print_level_timings_load_balance(print_level);}
2392 
2393  /// Disables printing of timings for load balance
2395  {Print_timings_level_load_balance=0;}
2396 
2397  /// Sets the printing level of timings for load balance
2398  void set_print_level_timings_load_balance(const unsigned &print_level)
2399  {
2400  const unsigned max_print_level = 3;
2401  // If printing level is greater than max. printing level
2402  if (print_level > max_print_level)
2403  {
2404  Print_timings_level_load_balance=max_print_level;
2405  }
2406  else
2407  {
2408  Print_timings_level_load_balance=print_level;
2409  }
2410  }
2411 
2412  /// Doc the targets for mesh adaptation
2413  void doc_adaptivity_targets(std::ostream &outfile)
2414  {
2415  outfile << std::endl;
2416  outfile << "Targets for mesh adaptation: " << std::endl;
2417  outfile << "---------------------------- " << std::endl;
2418  outfile << "Target for max. error: " << Max_permitted_error << std::endl;
2419  outfile << "Target for min. error: " << Min_permitted_error << std::endl;
2420  outfile << "Target min angle: " << Min_permitted_angle << std::endl;
2421  outfile << "Min. allowed element size: " << Min_element_size << std::endl;
2422  outfile << "Max. allowed element size: " << Max_element_size << std::endl;
2423  outfile << "Don't unrefine if less than " << Max_keep_unrefined
2424  << " elements need unrefinement." << std::endl;
2425  outfile << std::endl;
2426  }
2427 
2428  /// Refine mesh uniformly and doc process
2429  void refine_uniformly(DocInfo& doc_info)
2430  {
2431  // Set the element error to something big
2432  unsigned nelem=nelement();
2433  Vector<double> elem_error(nelem,DBL_MAX);
2434 
2435  // Limit the min element size to 1/3 of the current minimum
2436  double backup=Min_element_size;
2437 
2438  // Get current max and min element size
2439  double orig_max_area, orig_min_area;
2440  this->max_and_min_element_size(orig_max_area, orig_min_area);
2441 
2442  // Limit
2443  Min_element_size=orig_min_area/3.0;
2444 
2445  // Do it...
2446  adapt(elem_error);
2447 
2448  // Reset
2449  Min_element_size=backup;
2450  }
2451 
2452  /// \short Unrefine mesh uniformly: Return 0 for success,
2453  /// 1 for failure (if unrefinement has reached the coarsest permitted
2454  /// level)
2456  {
2457  throw OomphLibError("unrefine_uniformly() not implemented yet",
2458  OOMPH_CURRENT_FUNCTION,
2459  OOMPH_EXCEPTION_LOCATION);
2460  // dummy return
2461  return 0;
2462  }
2463 
2464  /// Adapt mesh, based on elemental error provided
2465  void adapt(const Vector<double>& elem_error);
2466 
2467  /// \short Access to function pointer to function that updates the
2468  /// mesh following the snapping of boundary nodes to the
2469  /// boundaries (e.g. to move boundary nodes very slightly
2470  /// to satisfy volume constraints)
2471  MeshUpdateFctPt& mesh_update_fct_pt()
2472  {
2473  return Mesh_update_fct_pt;
2474  }
2475 
2476  /// \short Access to function pointer to can be
2477  /// used to generate the internal point for the ihole-th
2478  ///hole.
2479  InternalHolePointUpdateFctPt& internal_hole_point_update_fct_pt()
2480  {
2481  return Internal_hole_point_update_fct_pt;
2482  }
2483 
2484 
2485 
2486 
2487 #ifdef OOMPH_HAS_MPI
2488  unsigned nsorted_shared_boundary_node(unsigned &b)
2489  {
2490  std::map<unsigned, Vector<Node*> >::iterator it =
2491  Sorted_shared_boundary_node_pt.find(b);
2492  if (it == Sorted_shared_boundary_node_pt.end())
2493  {
2494  std::ostringstream error_message;
2495  error_message
2496  <<"The boundary ("<<b<<") is not marked as shared\n";
2497  throw OomphLibError(error_message.str(),
2498  OOMPH_CURRENT_FUNCTION,
2499  OOMPH_EXCEPTION_LOCATION);
2500  }
2501  return (*it).second.size();
2502  }
2503 
2505  {Sorted_shared_boundary_node_pt.clear();}
2506 
2507  Node* sorted_shared_boundary_node_pt(unsigned &b, unsigned &i)
2508  {
2509  std::map<unsigned, Vector<Node*> >::iterator it =
2510  Sorted_shared_boundary_node_pt.find(b);
2511  if (it == Sorted_shared_boundary_node_pt.end())
2512  {
2513  std::ostringstream error_message;
2514  error_message
2515  <<"The boundary ("<<b<<") is not marked as shared\n";
2516  throw OomphLibError(error_message.str(),
2517  OOMPH_CURRENT_FUNCTION,
2518  OOMPH_EXCEPTION_LOCATION);
2519  }
2520  return (*it).second[i];
2521  }
2522 
2523 
2524  Vector<Node*> sorted_shared_boundary_node_pt(unsigned &b)
2525  {
2526  std::map<unsigned, Vector<Node*> >::iterator it =
2527  Sorted_shared_boundary_node_pt.find(b);
2528  if (it == Sorted_shared_boundary_node_pt.end())
2529  {
2530  std::ostringstream error_message;
2531  error_message
2532  <<"The boundary ("<<b<<") is not marked as shared\n";
2533  throw OomphLibError(error_message.str(),
2534  OOMPH_CURRENT_FUNCTION,
2535  OOMPH_EXCEPTION_LOCATION);
2536  }
2537  return (*it).second;
2538  }
2539 
2540 #endif // #ifdef OOMPH_HAS_MPI
2541 
2542  /// Helper function to create polylines and fill associate data
2543  // structures, used when creating from a mesh from polyfiles
2544  void create_polylines_from_polyfiles(const std::string& node_file_name,
2545  const std::string& poly_file_name);
2546 
2547 #ifdef OOMPH_HAS_MPI
2548  // \short Fill the boundary elements structures when dealing with
2549  // shared boundaries that overlap internal boundaries
2550  void fill_boundary_elements_and_nodes_for_internal_boundaries();
2551 
2552  // \short Fill the boundary elements structures when dealing with
2553  // shared boundaries that overlap internal boundaries. Document the
2554  // number of elements on the shared boundaries that go to internal
2555  // boundaries
2556  void fill_boundary_elements_and_nodes_for_internal_boundaries(
2557  std::ofstream& outfile);
2558 
2559  /// Used to re-establish any additional info. related with
2560  /// the distribution after a re-starting for triangle meshes
2562  OomphCommunicator* comm_pt, std::istream &restart_file)
2563  {
2564  // Ensure that the mesh is distributed
2565  if (this->is_mesh_distributed())
2566  {
2567  // Fill the structures for the boundary elements and face indexes
2568  // of the boundary elements
2569  this->fill_boundary_elements_and_nodes_for_internal_boundaries();
2570 
2571  // Re-establish the shared boundary elements and nodes scheme
2572  // before re-establish halo and haloed elements
2573  this->reset_shared_boundary_elements_and_nodes(comm_pt);
2574 
2575  // Sort the nodes on the boundaries so that they have the same order
2576  // on all the boundaries
2577  this->sort_nodes_on_shared_boundaries();
2578 
2579  // Re-establish the halo(ed) scheme
2580  this->reset_halo_haloed_scheme();
2581 
2582  // Re-set the number of boundaries to the original one
2583  const unsigned noriginal_boundaries =
2584  this->initial_shared_boundary_id();
2585  this->set_nboundary(noriginal_boundaries);
2586 
2587  // Go through the original boudaries and re-establish the
2588  // boundary coordinates
2589  for (unsigned b = 0; b < noriginal_boundaries; b++)
2590  {
2591  // Identify the segment boundaries and re-call the
2592  // setup_boundary_coordinates() method for the new boundaries
2593  // from restart
2594  this->identify_boundary_segments_and_assign_initial_zeta_values(b, this);
2595 
2596  if (this->boundary_geom_object_pt(b) != 0)
2597  {
2598  // Re-set the boundary coordinates
2599  this->template setup_boundary_coordinates<ELEMENT>(b);
2600  }
2601  }
2602 
2603  //Deform the boundary onto any geometric objects
2604  this->snap_nodes_onto_geometric_objects();
2605 
2606  } // if (this->is_mesh_distributed())
2607 
2608  }
2609 
2610 #endif // #ifdef OOMPH_HAS_MPI
2611 
2612  /// Method used to update the polylines representation after restart
2614  {
2615 #ifdef OOMPH_HAS_MPI
2616  // If the mesh is distributed then also update the shared
2617  // boundaries
2618  unsigned my_rank = 0;
2619  if (this->is_mesh_distributed())
2620  {
2621  my_rank = this->communicator_pt()->my_rank();
2622  }
2623 #endif
2624 
2625  // Update the polyline representation after restart
2626 
2627  // First update all internal boundaries
2628  const unsigned ninternal = this->Internal_polygon_pt.size();
2629  for (unsigned i_internal = 0; i_internal < ninternal; i_internal++)
2630  {
2631  this->update_polygon_after_restart(
2632  this->Internal_polygon_pt[i_internal]);
2633  }
2634 
2635  // then update the external boundaries
2636  const unsigned nouter = this->Outer_boundary_pt.size();
2637  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
2638  {
2639  this->update_polygon_after_restart(this->Outer_boundary_pt[i_outer]);
2640  }
2641 
2642 #ifdef OOMPH_HAS_MPI
2643  // If the mesh is distributed then also update the shared
2644  // boundaries
2645  if (this->is_mesh_distributed())
2646  {
2647  const unsigned ncurves = this->nshared_boundary_curves(my_rank);
2648  for (unsigned nc = 0; nc < ncurves; nc ++)
2649  {
2650  // Update the shared polyline
2651  this->update_shared_curve_after_restart(
2652  this->Shared_boundary_polyline_pt[my_rank][nc]//shared_curve
2653  );
2654  }
2655 
2656  } // if (this->is_mesh_distributed())
2657 #endif // #ifdef OOMPH_HAS_MPI
2658 
2659  const unsigned n_open_polyline = this->Internal_open_curve_pt.size();
2660  for (unsigned i = 0; i < n_open_polyline; i++)
2661  {
2662  this->update_open_curve_after_restart(
2663  this->Internal_open_curve_pt[i]);
2664  }
2665 
2666  }
2667 
2668 #ifdef OOMPH_HAS_MPI
2669 
2670  /// \short Performs the load balancing for unstructured meshes, the
2671  /// load balancing strategy is based on mesh migration
2672  void load_balance(const Vector<unsigned>&
2673  input_target_domain_for_local_non_halo_element);
2674 
2675  /// \short Use the first and second group of elements to find the
2676  /// intersection between them to get the shared boundary
2677  /// elements from the first and second group
2678  void get_shared_boundary_elements_and_face_indexes(
2679  const Vector<FiniteElement*> &first_element_pt,
2680  const Vector<FiniteElement*> &second_element_pt,
2681  Vector<FiniteElement*> &first_shared_boundary_element_pt,
2682  Vector<unsigned> &first_shared_boundary_element_face_index,
2683  Vector<FiniteElement*> &second_shared_boundary_element_pt,
2684  Vector<unsigned> &second_shared_boundary_element_face_index);
2685 
2686  /// \short Creates the new shared boundaries, this method is also in
2687  /// charge of computing the shared boundaries ids of each processor
2688  /// and send that info. to all the processors
2689  void create_new_shared_boundaries(std::set<FiniteElement*>
2690  &element_in_processor_pt,
2691  Vector<Vector<FiniteElement*> >
2692  &new_shared_boundary_element_pt,
2693  Vector<Vector<unsigned> >
2694  &new_shared_boundary_element_face_index);
2695 
2696  /// \short Computes the degree of the nodes on the shared boundaries, the
2697  /// degree of the node is computed from the global graph created by the
2698  /// shared boundaries of all processors
2699  void compute_shared_node_degree_helper(Vector<Vector<FiniteElement*> >
2700  &unsorted_face_ele_pt,
2701  std::map<Node*, unsigned>
2702  &global_node_degree);
2703 
2704  /// \short Sort the nodes on the new shared boundaries (after load balancing),
2705  /// computes the alias of the nodes and creates the adjacency matrix
2706  /// that represent the graph created by the shared edges between each
2707  /// pair of processors
2708  void create_adjacency_matrix_new_shared_edges_helper(
2709  Vector<Vector<FiniteElement*> > &unsorted_face_ele_pt,
2710  Vector<Vector<Node*> > &tmp_sorted_shared_node_pt,
2711  std::map<Node*, Vector<Vector<unsigned> > > &node_alias,
2712  Vector<Vector<Vector<unsigned> > > &adjacency_matrix);
2713 
2714  /// \short Get the nodes on the shared boundary (b), these are stored
2715  /// in the segment they belong
2716  void get_shared_boundary_segment_nodes_helper(
2717  const unsigned &shd_bnd_id, Vector<Vector<Node*> > &tmp_segment_nodes);
2718 
2719 #endif // #ifdef OOMPH_HAS_MPI
2720 
2721  /// \short Get the nodes on the boundary (b), these are stored in
2722  /// the segment they belong (also used by the load balance method
2723  /// to re-set the number of segments per boundary after load
2724  /// balance has taken place)
2725  void get_boundary_segment_nodes_helper(
2726  const unsigned &b, Vector<Vector<Node*> > &tmp_segment_nodes);
2727 
2728  /// \short Enable/disable unrefinement/refinement methods for original
2729  /// boundaries
2731  {Do_boundary_unrefinement_constrained_by_target_areas = true;}
2732 
2734  {Do_boundary_unrefinement_constrained_by_target_areas = false;}
2735 
2737  {Do_boundary_refinement_constrained_by_target_areas = true;}
2738 
2740  {Do_boundary_refinement_constrained_by_target_areas = false;}
2741 
2742  /// \short Enable/disable unrefinement/refinement methods for shared
2743  /// boundaries
2745  {Do_shared_boundary_unrefinement_constrained_by_target_areas = true;}
2746 
2748  {Do_shared_boundary_unrefinement_constrained_by_target_areas = false;}
2749 
2751  {Do_shared_boundary_refinement_constrained_by_target_areas = true;}
2752 
2754  {Do_shared_boundary_refinement_constrained_by_target_areas = false;}
2755 
2756 
2757  protected:
2758 
2759  /// \short A map that stores the vertices that receive connections, they
2760  /// are identified by the boundary number that receive the connection
2761  /// This is necessary for not erasing them on the adaptation process,
2762  /// specifically for the un-refinement process
2763  std::map<unsigned, std::set<Vector<double> > > Boundary_connections_pt;
2764 
2765  /// \short Verifies if the given boundary receives a connection, and
2766  /// if that is the case then returns the list of vertices that
2767  /// receive the connections
2768  const bool boundary_connections(const unsigned &b,
2769  const unsigned &c,
2770  std::set<Vector<double> > &vertices)
2771  {
2772  // Search for the given boundary
2773  std::map<unsigned, std::set<Vector<double> > >::
2774  iterator it = Boundary_connections_pt.find(b);
2775  // Was the boundary found?
2776  if (it != Boundary_connections_pt.end())
2777  {
2778  // Return the set of vertices that receive the connection
2779  vertices = (*it).second;
2780  return true;
2781  }
2782  else
2783  {
2784  return false;
2785  }
2786 
2787  }
2788 
2789  /// \short Synchronise the vertices that are marked for non deletion
2790  // on the shared boundaries. Unrefinement of shared boundaries is
2791  // performed only if the candidate node is not marked for non deletion
2792  const void synchronize_shared_boundary_connections();
2793 
2794  /// \short Mark the vertices that are not allowed for deletion by
2795  /// the unrefienment/refinement polyline methods. In charge of
2796  /// filling the Boundary_chunk_connections_pt structure
2797  void add_vertices_for_non_deletion();
2798 
2799  /// \short Adds the vertices from the sources boundary that are
2800  /// repeated in the destination boundary to the list of non
2801  /// delete-able vertices in the destination boundary
2802  void add_non_delete_vertices_from_boundary_helper(
2803  Vector<Vector<Node*> > src_bound_segment_node_pt,
2804  Vector<Vector<Node*> > dst_bound_segment_node_pt,
2805  const unsigned &dst_bnd_id, const unsigned &dst_bnd_chunk);
2806 
2807  /// \short After unrefinement and refinement has taken place compute
2808  /// the new vertices numbers of the temporary representation of the
2809  // boundaries to connect.
2810  void create_temporary_boundary_connections(
2811  Vector<TriangleMeshPolygon *> &tmp_outer_polygons_pt,
2812  Vector<TriangleMeshOpenCurve *> &tmp_open_curves_pt);
2813 
2814  /// \short After unrefinement and refinement has taken place compute
2815  /// the new vertices numbers of the boundaries to connect (in a
2816  /// distributed scheme it may be possible that the destination boundary
2817  /// does no longer exist, therefore the connection is suspended and
2818  /// resumed after the adaptation processor
2819  void restore_boundary_connections(
2820  Vector<TriangleMeshPolyLine*> &resume_initial_connection_polyline_pt,
2821  Vector<TriangleMeshPolyLine*> &resume_final_connection_polyline_pt);
2822 
2823  /// \short Restore the connections of the specific polyline
2824  /// The vertices numbering on the destination boundaries may have
2825  /// change because of (un)refinement in the destination boundaries.
2826  /// Also deals with connection that do not longer exist because the
2827  /// destination boundary does no longer exist because of the distribution
2828  /// process
2829  void restore_polyline_connections_helper(
2830  TriangleMeshPolyLine* polyline_pt,
2831  Vector<TriangleMeshPolyLine*> &resume_initial_connection_polyline_pt,
2832  Vector<TriangleMeshPolyLine*> &resume_final_connection_polyline_pt);
2833 
2834  /// \short Resume the boundary connections that may have been
2835  /// suspended because the destination boundary is no part of the
2836  /// domain. The connections are no permanently suspended because if
2837  /// load balance takes place the destination boundary may be part of
2838  /// the new domain representation therefore the connection would
2839  /// exist
2840  void resume_boundary_connections(
2841  Vector<TriangleMeshPolyLine*> &resume_initial_connection_polyline_pt,
2842  Vector<TriangleMeshPolyLine*> &resume_final_connection_polyline_pt);
2843 
2844  /// \short Computes the associated vertex number on the destination
2845  /// boundary
2846  bool get_connected_vertex_number_on_dst_boundary(
2847  Vector<double> &vertex_coordinates,
2848  const unsigned &dst_b_id, unsigned &vertex_number);
2849 
2850  /// \short Helper function that performs the unrefinement process
2851  // on the specified boundary by using the provided vertices
2852  /// representation. Optional boolean is used to run it as test only (if
2853  /// true is specified as input) in which case vertex coordinates aren't
2854  /// actually modified. Returned boolean indicates if polyline was (or
2855  /// would have been -- if called with check_only=false) changed.
2856  bool unrefine_boundary(const unsigned &b,
2857  const unsigned &c,
2858  Vector<Vector<double> > &vector_bnd_vertices,
2859  double &unrefinement_tolerance,
2860  const bool &check_only = false);
2861 
2862  /// \short Helper function that performs the refinement process
2863  /// on the specified boundary by using the provided vertices
2864  /// representation. Optional boolean is used to run it as test only (if
2865  /// true is specified as input) in which case vertex coordinates aren't
2866  /// actually modified. Returned boolean indicates if polyline was (or
2867  /// would have been -- if called with check_only=false) changed.
2868  bool refine_boundary(Mesh* face_mesh_pt,
2869  Vector<Vector<double> > &vector_bnd_vertices,
2870  double &refinement_tolerance,
2871  const bool &check_only = false);
2872 
2873  // \short Helper function that applies the maximum length constraint
2874  // when it was specified. This will increase the number of points in
2875  // the current curve section in case that any segment on it does not
2876  // fulfils the requirement
2877  bool apply_max_length_constraint(Mesh* face_mesh_pt,
2878  Vector<Vector<double> >
2879  &vector_bnd_vertices,
2880  double &max_length_constraint);
2881 
2882  /// \short Helper function that performs the unrefinement process on
2883  /// the specified boundary by using the provided vertices
2884  /// representation and the associated target area. Used only when the
2885  /// 'allow_automatic_creation_of_vertices_on_boundaries' flag is set to
2886  /// true.
2887  bool unrefine_boundary_constrained_by_target_area(
2888  const unsigned &b, const unsigned &c,
2889  Vector<Vector<double> > &vector_bnd_vertices,
2890  double &unrefinement_tolerance, Vector<double> &area_constraint);
2891 
2892  /// \short Helper function that performs the refinement process on
2893  /// the specified boundary by using the provided vertices
2894  /// representation and the associated elements target area. Used
2895  /// only when the 'allow_automatic_creation_of_vertices_on_boundaries'
2896  /// flag is set to true.
2897  bool refine_boundary_constrained_by_target_area(
2898  MeshAsGeomObject* mesh_geom_obj_pt,
2899  Vector<Vector<double> > &vector_bnd_vertices,
2900  double &refinement_tolerance, Vector<double> &area_constraint);
2901 
2902  /// \short Helper function that performs the unrefinement process
2903  /// on the specified boundary by using the provided vertices
2904  /// representation and the associated target area.
2905  /// NOTE: This is the version that applies unrefinement to shared
2906  /// boundaries
2907  bool unrefine_shared_boundary_constrained_by_target_area(
2908  const unsigned &b, const unsigned &c,
2909  Vector<Vector<double> > &vector_bnd_vertices,
2910  Vector<double> &area_constraint);
2911 
2912  /// \short Helper function that performs the refinement process
2913  /// on the specified boundary by using the provided vertices
2914  /// representation and the associated elements target area.
2915  /// NOTE: This is the version that applies refinement to shared
2916  /// boundaries
2917  bool refine_shared_boundary_constrained_by_target_area(
2918  Vector<Vector<double> > &vector_bnd_vertices,
2919  Vector<double> &area_constraint);
2920 
2921  /// Flag that enables or disables boundary unrefinement (true by default)
2923 
2924  /// Flag that enables or disables boundary refinement (true by default)
2926 
2927  /// Flag that enables or disables boundary unrefinement (true by default)
2929 
2930  /// Flag that enables or disables boundary unrefinement (true by default)
2932 
2933  /// Set all the flags to true (the default values)
2935  {
2936  // All boundaries refinement and unrefinement are allowed by
2937  // default
2938  Do_boundary_unrefinement_constrained_by_target_areas = true;
2939  Do_boundary_refinement_constrained_by_target_areas = true;
2940  Do_shared_boundary_unrefinement_constrained_by_target_areas = true;
2941  Do_shared_boundary_refinement_constrained_by_target_areas = true;
2942  }
2943 
2944 #ifdef OOMPH_HAS_MPI
2945  /// \short Stores the nodes in the boundaries in the same order in all the
2946  /// processors
2947  /// Sorted_shared_boundary_node_pt[bnd_id][i-th node] = Node*
2948  /// It is a map since the boundary id may not start at zero
2949  std::map<unsigned, Vector<Node*> > Sorted_shared_boundary_node_pt;
2950 
2951  /// \short Sort the nodes on shared boundaries so that the processors
2952  /// that share a boundary agree with the order of the nodes on the
2953  /// boundary
2954  void sort_nodes_on_shared_boundaries();
2955 
2956  /// \short Re-establish the shared boundary elements after the
2957  /// adaptation process (the updating of shared nodes is optional and
2958  /// performed by default)
2959  void reset_shared_boundary_elements_and_nodes(const bool flush_elements
2960  = true,
2961  const bool update_elements
2962  = true,
2963  const bool flush_nodes
2964  = true,
2965  const bool update_nodes
2966  = true);
2967 
2968  /// \short In charge of. re-establish the halo(ed) scheme on all processors.
2969  /// Sends info. to create halo elements and nodes on the processors
2970  /// that need it. It uses and all to all communication strategy therefore
2971  /// must be called on all processors.
2972  void reset_halo_haloed_scheme();
2973 
2974  /// \short Compute the names of the nodes on shared boundaries in
2975  /// this (my_rank) processor with other processors. Also compute the
2976  /// names of nodes on shared boundaries of other processors with
2977  /// other processors (useful when there is an element that requires
2978  /// to be sent to this (my_rank) processor because there is a shared
2979  /// node between this (my_rank) and other processors BUT there is
2980  /// not a shared boundary between this and the other processor
2981  void compute_global_node_names_and_shared_nodes(
2982  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
2983  &other_proc_shd_bnd_node_pt,
2984  Vector<Vector<Vector<unsigned> > > &global_node_names,
2985  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
2986  Vector<Node*> &global_shared_node_pt);
2987 
2988  /// \short Get the original boundaries to which is associated each
2989  /// shared node, and send the info. to the related processors. We
2990  /// need to do this so that at the reset of halo(ed) info. stage,
2991  /// the info. be already updated.
2992  void send_boundary_node_info_of_shared_nodes(
2993  Vector<Vector<Vector<unsigned> > > &global_node_names,
2994  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
2995  Vector<Node*> &global_shared_node_pt);
2996 
2997  /// \short In charge of creating additional halo(ed) elements on
2998  /// those processors that have no shared boundaries in common but have
2999  /// shared nodes
3000  void reset_halo_haloed_scheme_helper(
3001  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
3002  &other_proc_shd_bnd_node_pt,
3003  Vector<Vector<Node *> > &iproc_currently_created_nodes_pt,
3004  Vector<Vector<Vector<unsigned> > > &global_node_names,
3005  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
3006  Vector<Node*> &global_shared_node_pt);
3007 
3008  // ====================================================================
3009  // Methods for load balancing
3010  // ====================================================================
3011 
3012 //#define ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
3013 
3014  // *********************************************************************
3015  // BEGIN: Methods to perform load balance
3016  // *********************************************************************
3017 
3018  /// \short Check if necessary to add the element to the new domain or if it has
3019  /// been previously added
3021  Vector<FiniteElement*> &new_elements_on_domain,
3022  FiniteElement* &ele_pt)
3023  {
3024  // Get the number of elements currently added to the new domain
3025  const unsigned nnew_elements_on_domain = new_elements_on_domain.size();
3026 
3027  // Flag to state if has been added or not
3028  bool already_on_new_domain = false;
3029  unsigned new_domain_ele_index = 0;
3030 
3031  for (unsigned e = 0; e < nnew_elements_on_domain; e++)
3032  {
3033  if (ele_pt == new_elements_on_domain[e])
3034  {
3035  // It's already there, so...
3036  already_on_new_domain = true;
3037  // ...set the index of this element
3038  new_domain_ele_index = e;
3039  break;
3040  }
3041  }
3042 
3043  // Has it been found?
3044  if (!already_on_new_domain)
3045  {
3046  // Not found, so add it:
3047  new_elements_on_domain.push_back(ele_pt);
3048  // Return the index where it's just been added
3049  return nnew_elements_on_domain;
3050  }
3051  else
3052  {
3053  // Return the index where it was found
3054  return new_domain_ele_index;
3055  }
3056 
3057  }
3058 
3059  /// \short Helper function to get the required elemental information from
3060  /// the element to be sent. This info. involves the association of
3061  /// the element to a boundary or region, and if its part of the
3062  /// halo(ed) elements within a processor
3063  void get_required_elemental_information_load_balance_helper(
3064  unsigned& iproc,
3065  Vector<Vector<FiniteElement*> > &f_haloed_ele_pt,
3066  FiniteElement* ele_pt);
3067 
3068  /// \short Check if necessary to add the node to the new domain or if it has been
3069  /// already added
3071  Vector<Node*> &new_nodes_on_domain,
3072  Node*& node_pt)
3073  {
3074  // Get the number of nodes currently added to the new domain
3075  const unsigned nnew_nodes_on_domain = new_nodes_on_domain.size();
3076 
3077  // Flag to state if has been added or not
3078  bool already_on_new_domain = false;
3079  unsigned new_domain_node_index = 0;
3080 
3081  for (unsigned n = 0; n < nnew_nodes_on_domain; n++)
3082  {
3083  if (node_pt == new_nodes_on_domain[n])
3084  {
3085  // It's already there, so...
3086  already_on_new_domain = true;
3087  // ...set the index of this element
3088  new_domain_node_index = n;
3089  break;
3090  }
3091  }
3092 
3093  // Has it been found?
3094  if (!already_on_new_domain)
3095  {
3096  // Not found, so add it:
3097  new_nodes_on_domain.push_back(node_pt);
3098  // Return the index where it's just been added
3099  return nnew_nodes_on_domain;
3100  }
3101  else
3102  {
3103  // Return the index where it was found
3104  return new_domain_node_index;
3105  }
3106 
3107  }
3108 
3109  /// \short Helper function to add haloed node
3110  void add_node_load_balance_helper(unsigned& iproc,
3111  Vector<Vector<FiniteElement*> >
3112  &f_halo_ele_pt,
3113  Vector<Node*> &new_nodes_on_domain,
3114  Node* nod_pt);
3115 
3116  /// \short Helper function to get the required nodal information
3117  /// from an haloed node so that a fully-functional node (and
3118  /// therefore element) can be created on the receiving process
3119  /// (this is the specific version for the load balance strategy,
3120  /// the difference with the original method is that it checks if
3121  /// the node is on a shared boundary no associated with the current
3122  /// processor --my_rank--, or in a haloed element from other
3123  /// processors
3124  void get_required_nodal_information_load_balance_helper(
3125  Vector<Vector<FiniteElement*> > &f_halo_ele_pt,
3126  unsigned& iproc,
3127  Node* nod_pt);
3128 
3129  /// \short Helper function to create elements on the loop
3130  /// process based on the info received in
3131  /// send_and_received_elements_nodes_info
3132  void create_element_load_balance_helper(
3133  unsigned& iproc,
3134  Vector<Vector<FiniteElement*> > &f_haloed_ele_pt,
3135  Vector<Vector<std::map<unsigned,FiniteElement*> > >
3136  &received_old_haloed_element_pt,
3137  Vector<FiniteElement*> &new_elements_on_domain,
3138  Vector<Node*> &new_nodes_on_domain,
3139  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
3140  &other_proc_shd_bnd_node_pt,
3141  Vector<Vector<Vector<unsigned> > > &global_node_names,
3142  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
3143  Vector<Node*> &global_shared_node_pt);
3144 
3145  /// \short Helper function to create elements on the loop
3146  /// process based on the info received in
3147  /// send_and_received_elements_nodes_info
3148  /// This function is in charge of verify if the element is associated
3149  /// to a boundary and associate to it if that is the case
3150  void add_element_load_balance_helper(const unsigned &iproc,
3151  Vector<Vector<std::map<
3152  unsigned,FiniteElement*> > >
3153  &received_old_haloed_element_pt,
3154  FiniteElement* ele_pt);
3155 
3156  /// \short Helper function to add a new node from load balance
3157  void add_received_node_load_balance_helper(
3158  Node* &new_nod_pt,
3159  Vector<Vector<FiniteElement*> > &f_haloed_ele_pt,
3160  Vector<Vector<std::map<unsigned,FiniteElement*> > >
3161  &received_old_haloed_element_pt,
3162  Vector<Node*> &new_nodes_on_domain,
3163  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
3164  &other_proc_shd_bnd_node_pt,
3165  unsigned& iproc, unsigned& node_index,
3166  FiniteElement* const &new_el_pt,
3167  Vector<Vector<Vector<unsigned> > > &global_node_names,
3168  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
3169  Vector<Node*> &global_shared_node_pt);
3170 
3171  /// \short Helper function which constructs a new node (on an
3172  /// element) with the information sent from the load balance
3173  /// process
3174  void construct_new_node_load_balance_helper(
3175  Node* &new_nod_pt,
3176  Vector<Vector<FiniteElement*> > &f_haloed_ele_pt,
3177  Vector<Vector<std::map<unsigned,FiniteElement*> > >
3178  &received_old_haloed_element_pt,
3179  Vector<Node*> &new_nodes_on_domain,
3180  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
3181  &other_proc_shd_bnd_node_pt,
3182  unsigned& iproc, unsigned& node_index,
3183  FiniteElement* const &new_el_pt,
3184  Vector<Vector<Vector<unsigned> > > &global_node_names,
3185  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
3186  Vector<Node*> &global_shared_node_pt);
3187 
3188  // *********************************************************************
3189  // END: Methods to perform load balance
3190  // *********************************************************************
3191 
3192  // *********************************************************************
3193  // Start communication variables
3194  // *********************************************************************
3195  /// \short Vector of flat-packed doubles to be communicated with
3196  /// other processors
3197  Vector<double> Flat_packed_doubles;
3198 
3199  /// \short Counter used when processing vector of flat-packed
3200  /// doubles
3202 
3203  /// \short Vector of flat-packed unsigneds to be communicated with
3204  /// other processors
3205  Vector<unsigned> Flat_packed_unsigneds;
3206 
3207  /// \short Counter used when processing vector of flat-packed
3208  /// unsigneds
3210 
3211 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
3212  /// \short Temporary vector of strings to enable full annotation of
3213  /// RefineableTriangleMesh comms
3214  Vector<std::string> Flat_packed_unsigneds_string;
3215 #endif
3216 
3217  // *********************************************************************
3218  // End communication variables
3219  // *********************************************************************
3220 
3221  // *********************************************************************
3222  // Start communication functions
3223  // *********************************************************************
3224 
3225  /// \short Check if necessary to add the element as haloed or if it has been
3226  /// previously added to the haloed scheme
3227  unsigned try_to_add_root_haloed_element_pt(const unsigned& p,
3228  GeneralisedElement*& el_pt)
3229  {
3230  // Loop over current storage
3231  unsigned n_haloed=this->nroot_haloed_element(p);
3232 
3233  // Is this already an haloed element?
3234  bool already_haloed_element=false;
3235  unsigned haloed_el_index=0;
3236  for (unsigned eh=0;eh<n_haloed;eh++)
3237  {
3238  if (el_pt==this->root_haloed_element_pt(p, eh))
3239  {
3240  // It's already there, so...
3241  already_haloed_element=true;
3242  // ...set the index of this element
3243  haloed_el_index=eh;
3244  break;
3245  }
3246  }
3247 
3248  // Has it been found?
3249  if (!already_haloed_element)
3250  {
3251  // Not found, so add it:
3252  this->add_root_haloed_element_pt(p, el_pt);
3253  // Return the index where it's just been added
3254  return n_haloed;
3255  }
3256  else
3257  {
3258  // Return the index where it was found
3259  return haloed_el_index;
3260  }
3261  }
3262 
3263  /// \short Check if necessary to add the node as haloed or if it has been
3264  /// previously added to the haloed scheme
3265  unsigned try_to_add_haloed_node_pt(const unsigned& p, Node*& nod_pt)
3266  {
3267  // Loop over current storage
3268  unsigned n_haloed_nod=this->nhaloed_node(p);
3269 
3270  // Is this already an haloed node?
3271  bool is_an_haloed_node=false;
3272  unsigned haloed_node_index=0;
3273  for (unsigned k=0;k<n_haloed_nod;k++)
3274  {
3275  if (nod_pt==this->haloed_node_pt(p,k))
3276  {
3277  is_an_haloed_node=true;
3278  haloed_node_index=k;
3279  break;
3280  }
3281  }
3282 
3283  // Has it been found?
3284  if (!is_an_haloed_node)
3285  {
3286  // Not found, so add it
3287  this->add_haloed_node_pt(p, nod_pt);
3288  // Return the index where it's just been added
3289  return n_haloed_nod;
3290  }
3291  else
3292  {
3293  // Return the index where it was found
3294  return haloed_node_index;
3295  }
3296  }
3297 
3298  /// \short Helper function to get the required elemental information from
3299  /// an haloed element. This info. involves the association of the element
3300  /// to a boundary or region.
3301  void get_required_elemental_information_helper(unsigned& iproc,
3302  FiniteElement* ele_pt);
3303 
3304  /// \short Helper function to get the required nodal information
3305  /// from a haloed node so that a fully-functional halo node (and
3306  /// therefore element) can be created on the receiving process
3307  void get_required_nodal_information_helper(unsigned& iproc, Node* nod_pt);
3308 
3309  /// \short Helper function to add haloed node
3310  void add_haloed_node_helper(unsigned& iproc, Node* nod_pt);
3311 
3312  /// \short Helper function to send back halo and haloed information
3313  void send_and_receive_elements_nodes_info(int& send_proc, int &recv_proc);
3314 
3315  /// \short Helper function to create (halo) elements on the loop
3316  /// process based on the info received in send_and_received_located_info
3317  void create_halo_element(unsigned &iproc,
3318  Vector<Node*> &new_nodes_on_domain,
3319  Vector<Vector<Vector<std::map<unsigned,
3320  Node*> > > > &other_proc_shd_bnd_node_pt,
3321  Vector<Vector<Vector<unsigned> > >
3322  &global_node_names,
3323  std::map<Vector<unsigned>, unsigned>
3324  &node_name_to_global_index,
3325  Vector<Node*> &global_shared_node_pt);
3326 
3327  /// \short Helper function to create (halo) elements on the loop
3328  /// process based on the info received in send_and_received_located_info
3329  /// This function is in charge of verify if the element is associated to
3330  /// a boundary
3331  void add_halo_element_helper(unsigned& iproc, FiniteElement* ele_pt);
3332 
3333  /// \short Helper function to add halo node
3334  void add_halo_node_helper(Node* &new_nod_pt,
3335  Vector<Node*> &new_nodes_on_domain,
3336  Vector<Vector<Vector<std::map<unsigned,
3337  Node*> > > >
3338  &other_proc_shd_bnd_node_pt,
3339  unsigned& iproc,
3340  unsigned& node_index,
3341  FiniteElement* const &new_el_pt,
3342  Vector<Vector<Vector<unsigned> > >
3343  &global_node_names,
3344  std::map<Vector<unsigned>, unsigned>
3345  &node_name_to_global_index,
3346  Vector<Node*> &global_shared_node_pt);
3347 
3348  /// \short Helper function which constructs a new halo node
3349  /// (on an element) with the information sent from the haloed process
3350  void construct_new_halo_node_helper(Node* &new_nod_pt,
3351  Vector<Node*> &new_nodes_on_domain,
3352  Vector<Vector<Vector<std::map<unsigned,
3353  Node*> > > >
3354  &other_proc_shd_bnd_node_pt,
3355  unsigned& iproc,
3356  unsigned& node_index,
3357  FiniteElement* const &new_el_pt,
3358  Vector<Vector<Vector<unsigned> > >
3359  &global_node_names,
3360  std::map<Vector<unsigned>, unsigned>
3361  &node_name_to_global_index,
3362  Vector<Node*> &global_shared_node_pt);
3363 
3364  /// \short Helper function that assigns/updates the references to the node
3365  /// so that it can be found with any other reference. The return
3366  /// value indicates whether or not a node was found on the same
3367  /// reference
3368  void update_other_proc_shd_bnd_node_helper
3369  (Node* &new_nod_pt,
3370  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
3371  &other_proc_shd_bnd_node_pt,
3372  Vector<unsigned> &other_processor_1,
3373  Vector<unsigned> &other_processor_2,
3374  Vector<unsigned> &other_shared_boundaries,
3375  Vector<unsigned> &other_indexes,
3376  Vector<Vector<Vector<unsigned> > > &global_node_names,
3377  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
3378  Vector<Node*> &global_shared_node_pt);
3379 
3380  // *********************************************************************
3381  // End Communication funtions
3382  // *********************************************************************
3383 
3384 #endif // #ifdef OOMPH_HAS_MPI
3385 
3386  /// \short Helper function that updates the input polygon's PSLG
3387  /// by using the end-points of elements from FaceMesh(es) that are
3388  /// constructed for the boundaries associated with the segments of the
3389  /// polygon. Optional boolean is used to run it as test only (if
3390  /// true is specified as input) in which case polygon isn't actually
3391  /// modified. Returned boolean indicates if polygon was (or would have
3392  /// been -- if called with check_only=false) changed.
3393  bool update_polygon_using_face_mesh(TriangleMeshPolygon* polygon_pt,
3394  const bool& check_only=false);
3395 
3396  /// \short Helper function that updates the input open curve by using
3397  /// end-points of elements from FaceMesh(es) that are constructed for the
3398  /// boundaries associated with the polylines. Optional boolean is used to
3399  /// run it as test only (if true is specified as input) in which case the
3400  /// polylines are not actually modified. Returned boolean indicates if
3401  /// polylines were (or would have been -- if called with check_only=false)
3402  /// changed.
3403  bool update_open_curve_using_face_mesh(
3404  TriangleMeshOpenCurve* open_polyline_pt,
3405  const bool& check_only=false);
3406 
3407  /// \short Generate a new PSLG representation of the inner hole
3408  /// boundaries. Optional boolean is used to run it as test only (if
3409  /// true is specified as input) in which case PSLG isn't actually
3410  /// modified. Returned boolean indicates if PSLG was (or would have
3411  /// been -- if called with check_only=false) changed.
3412  virtual bool surface_remesh_for_inner_hole_boundaries(
3413  Vector<Vector<double> > &internal_point_coord,
3414  const bool& check_only=false);
3415 
3416  /// \short Snap the boundary nodes onto any curvilinear boundaries
3417  void snap_nodes_onto_boundary(RefineableTriangleMesh<ELEMENT>* &new_mesh_pt,
3418  const unsigned &b);
3419 
3420  /// \short Helper function
3421  /// Creates an unsorted face mesh representation from the specified
3422  /// boundary id. It means that the elements are not sorted along the
3423  /// boundary
3424  void create_unsorted_face_mesh_representation(
3425  const unsigned &boundary_id,
3426  Mesh* face_mesh_pt);
3427 
3428  /// \short Helper function
3429  /// Creates a sorted face mesh representation of the specified PolyLine
3430  /// It means that the elements are sorted along the boundary
3431  /// It also returns a map that indicated the inverted elements
3432  void create_sorted_face_mesh_representation(
3433  const unsigned &boundary_id,
3434  Mesh* face_mesh_pt,
3435  std::map<FiniteElement*, bool> &is_inverted,
3436  bool &inverted_face_mesh);
3437 
3438  /// \short Helper function to construct face mesh representation of all
3439  /// polylines, possibly with segments re-distributed between polylines
3440  /// to maintain an appxroximately even sub-division of the polygon
3441  void get_face_mesh_representation(TriangleMeshPolygon* polygon_pt,
3442  Vector<Mesh*>& face_mesh_pt);
3443 
3444  /// \short Helper function to construct face mesh representation of
3445  /// open curves
3446  void get_face_mesh_representation(
3447  TriangleMeshOpenCurve* open_polyline_pt,
3448  Vector<Mesh*>& face_mesh_pt);
3449 
3450  /// \short Updates the polylines representation after restart
3451  void update_polygon_after_restart(TriangleMeshPolygon* &polygon_pt);
3452 
3453  /// \short Updates the open curve representation after restart
3454  void update_open_curve_after_restart(TriangleMeshOpenCurve* &open_curve_pt);
3455 
3456  /// \short Updates the polylines using the elements area as constraint for
3457  /// the number of points along the boundaries
3458  bool update_polygon_using_elements_area(
3459  TriangleMeshPolygon* &polygon_pt, const Vector<double> &target_area);
3460 
3461  /// \short Updates the open curve but using the elements area instead
3462  /// of the default refinement and unrefinement methods
3463  bool update_open_curve_using_elements_area(
3464  TriangleMeshOpenCurve* &open_curve_pt, const Vector<double> &target_area);
3465 
3466 #ifdef OOMPH_HAS_MPI
3467  /// \short Updates the polylines using the elements area as
3468  /// constraint for the number of points along the boundaries
3469  bool update_shared_curve_using_elements_area(
3470  Vector<TriangleMeshPolyLine*> &vector_polyline_pt,
3471  const Vector<double> &target_areas);
3472 
3473  /// \short Updates the shared polylines representation after restart
3474  void update_shared_curve_after_restart(Vector<TriangleMeshPolyLine*>
3475  &vector_polyline_pt);
3476 
3477 #endif // #ifdef OOMPH_HAS_MPI
3478 
3479  /// Helper function to initialise data associated with adaptation
3481  {
3482  // Number of bins in the x-direction
3483  // when transferring target areas by bin method. Only used if we
3484  // don't have CGAL!
3485  this->Nbin_x_for_area_transfer=100;
3486 
3487  // Number of bins in the y-direction
3488  // when transferring target areas by bin method. Only used if we
3489  // don't have CGAL!
3490  this->Nbin_y_for_area_transfer=100;
3491 
3492  // Initialise "what it says" -- used when transferring target areas
3493  // using cgal-based sample point container
3494  Max_sample_points_for_limited_locate_zeta_during_target_area_transfer=5;
3495 
3496  // Set max and min targets for adaptation
3497  this->Max_element_size=1.0;
3498  this->Min_element_size=0.001;
3499  this->Min_permitted_angle=15.0;
3500 
3501  // By default we want to do projection
3502  this->Disable_projection=false;
3503 
3504  // Use by default an iterative solver for the projection problem
3505  this->Use_iterative_solver_for_projection=true;
3506 
3507  // Set the defaul value for printing level adaptation (default 0)
3508  this->Print_timings_level_adaptation=0;
3509 
3510  // Set the defaul value for printing level load balance (default 0)
3511  this->Print_timings_level_load_balance=0;
3512 
3513  // By default we want no info. about timings for transferring of
3514  // target areas
3515  this->Print_timings_transfering_target_areas=false;
3516 
3517  // By default we want no info. about timings for projection
3518  this->Print_timings_projection=false;
3519 
3520  // Initialise function pointer to function that updates the
3521  // mesh following the snapping of boundary nodes to the
3522  // boundaries (e.g. to move boundary nodes very slightly
3523  // to satisfy volume constraints)
3524  Mesh_update_fct_pt=0;
3525 
3526  // Initialise function point for update of internal hole
3527  // point to null
3528  Internal_hole_point_update_fct_pt=0;
3529 
3530  }
3531 
3532 #ifdef OOMPH_HAS_TRIANGLE_LIB
3533 
3534  /// \short Build a new TriangulateIO object from previous TriangulateIO
3535  /// based on target area for each element
3536  void refine_triangulateio(TriangulateIO& triangulate_io,
3537  const Vector<double> &target_area,
3538  TriangulateIO &triangle_refine);
3539 
3540 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB
3541 
3542  /// \short Compute target area based on the element's error and the
3543  /// error target; return minimum angle (in degrees)
3544  double compute_area_target(const Vector<double> &elem_error,
3545  Vector<double> &target_area)
3546  {
3547  double min_angle=DBL_MAX;
3548  unsigned count_unrefined=0;
3549  unsigned count_refined=0;
3550  this->Nrefinement_overruled=0;
3551 
3552  // Record max. area constraint set by region
3553  std::map<FiniteElement*,double> max_area_from_region;
3554  for (std::map<unsigned, double>::iterator it=this->Regions_areas.begin();
3555  it!=this->Regions_areas.end();it++)
3556  {
3557  unsigned r=(*it).first;
3558  unsigned nel=this->nregion_element(r);
3559  for(unsigned e=0;e<nel;e++)
3560  {
3561  max_area_from_region[this->region_element_pt(r,e)]=(*it).second;
3562  }
3563  }
3564 
3565  unsigned nel=this->nelement();
3566  for (unsigned e=0;e<nel;e++)
3567  {
3568  // Get element
3569  FiniteElement* el_pt=this->finite_element_pt(e);
3570 
3571  // Area
3572  double area=el_pt->size();
3573 
3574  // Min angle based on vertex coordinates
3575  // (vertices are enumerated first)
3576  double ax=el_pt->node_pt(0)->x(0);
3577  double ay=el_pt->node_pt(0)->x(1);
3578 
3579  double bx=el_pt->node_pt(1)->x(0);
3580  double by=el_pt->node_pt(1)->x(1);
3581 
3582  double cx=el_pt->node_pt(2)->x(0);
3583  double cy=el_pt->node_pt(2)->x(1);
3584 
3585  // Min angle
3586  double angle0=
3587  acos(((ax-cx)*(bx-cx)+(ay-cy)*(by-cy))/
3588  (sqrt((ax-cx)*(ax-cx)+(ay-cy)*(ay-cy))*
3589  sqrt((bx-cx)*(bx-cx)+(by-cy)*(by-cy))))*
3590  180.0/MathematicalConstants::Pi;
3591  min_angle=std::min(min_angle,angle0);
3592 
3593  double angle1=
3594  acos(((ax-bx)*(cx-bx)+(ay-by)*(cy-by))/
3595  (sqrt((ax-bx)*(ax-bx)+(ay-by)*(ay-by))*
3596  sqrt((cx-bx)*(cx-bx)+(cy-by)*(cy-by))))*
3597  180.0/MathematicalConstants::Pi;
3598  min_angle=std::min(min_angle,angle1);
3599 
3600  double angle2=180.0-angle0-angle1;
3601  min_angle=std::min(min_angle,angle2);
3602 
3603  // Mimick refinement in tree-based procedure: Target areas
3604  // for elements that exceed permitted error is 1/3 of their
3605  // current area, corresponding to a uniform sub-division.
3606  double size_ratio=3.0;
3607  if (elem_error[e]>max_permitted_error())
3608  {
3609  // Reduce area
3610  target_area[e]=std::max(area/size_ratio,Min_element_size);
3611 
3612  //...but also make sure we're below the max element size
3613  target_area[e]=std::min(target_area[e],Max_element_size);
3614 
3615  if (target_area[e]!=Min_element_size)
3616  {
3617  count_refined++;
3618  }
3619  else
3620  {
3621  this->Nrefinement_overruled++;
3622  }
3623  }
3624  else if (elem_error[e]<min_permitted_error())
3625  {
3626  // Increase the area
3627  target_area[e]=std::min(size_ratio*area,Max_element_size);
3628 
3629  //...but also make sure we're above the min element size
3630  target_area[e]=std::max(target_area[e],Min_element_size);
3631 
3632  if (target_area[e]!=Max_element_size)
3633  {
3634  count_unrefined++;
3635  }
3636  }
3637  else
3638  {
3639  // Leave it alone but enforce size limits
3640  double area_leave_alone = std::max(area,Min_element_size);
3641  target_area[e] = std::min(area_leave_alone,Max_element_size);
3642  }
3643 
3644  // Enforce max areas from regions
3645  std::map<FiniteElement*,double>::iterator it=
3646  max_area_from_region.find(el_pt);
3647  if (it!=max_area_from_region.end())
3648  {
3649  target_area[e]=std::min(target_area[e],(*it).second);
3650  }
3651 
3652  }
3653 
3654 
3655  // Tell everybody
3656  this->Nrefined=count_refined;
3657  this->Nunrefined=count_unrefined;
3658 
3659  if (this->Nrefinement_overruled!=0)
3660  {
3661  oomph_info
3662  << "\nNOTE: Refinement of "
3663  << this->Nrefinement_overruled << " elements was "
3664  << "overruled \nbecause the target area would have "
3665  << "been below \nthe minimum permitted area of "
3666  << Min_element_size
3667  << ".\nYou can change the minimum permitted area with the\n"
3668  << "function RefineableTriangleMesh::min_element_size().\n\n";
3669  }
3670  return min_angle;
3671  }
3672 
3673  /// \short Number of bins in the x-direction
3674  /// when transferring target areas by bin method. Only used if we
3675  /// don't have CGAL!
3677 
3678  /// \short Number of bins in the y-direction
3679  /// when transferring target areas by bin method. Only used if we
3680  /// don't have CGAL!
3682 
3683  /// \short Default value for max. number of sample points used for locate_zeta
3684  /// when transferring target areas using cgal-based sample point container
3686 
3687  /// Max permitted element size
3689 
3690  /// Min permitted element size
3692 
3693  /// Min angle before remesh gets triggered
3695 
3696  /// Enable/disable solution projection during adaptation
3698 
3699  /// Flag to indicate whether to use or not an iterative solver (CG
3700  /// with diagonal preconditioned) for the projection problem
3702 
3703  /// Enable/disable printing timings for transfering target areas
3705 
3706  /// Enable/disable printing timings for projection
3708 
3709  /// The printing level for adaptation
3711 
3712  /// The printing level for load balance
3714 
3715  /// \short Function pointer to function that updates the
3716  /// mesh following the snapping of boundary nodes to the
3717  /// boundaries (e.g. to move boundary nodes very slightly
3718  /// to satisfy volume constraints)
3719  MeshUpdateFctPt Mesh_update_fct_pt;
3720 
3721  /// \short Function pointer to function that can be set
3722  /// to update the position of the central point in internal
3723  /// holes
3724  InternalHolePointUpdateFctPt Internal_hole_point_update_fct_pt;
3725 
3726  };
3727 
3728 
3729 /////////////////////////////////////////////////////////////////////
3730 /////////////////////////////////////////////////////////////////////
3731 /////////////////////////////////////////////////////////////////////
3732 
3733 
3734 //=========================================================================
3735 /// Unstructured Triangle Mesh upgraded to solid mesh
3736 //=========================================================================
3737  template<class ELEMENT>
3738  class SolidTriangleMesh : public virtual TriangleMesh<ELEMENT>,
3739  public virtual SolidMesh
3740  {
3741 
3742  public:
3743 
3744 #ifdef OOMPH_HAS_TRIANGLE_LIB
3745 
3746  /// \short Build mesh, based on closed curve that specifies
3747  /// the outer boundary of the domain and any number of internal
3748  /// clsed curves. Specify target area for uniform element size.
3749  SolidTriangleMesh(TriangleMeshParameters &triangle_mesh_parameters,
3750  TimeStepper* time_stepper_pt=&Mesh::Default_TimeStepper)
3751  : TriangleMesh<ELEMENT>(triangle_mesh_parameters,
3752  time_stepper_pt)
3753  {
3754  //Assign the Lagrangian coordinates
3755  set_lagrangian_nodal_coordinates();
3756  }
3757 
3758 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB
3759 
3761  const std::string& node_file_name,
3762  const std::string& element_file_name,
3763  const std::string& poly_file_name,
3764  TimeStepper* time_stepper_pt=
3765  &Mesh::Default_TimeStepper,
3766  const bool &allow_automatic_creation_of_vertices_on_boundaries=true)
3767  : TriangleMesh<ELEMENT>(node_file_name,
3768  element_file_name,
3769  poly_file_name,
3770  time_stepper_pt,
3771  allow_automatic_creation_of_vertices_on_boundaries)
3772  {
3773  //Assign the Lagrangian coordinates
3774  set_lagrangian_nodal_coordinates();
3775  }
3776 
3777  /// Empty Destructor
3778  virtual ~SolidTriangleMesh() { }
3779  };
3780 
3781 
3782 ////////////////////////////////////////////////////////////////////////
3783 ////////////////////////////////////////////////////////////////////////
3784 ////////////////////////////////////////////////////////////////////////
3785 
3786 #ifdef OOMPH_HAS_TRIANGLE_LIB
3787 
3788 //=========================================================================
3789 /// Unstructured refineable Triangle Mesh upgraded to solid mesh
3790 //=========================================================================
3791  template<class ELEMENT>
3793  public virtual RefineableTriangleMesh<ELEMENT>,
3794  public virtual SolidMesh
3795  {
3796 
3797  public:
3798 
3799  /// \short Build mesh, based on the specifications on
3800  /// TriangleMeshParameter
3802  TimeStepper* time_stepper_pt=
3803  &Mesh::Default_TimeStepper)
3804  : TriangleMesh<ELEMENT>(triangle_mesh_parameters,
3805  time_stepper_pt),
3806  RefineableTriangleMesh<ELEMENT>(triangle_mesh_parameters,
3807  time_stepper_pt)
3808  {
3809  //Assign the Lagrangian coordinates
3810  set_lagrangian_nodal_coordinates();
3811  }
3812 
3813  /// \short Build mesh from specified triangulation and
3814  /// associated target areas for elements in it.
3816  const Vector<double> &target_area,
3817  TriangulateIO& triangulate_io,
3818  TimeStepper* time_stepper_pt=
3819  &Mesh::Default_TimeStepper,
3820  const bool &use_attributes=false,
3821  const bool
3822  &allow_automatic_creation_of_vertices_on_boundaries=true,
3823  OomphCommunicator* comm_pt = 0) :
3824  RefineableTriangleMesh<ELEMENT>(
3825  target_area,
3826  triangulate_io,
3827  time_stepper_pt,
3828  use_attributes,
3829  allow_automatic_creation_of_vertices_on_boundaries,
3830  comm_pt)
3831  {
3832  //Assign the Lagrangian coordinates
3833  set_lagrangian_nodal_coordinates();
3834  }
3835 
3836  /// Empty Destructor
3838  };
3839 
3840 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB
3841 
3842 }
3843 
3844 #endif
bool Print_timings_transfering_target_areas
Enable/disable printing timings for transfering target areas.
RefineableSolidTriangleMesh(TriangleMeshParameters &triangle_mesh_parameters, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Build mesh, based on the specifications on TriangleMeshParameter.
void disable_timings_projection()
Disables info. and timings for projection.
Vector< unsigned > & shared_boundaries_ids(const unsigned &p, const unsigned &q)
Node *& boundary_segment_node_pt(const unsigned &b, const unsigned &s, const unsigned &n)
Return pointer to node n on boundary b.
double Max_element_size
Max permitted element size.
bool Do_boundary_refinement_constrained_by_target_areas
Flag that enables or disables boundary refinement (true by default)
double & min_element_size()
Min element size allowed during adaptation.
virtual void load_balance(const Vector< unsigned > &target_domain_for_local_non_halo_element)
Virtual function to perform the load balance routines.
Vector< TriangleMeshOpenCurve * > Internal_open_curves_pt
Internal boundaries.
const unsigned nshared_boundary_node(const unsigned &b)
void enable_timings_projection()
Enables info. and timings for projection.
Unstructured refineable Triangle Mesh upgraded to solid mesh.
std::map< unsigned, Vector< double > > & regions_coordinates()
Helper function for getting access to the regions coordinates.
Vector< TriangleMeshClosedCurve * > Internal_closed_curve_pt
Internal closed boundaries.
std::map< unsigned, double > Regions_areas
Target areas for regions; defaults to 0.0 which (luckily) implies "no specific target area" for trian...
void enable_projection()
Enables the solution projection step during adaptation.
virtual ~RefineableTriangleMesh()
Empty Destructor.
void initialise_adaptation_data()
Helper function to initialise data associated with adaptation.
const unsigned nshared_boundaries() const
void disable_shared_boundary_unrefinement_constrained_by_target_areas()
bool Disable_projection
Enable/disable solution projection during adaptation.
MeshUpdateFctPt & mesh_update_fct_pt()
Access to function pointer to function that updates the mesh following the snapping of boundary nodes...
std::map< unsigned, unsigned > Shared_boundary_overlaps_internal_boundary
Stores information about those shared boundaries that lie over or over a segment of an internal bound...
Vector< TriangleMeshClosedCurve * > & outer_boundary_pt()
Helper function for getting access to the outer boundary.
bool is_internal_boundary_refinement_allowed() const
Helper function for getting the status of boundary refinement.
void set_target_area_for_region(const unsigned &i, const double &area)
Helper function to specify target area for region.
RefineableTriangleMesh(const Vector< double > &target_area, TriangulateIO &triangulate_io, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper, const bool &use_attributes=false, const bool &allow_automatic_creation_of_vertices_on_boundaries=true, OomphCommunicator *comm_pt=0)
Build mesh from specified triangulation and associated target areas for elements in it NOTE: This is ...
void update_polyline_representation_from_restart()
Method used to update the polylines representation after restart.
Vector< TriangleMeshOpenCurve * > internal_open_curves_pt() const
Helper function for getting the internal open boundaries.
void reestablish_distribution_info_for_restart(OomphCommunicator *comm_pt, std::istream &restart_file)
const unsigned nshared_boundary_curves(const unsigned &p) const
virtual void reestablish_distribution_info_for_restart(OomphCommunicator *comm_pt, std::istream &restart_file)
std::map< unsigned, Vector< TriangleMeshPolyLine * > > Boundary_subpolylines
The polylines that will temporary represent the boundary that was splitted in the distribution proces...
TriangleMeshParameters(Vector< TriangleMeshClosedCurve *> &outer_boundary_pt)
void disable_internal_boundary_refinement()
Helper function for disabling the use of boundary refinement.
unsigned Counter_for_flat_packed_doubles
Counter used when processing vector of flat-packed doubles.
SolidTriangleMesh(const std::string &node_file_name, const std::string &element_file_name, const std::string &poly_file_name, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper, const bool &allow_automatic_creation_of_vertices_on_boundaries=true)
unsigned try_to_add_node_pt_load_balance(Vector< Node *> &new_nodes_on_domain, Node *&node_pt)
Check if necessary to add the node to the new domain or if it has been already added.
Vector< TriangleMeshOpenCurve * > & internal_open_curves_pt()
Helper function for getting access to the internal open boundaries.
std::map< unsigned, Vector< int > > Face_index_at_shared_boundary
For the e-th finite element on shared boundary b, this is the index of the face that lies along that ...
void operator=(const TriangleMesh &)
Broken assignment operator.
unsigned try_to_add_root_haloed_element_pt(const unsigned &p, GeneralisedElement *&el_pt)
Check if necessary to add the element as haloed or if it has been previously added to the haloed sche...
void add_shared_boundary_node(const unsigned &b, Node *node_pt)
Add the node the shared boundary.
void initialise_boundary_refinement_data()
Set all the flags to true (the default values)
void add_region_coordinates(const unsigned &i, Vector< double > &region_coordinates)
Helper function for getting the extra regions.
bool Do_boundary_unrefinement_constrained_by_target_areas
Flag that enables or disables boundary unrefinement (true by default)
void enable_use_attributes()
Helper function for enabling the use of attributes.
Helper object for dealing with the parameters used for the TriangleMesh objects.
std::map< unsigned, double > Regions_areas
Target areas for regions; defaults to 0.0 which (luckily) implies "no specific target area" for trian...
void disable_boundary_refinement()
Helper function for disabling the use of boundary refinement.
void update_triangulateio()
Update the triangulateio object to the current nodal positions.
bool Triangulateio_exists
Boolean defining if Triangulateio object has been built or not.
void disable_print_timings_adaptation()
Disables printing of timings for adaptation.
std::map< unsigned, Vector< unsigned > > & shared_boundary_from_processors()
Return the association of the shared boundaries with the processors.
Vector< Node * > & boundary_segment_node_pt(const unsigned &b, const unsigned &s)
Return direct access to nodes associated with a segment of a given boundary.
std::map< unsigned, Vector< unsigned > > Shared_boundary_from_processors
Stores the processors involved in the generation of a shared boundary, in 2D two processors give rise...
Vector< unsigned > Flat_packed_unsigneds
Vector of flat-packed unsigneds to be communicated with other processors.
void refine_uniformly(DocInfo &doc_info)
Refine mesh uniformly and doc process.
coord2_t cross(const Point &O, const Point &A, const Point &B)
2D cross product of OA and OB vectors, i.e. z-component of their 3D cross product. Returns a positive value, if OAB makes a counter-clockwise turn, negative for clockwise turn, and zero if the points are collinear.
Vector< Vector< double > > & extra_holes_coordinates()
Helper function for getting access to the extra holes.
Vector< TriangleMeshClosedCurve * > outer_boundary_pt() const
Helper function for getting the outer boundary.
InternalHolePointUpdateFctPt Internal_hole_point_update_fct_pt
Function pointer to function that can be set to update the position of the central point in internal ...
unsigned try_to_add_element_pt_load_balance(Vector< FiniteElement *> &new_elements_on_domain, FiniteElement *&ele_pt)
Check if necessary to add the element to the new domain or if it has been previously added...
bool is_boundary_refinement_allowed() const
Helper function for getting the status of boundary refinement.
bool Do_shared_boundary_refinement_constrained_by_target_areas
Flag that enables or disables boundary unrefinement (true by default)
const unsigned shared_boundaries_ids(const unsigned &p, const unsigned &q, const unsigned &i) const
std::map< unsigned, Vector< double > > Regions_coordinates
Store the coordinates for defining extra regions The key on the map is the region id...
unsigned max_sample_points_for_limited_locate_zeta_during_target_area_transfer()
Read/write access to number of sample points from which we try to locate zeta by Newton method when t...
TriangleMesh()
Empty constructor.
void disable_projection()
Disables the solution projection step during adaptation.
unsigned Nbin_y_for_area_transfer
Number of bins in the y-direction when transferring target areas by bin method. Only used if we don&#39;t...
std::map< unsigned, unsigned > & shared_boundary_overlaps_internal_boundary()
Gets the storage that indicates if a shared boundary is part of an internal boundary.
TriangleMeshParameters(TriangleMeshClosedCurve *outer_boundary_pt)
bool is_mesh_distributed() const
Boolean to indicate if Mesh has been distributed.
Vector< TriangleMeshClosedCurve * > & internal_closed_curve_pt()
Helper function for getting access to the internal closed boundaries.
void remesh_from_internal_triangulateio()
Completely regenerate the mesh from the trianglateio structure.
void flush_shared_boundary_node(const unsigned &b)
Flush the boundary nodes associated to the shared boundary b.
Vector< unsigned > shared_boundaries_ids(const unsigned &p, const unsigned &q) const
Vector< Vector< Node * > > & boundary_segment_node_pt(const unsigned &b)
Return direct access to nodes associated with a boundary but sorted in segments.
void set_print_level_timings_adaptation(const unsigned &print_level)
Sets the printing level of timings for adaptation.
const unsigned initial_shared_boundary_id()
The initial boundary id for shared boundaries.
bool First_time_compute_holes_left_by_halo_elements
Flag to know if it is the first time we are going to compute the holes left by the halo elements...
void set_communicator_pt(OomphCommunicator *comm_pt)
Function to set communicator (mesh is then assumed to be distributed)
const unsigned nshared_boundaries(const unsigned &p, const unsigned &q) const
Access functions to boundaries shared with processors.
double & max_element_size()
Max element size allowed during adaptation.
bool Internal_boundary_refinement
Do not allow refinement of nodes on the internal boundary.
virtual ~TriangleMeshParameters()
Empty destructor.
TriangleMeshPolyLine * shared_boundary_polyline_pt(const unsigned &p, const unsigned &c, const unsigned &i) const
std::map< unsigned, Vector< Node * > > Shared_boundary_node_pt
Stores the boundary nodes adjacent to the shared boundaries, these nodes are a subset of the halo and...
virtual ~TriangleMesh()
Destructor.
Vector< double > Flat_packed_doubles
Vector of flat-packed doubles to be communicated with other processors.
std::vector< Point > convex_hull(std::vector< Point > P)
Returns a list of points on the convex hull in counter-clockwise order. Note: the last point in the r...
InternalHolePointUpdateFctPt & internal_hole_point_update_fct_pt()
Access to function pointer to can be used to generate the internal point for the ihole-th hole...
unsigned nsorted_shared_boundary_node(unsigned &b)
const bool shared_boundary_overlaps_internal_boundary(const unsigned &shd_bnd_id)
Checks if the shared boundary overlaps an internal boundary.
unsigned Final_shared_boundary_id
The final boundary id for shared boundaries.
void enable_shared_boundary_unrefinement_constrained_by_target_areas()
Enable/disable unrefinement/refinement methods for shared boundaries.
void get_shared_boundaries_overlapping_internal_boundary(const unsigned &internal_bnd_id, Vector< unsigned > &shd_bnd_ids)
Gets the shared boundaries ids that overlap the given internal boundary.
bool Boundary_refinement
Do not allow refinement of nodes on the boundary.
Vector< unsigned > Oomph_vertex_nodes_id
Vector storing oomph-lib node number for all vertex nodes in the TriangulateIO representation of the ...
double Element_area
The element are when calling triangulate external routine.
std::map< unsigned, bool > Boundary_was_splitted
Flag to indicate if a polyline has been splitted during the distribution process, the boundary id of ...
RefineableTriangleMesh(const std::string &node_file_name, const std::string &element_file_name, const std::string &poly_file_name, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper, const bool &allow_automatic_creation_of_vertices_on_boundaries=true)
Build mesh, based on the polyfiles.
void add_face_index_at_shared_boundary(const unsigned &b, const unsigned &i)
void add_shared_boundary_element(const unsigned &b, FiniteElement *ele_pt)
MeshUpdateFctPt Mesh_update_fct_pt
Function pointer to function that updates the mesh following the snapping of boundary nodes to the bo...
const unsigned read_unsigned_line_helper(std::istream &read_file)
bool Print_timings_projection
Enable/disable printing timings for projection.
double Min_element_size
Min permitted element size.
FiniteElement * shared_boundary_element_pt(const unsigned &b, const unsigned &e)
Vector< Vector< unsigned > > shared_boundaries_ids(const unsigned &p) const
void enable_timings_tranfering_target_areas()
Enables info. and timings for tranferring of target areas.
unsigned unrefine_uniformly()
Unrefine mesh uniformly: Return 0 for success, 1 for failure (if unrefinement has reached the coarses...
TriangleMesh(TriangleMeshParameters &triangle_mesh_parameters, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Build mesh, based on the specifications on TriangleMeshParameters.
std::map< unsigned, std::vector< bool > > Boundary_marked_as_shared_boundary
Flag to indicate if an internal boundary will be used as shared boundary because there is overlapping...
Vector< unsigned > & shared_boundary_from_processors(const unsigned &b)
void enable_print_timings_adaptation(const unsigned &print_level=1)
Enables printing of timings for adaptation.
Node * shared_boundary_node_pt(const unsigned &b, const unsigned &n)
double & element_area()
Helper function for getting access to the element area.
void disable_print_timings_load_balance()
Disables printing of timings for load balance.
void disable_use_attributes()
Helper function for disabling the use of attributes.
const unsigned nboundary_subpolylines(const unsigned &b)
Gets the number of subpolylines that create the boundarya (useful only when the boundary is marked as...
Vector< Vector< double > > extra_holes_coordinates() const
Helper function for getting the extra holes.
Vector< TriangleMeshClosedCurve * > Outer_boundary_pt
The outer boundary.
virtual ~RefineableSolidTriangleMesh()
Empty Destructor.
std::map< unsigned, std::set< Vector< double > > > Boundary_connections_pt
A map that stores the vertices that receive connections, they are identified by the boundary number t...
TriangleScaffoldMesh * Tmp_mesh_pt
Temporary scaffold mesh.
void triangulate(char *triswitches, struct oomph::TriangulateIO *in, struct oomph::TriangulateIO *out, struct oomph::TriangulateIO *vorout)
TimeStepper * Time_stepper_pt
Timestepper used to build elements.
bool is_node_on_shared_boundary(const unsigned &b, Node *const &node_pt)
Is the node on the shared boundary.
const unsigned nshared_boundary_overlaps_internal_boundary()
Get the number of shared boundaries overlaping internal boundaries.
Vector< TriangleMeshClosedCurve * > internal_closed_curve_pt() const
Helper function for getting the internal closed boundaries.
void enable_boundary_refinement()
Helper function for enabling the use of boundary refinement.
RefineableTriangleMesh(TriangleMeshParameters &triangle_mesh_parameters, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Build mesh, based on the specifications on TriangleMeshParameters.
void doc_adaptivity_targets(std::ostream &outfile)
Doc the targets for mesh adaptation.
std::map< unsigned, Vector< Node * > > Sorted_shared_boundary_node_pt
Stores the nodes in the boundaries in the same order in all the processors Sorted_shared_boundary_nod...
double Min_permitted_angle
Min angle before remesh gets triggered.
TriangleMesh(const std::string &node_file_name, const std::string &element_file_name, const std::string &poly_file_name, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper, const bool &allow_automatic_creation_of_vertices_on_boundaries=true)
Constructor with the input files.
unsigned Print_timings_level_adaptation
The printing level for adaptation.
Vector< std::string > Flat_packed_unsigneds_string
Temporary vector of strings to enable full annotation of RefineableTriangleMesh comms.
void enable_boundary_unrefinement_constrained_by_target_areas()
Enable/disable unrefinement/refinement methods for original boundaries.
virtual ~SolidTriangleMesh()
Empty Destructor.
SolidTriangleMesh(TriangleMeshParameters &triangle_mesh_parameters, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Build mesh, based on closed curve that specifies the outer boundary of the domain and any number of i...
std::map< unsigned, double > & target_area_for_region()
Helper function for getting access to the region&#39;s target areas.
void update_triangulateio(Vector< Vector< double > > &internal_point)
Update the TriangulateIO object to the current nodal position and the centre hole coordinates...
unsigned Max_sample_points_for_limited_locate_zeta_during_target_area_transfer
Default value for max. number of sample points used for locate_zeta when transferring target areas us...
double element_area() const
Helper function for getting the element area.
unsigned Initial_shared_boundary_id
The initial boundary id for shared boundaries.
const unsigned nshared_boundary_polyline(const unsigned &p, const unsigned &c) const
void disable_timings_tranfering_target_areas()
Disables info. and timings for tranferring of target areas.
Unstructured Triangle Mesh upgraded to solid mesh.
double compute_area_target(const Vector< double > &elem_error, Vector< double > &target_area)
Compute target area based on the element&#39;s error and the error target; return minimum angle (in degre...
void flush_shared_boundary_element(const unsigned &b)
Vector< Vector< double > > Extra_holes_coordinates
Store the coordinates for defining extra holes.
const unsigned nshared_boundary_element(const unsigned &b)
bool Use_attributes
Define the use of attributes (regions)
const bool boundary_was_splitted(const unsigned &b)
Helper function to verify if a given boundary was splitted in the distribution process.
const unsigned shared_boundary_overlapping_internal_boundary(const unsigned &shd_bnd_id)
Gets the boundary id of the internal boundary that the shared boundary lies on.
RefineableSolidTriangleMesh(const Vector< double > &target_area, TriangulateIO &triangulate_io, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper, const bool &use_attributes=false, const bool &allow_automatic_creation_of_vertices_on_boundaries=true, OomphCommunicator *comm_pt=0)
Build mesh from specified triangulation and associated target areas for elements in it...
void enable_print_timings_load_balance(const unsigned &print_level=1)
Enables printing of timings for load balance.
void enable_internal_boundary_refinement()
Helper function for enabling the use of boundary refinement.
void set_print_level_timings_load_balance(const unsigned &print_level)
Sets the printing level of timings for load balance.
Vector< Vector< double > > Original_extra_holes_coordinates
Backup the original extra holes coordinates.
const bool boundary_marked_as_shared_boundary(const unsigned &b, const unsigned &isub)
Returns the value that indicates if a subpolyline of a given boundary continues been used as internal...
Node * sorted_shared_boundary_node_pt(unsigned &b, unsigned &i)
Vector< Vector< Vector< unsigned > > > Shared_boundaries_ids
Stores the boundaries ids created by the interaction of two processors Shared_boundaries_ids[iproc][j...
unsigned Counter_for_flat_packed_unsigneds
Counter used when processing vector of flat-packed unsigneds.
Vector< Node * > sorted_shared_boundary_node_pt(unsigned &b)
Vector< Vector< Vector< unsigned > > > & shared_boundaries_ids()
unsigned Print_timings_level_load_balance
The printing level for load balance.
Vector< TriangleMeshPolyLine * > & shared_boundary_polyline_pt(const unsigned &p, const unsigned &c)
TriangleMesh(const TriangleMesh &dummy)
Broken copy constructor.
Vector< Vector< unsigned > > & shared_boundaries_ids(const unsigned &p)
const unsigned final_shared_boundary_id()
The final boundary id for shared boundaries.
const bool boundary_connections(const unsigned &b, const unsigned &c, std::set< Vector< double > > &vertices)
Verifies if the given boundary receives a connection, and if that is the case then returns the list o...
int face_index_at_shared_boundary(const unsigned &b, const unsigned &e)
TriangleMesh(const std::string &poly_file_name, const double &element_area, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper, const bool &allow_automatic_creation_of_vertices_on_boundaries=true)
Build mesh from poly file, with specified target area for all elements.
bool Do_shared_boundary_unrefinement_constrained_by_target_areas
Flag that enables or disables boundary unrefinement (true by default)
unsigned Nbin_x_for_area_transfer
Number of bins in the x-direction when transferring target areas by bin method. Only used if we don&#39;t...
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...
TriangleMeshClosedCurve * outer_boundary_pt(const unsigned &i) const
Helper function for getting the i-th outer boundary.
void flush_shared_boundary_node()
Flush ALL the shared boundary nodes.
bool is_use_attributes() const
Helper function for getting the status of use_attributes variable.
double & min_permitted_angle()
Min angle before remesh gets triggered.
Unstructured refineable Triangle Mesh.
OomphCommunicator * communicator_pt() const
Read-only access fct to communicator (Null if mesh is not distributed)
void generic_constructor(Vector< TriangleMeshPolygon *> &outer_boundary_pt, Vector< TriangleMeshPolygon *> &internal_polygon_pt, Vector< TriangleMeshOpenCurve *> &open_polylines_pt, const double &element_area, Vector< Vector< double > > &extra_holes_coordinates, std::map< unsigned, Vector< double > > &regions_coordinates, std::map< unsigned, double > &regions_areas, TimeStepper *time_stepper_pt, const bool &use_attributes, const bool &refine_boundary, const bool &refine_internal_boundary)
A general-purpose construction function that builds the mesh once the different specific constructors...
std::map< unsigned, Vector< FiniteElement * > > Shared_boundary_element_pt
Stores the boundary elements adjacent to the shared boundaries, these elements are a subset of the ha...
bool triangulateio_exists()
Boolean defining if Triangulateio object has been built or not.
Vector< unsigned > oomph_vertex_nodes_id()
Return the vector that contains the oomph-lib node number for all vertex nodes in the TriangulateIO r...
TriangleMeshClosedCurve *& outer_boundary_pt(const unsigned &i)
Helper function for getting access to the i-th outer boundary.
unsigned & nbin_x_for_area_transfer()
Read/write access to number of bins in the x-direction when transferring target areas by bin method...
Vector< TriangleMeshPolyLine * > & boundary_subpolylines(const unsigned &b)
Gets the vector of auxiliar polylines that will represent the given boundary (useful only when the bo...
unsigned try_to_add_haloed_node_pt(const unsigned &p, Node *&nod_pt)
Check if necessary to add the node as haloed or if it has been previously added to the haloed scheme...
void shared_boundaries_in_this_processor(Vector< unsigned > &shared_boundaries_in_this_processor)
Get the shared boundaries ids living in the current processor.
Vector< Vector< Vector< TriangleMeshPolyLine * > > > Shared_boundary_polyline_pt
Stores the polyline representation of the shared boundaries Shared_boundary_polyline_pt[iproc][ncurve...
Vector< Vector< Vector< unsigned > > > shared_boundaries_ids() const
unsigned & nbin_y_for_area_transfer()
Read/write access to number of bins in the y-direction when transferring target areas by bin method...