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