meshes/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"
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;
205 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;
227 OomphLibWarning(error_message.str(),
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)
290 {
291 Comm_pt = comm_pt;
292 }
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
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
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
453 Time_stepper_pt = time_stepper_pt;
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
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 {
490 this->template setup_boundary_coordinates<ELEMENT>(b);
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
511 triangle_mesh_parameters
513
514 // Store Timestepper used to build elements
515 Time_stepper_pt = time_stepper_pt;
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;
546 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
572 closed_curve_to_polygon_helper(outer_boundary_pt[i], max_boundary_id);
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)
623 internal_open_curve_pt[i], max_boundary_id);
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(),
710 time_stepper_pt,
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 {
730 this->template setup_boundary_coordinates<ELEMENT>(b);
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
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
765 Time_stepper_pt = time_stepper_pt;
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
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
808 build_from_scaffold(time_stepper_pt, use_attributes);
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;
817
818 // Setup boundary coordinates for boundaries
819 unsigned nb = nboundary();
820 for (unsigned b = 0; b < nb; b++)
821 {
822 this->template setup_boundary_coordinates<ELEMENT>(b);
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 {
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
872 void set_mesh_level_time_stepper(TimeStepper* const& time_stepper_pt,
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 {
935 return Boundary_segment_node_pt[b];
936 }
937
938 /// Return direct access to nodes associated with a segment of
939 /// a given boundary
941 const unsigned& s)
942 {
943 return Boundary_segment_node_pt[b][s];
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
965 unsigned count_coord = 0;
966 for (unsigned ihole = 0; ihole < nhole; ihole++)
967 {
968 Triangulateio.holelist[count_coord] += internal_point[ihole][0];
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
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);
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
1012 getline(read_file, input_string, '#');
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 {
1117 nbound = this->initial_shared_boundary_id();
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
1174 void build_from_scaffold(TimeStepper* time_stepper_pt,
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,
1196 TimeStepper* time_stepper_pt,
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
1222 Time_stepper_pt = time_stepper_pt;
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
1244
1245 // Convert TriangleMeshPolyLine and TriangleMeshClosedCurvePolyLine
1246 // to a triangulateio object
1248 outer_boundary_pt,
1251 extra_holes_coordinates,
1252 regions_coordinates,
1255
1256 // Initialize TriangulateIO structure
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
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
1308 build_from_scaffold(time_stepper_pt, true);
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
1316 build_from_scaffold(time_stepper_pt, use_attributes);
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;
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 {
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 {
1481 return Shared_boundary_polyline_pt[p][c];
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 {
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 {
1527 Shared_boundary_element_pt[b].clear();
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 {
1541 Shared_boundary_element_pt[b].push_back(ele_pt);
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 {
1552 return Shared_boundary_element_pt[b][e];
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;
1713 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;
1798 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;
1843 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;
1870 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
2038 OomphCommunicator* comm_pt,
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)
2249 : TriangleMesh<ELEMENT>(triangle_mesh_parameters, time_stepper_pt)
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,
2267 : TriangleMesh<ELEMENT>(
2271 time_stepper_pt,
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,
2298 OomphCommunicator* comm_pt = 0)
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
2346 triangulate(triswitches, &triangle_refine, &this->Triangulateio, 0);
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;
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
2570 this->max_and_min_element_size(orig_max_area, orig_min_area);
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
2615 unsigned nsorted_shared_boundary_node(unsigned& b)
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
2635 Node* sorted_shared_boundary_node_pt(unsigned& b, unsigned& i)
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();
2710 this->set_nboundary(noriginal_boundaries);
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
2730 this->snap_nodes_onto_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(
2757 this->Internal_polygon_pt[i_internal]);
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(
2964 TriangleMeshPolyLine* polyline_pt,
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(
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
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
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 {
3216 if (node_pt == new_nodes_on_domain[n])
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:
3386 this->add_root_haloed_element_pt(p, el_pt);
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,
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,
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
3696 FiniteElement* el_pt = this->finite_element_pt(e);
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)))) *
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)))) *
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;
3734 if (elem_error[e] > max_permitted_error())
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;
3782 this->Nunrefined = count_unrefined;
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)
3873 : TriangleMesh<ELEMENT>(triangle_mesh_parameters, time_stepper_pt)
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,
3887 : TriangleMesh<ELEMENT>(
3891 time_stepper_pt,
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
3922 TimeStepper* time_stepper_pt = &Mesh::Default_TimeStepper)
3923 : TriangleMesh<ELEMENT>(triangle_mesh_parameters, time_stepper_pt),
3925 time_stepper_pt)
3926 {
3927 // Assign the Lagrangian coordinates
3929 }
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,
3939 OomphCommunicator* comm_pt = 0)
3940 : RefineableTriangleMesh<ELEMENT>(
3943 time_stepper_pt,
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
e
Definition cfortran.h:571
static char t char * s
Definition cfortran.h:568
cstr elem_len * i
Definition cfortran.h:603
char t
Definition cfortran.h:568
A class that represents a collection of data; each Data object may contain many different individual ...
Definition nodes.h:86
Information for documentation of results: Directory and file number to enable output in the form RESL...
A general Finite Element class.
Definition elements.h:1317
double size() const
Calculate the size of the element (length, area, volume,...) in Eulerian computational coordinates....
Definition elements.cc:4320
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition elements.h:2179
A Generalised Element class.
Definition elements.h:73
This class provides a GeomObject representation of a given finite element mesh. The Lagrangian coordi...
A general mesh class.
Definition mesh.h:67
Vector< Node * > Node_pt
Vector of pointers to nodes.
Definition mesh.h:183
static Steady< 0 > Default_TimeStepper
Default Steady Timestepper, to be used in default arguments to Mesh constructors.
Definition mesh.h:75
bool is_mesh_distributed() const
Boolean to indicate if Mesh has been distributed.
Definition mesh.h:1596
std::map< unsigned, Vector< GeneralisedElement * > > Root_haloed_element_pt
Map of vectors holding the pointers to the root haloed elements.
Definition mesh.h:103
Vector< Vector< FiniteElement * > > Boundary_element_pt
Vector of Vector of pointers to elements on the boundaries: Boundary_element_pt(b,...
Definition mesh.h:91
void flush_element_and_node_storage()
Flush storage for elements and nodes by emptying the vectors that store the pointers to them....
Definition mesh.h:411
std::map< unsigned, Vector< GeneralisedElement * > > External_haloed_element_pt
Map of vectors holding the pointers to the external haloed elements.
Definition mesh.h:129
Vector< Vector< int > > Face_index_at_boundary
For the e-th finite element on boundary b, this is the index of the face that lies along that boundar...
Definition mesh.h:95
void set_nboundary(const unsigned &nbound)
Set the number of boundaries in the mesh.
Definition mesh.h:509
Node *& node_pt(const unsigned long &n)
Return pointer to global node n.
Definition mesh.h:440
std::map< unsigned, Vector< Node * > > External_haloed_node_pt
Map of vectors holding the pointers to the external haloed nodes.
Definition mesh.h:138
std::map< unsigned, Vector< GeneralisedElement * > > Root_halo_element_pt
Map of vectors holding the pointers to the root halo elements.
Definition mesh.h:100
unsigned nboundary() const
Return number of boundaries.
Definition mesh.h:835
void remove_boundary_nodes()
Clear all pointers to boundary nodes.
Definition mesh.cc:204
unsigned long nnode() const
Return number of nodes in the mesh.
Definition mesh.h:604
std::map< unsigned, Vector< Node * > > Halo_node_pt
Map of vectors holding the pointers to the halo nodes.
Definition mesh.h:106
void set_communicator_pt(OomphCommunicator *comm_pt)
Function to set communicator (mesh is assumed to be distributed if the communicator pointer is non-nu...
Definition mesh.h:1623
std::map< unsigned, Vector< Node * > > Haloed_node_pt
Map of vectors holding the pointers to the haloed nodes.
Definition mesh.h:109
Vector< GeneralisedElement * > Element_pt
Vector of pointers to generalised elements.
Definition mesh.h:186
OomphCommunicator * communicator_pt() const
Read-only access fct to communicator (Null if mesh is not distributed, i.e. if we don't have mpi).
Definition mesh.h:1608
std::map< unsigned, Vector< Node * > > External_halo_node_pt
Map of vectors holding the pointers to the external halo nodes.
Definition mesh.h:135
unsigned long nelement() const
Return number of elements in the mesh.
Definition mesh.h:598
std::map< unsigned, Vector< GeneralisedElement * > > External_halo_element_pt
External halo(ed) elements are created as and when they are needed to act as source elements for the ...
Definition mesh.h:126
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition nodes.h:906
double & x(const unsigned &i)
Return the i-th nodal coordinate.
Definition nodes.h:1060
An oomph-lib wrapper to the MPI_Comm communicator object. Just contains an MPI_Comm object (which is ...
An OomphLibError object which should be thrown when an run-time error is encountered....
An OomphLibWarning object which should be created as a temporary object to issue a warning....
Base class for refineable meshes. Provides standardised interfaces for the following standard mesh ad...
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 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.
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.
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....
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.
General SolidMesh class.
Definition mesh.h:2570
void set_lagrangian_nodal_coordinates()
Make the current configuration the undeformed one by setting the nodal Lagrangian coordinates to thei...
Definition mesh.cc:9564
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.
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
Base class for time-stepping schemes. Timestepper provides an approximation of the temporal derivativ...
Base class for triangle meshes (meshes made of 2D triangle elements). Note: we choose to template Tri...
TriangulateIO Triangulateio
TriangulateIO representation of the mesh.
Base class defining a closed curve for the Triangle mesh generation.
Base class defining an open curve for the Triangle mesh generation Basically used to define internal ...
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.
Class defining a polyline for use in Triangle Mesh generation.
Class defining a closed polygon for the Triangle mesh generation.
Triangle mesh build with the help of the scaffold mesh coming from the triangle mesh generator Triang...
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 add_face_index_at_shared_boundary(const unsigned &b, const unsigned &i)
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
Triangle Mesh that is based on input files generated by the triangle mesh generator Triangle.
Vector< TriangleMeshOpenCurve * > Internal_open_curve_pt
Vector of open polylines that define internal curves.
bool is_automatic_creation_of_vertices_on_boundaries_allowed()
Returns the status of the variable Allow_automatic_creation_of_vertices_on_boundaries.
Vector< TriangleMeshPolygon * > Outer_boundary_pt
Polygon that defines outer boundaries.
Vector< TriangleMeshPolygon * > Internal_polygon_pt
Vector of polygons that define internal polygons.
void snap_nodes_onto_geometric_objects()
Snap the boundary nodes onto any curvilinear boundaries defined by geometric objects.
TriangleMeshOpenCurve * create_open_curve_with_polyline_helper(TriangleMeshOpenCurve *open_curve_pt, unsigned &max_bnd_id_local)
Helper function that creates and returns an open curve with the polyline representation of its consti...
std::map< unsigned, Vector< Vector< Node * > > > Boundary_segment_node_pt
Used to store the nodes associated to a boundary and to an specific segment (this only applies in dis...
std::map< unsigned, Vector< double > > Regions_coordinates
Storage for extra coordinates for regions. The key on the map is the region id.
Vector< Vector< double > > Extra_holes_coordinates
Storage for extra coordinates for holes.
bool Allow_automatic_creation_of_vertices_on_boundaries
Flag to indicate whether the automatic creation of vertices along the boundaries by Triangle is allow...
Vector< std::map< unsigned, Vector< FiniteElement * > > > Boundary_region_element_pt
Storage for elements adjacent to a boundary in a particular region.
Vector< double > Region_attribute
Vector of attributes associated with the elements in each region.
Vector< std::map< unsigned, Vector< int > > > Face_index_region_at_boundary
Storage for the face index adjacent to a boundary in a particular region.
TriangleMeshPolygon * closed_curve_to_polygon_helper(TriangleMeshClosedCurve *closed_curve_pt, unsigned &max_bnd_id_local)
Helper function that returns a polygon representation for the given closed curve, it also computes th...
std::set< TriangleMeshOpenCurve * > Free_open_curve_pt
A set that contains the open curves created by this object therefore it is necessary to free their as...
std::set< TriangleMeshCurveSection * > Free_curve_section_pt
A set that contains the curve sections created by this object therefore it is necessary to free their...
std::map< unsigned, Vector< std::pair< double, double > > > Polygonal_vertex_arclength_info
Storage for pairs of doubles representing: .first: the arclength along the polygonal representation o...
std::set< TriangleMeshPolygon * > Free_polygon_pt
A set that contains the polygons created by this object therefore it is necessary to free their assoc...
std::map< unsigned, Vector< FiniteElement * > > Region_element_pt
Vector of elements in each region differentiated by attribute (the key of the map is the attribute)
void build_triangulateio(Vector< TriangleMeshPolygon * > &outer_polygons_pt, Vector< TriangleMeshPolygon * > &internal_polygons_pt, Vector< TriangleMeshOpenCurve * > &open_curves_pt, Vector< Vector< double > > &extra_holes_coordinates, std::map< unsigned, Vector< double > > &regions_coordinates, std::map< unsigned, double > &regions_areas, TriangulateIO &triangulate_io)
Create TriangulateIO object from outer boundaries, internal boundaries, and open curves....
void set_geom_objects_and_coordinate_limits_for_open_curve(TriangleMeshOpenCurve *input_open_curve_pt)
Stores the geometric objects associated to the curve sections that compound the open curve....
void set_geom_objects_and_coordinate_limits_for_close_curve(TriangleMeshClosedCurve *input_closed_curve_pt)
Stores the geometric objects associated to the curve sections that compound the closed curve....
std::map< unsigned, TriangleMeshCurveSection * > Boundary_curve_section_pt
A map that stores the associated curve section of the specified boundary id.
A slight extension to the standard template vector class so that we can include "graceful" array rang...
Definition Vector.h:58
const double Pi
50 digits from maple
void create_triangulateio_from_polyfiles(const std::string &node_file_name, const std::string &element_file_name, const std::string &poly_file_name, TriangulateIO &triangle_io, bool &use_attributes)
Create a triangulateio data file from ele node and poly files. This is used if the mesh is generated ...
void initialise_triangulateio(TriangulateIO &triangle_io)
Initialise TriangulateIO structure.
void clear_triangulateio(TriangulateIO &triangulate_io, const bool &clear_hole_data)
Clear TriangulateIO structure.
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
void triangulate(char *triswitches, struct oomph::TriangulateIO *in, struct oomph::TriangulateIO *out, struct oomph::TriangulateIO *vorout)
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...
bool operator<(const Point &p) const
The Triangle data structure, modified from the triangle.h header supplied with triangle 1....
double * pointlist
Pointer to list of points x coordinate followed by y coordinate.