Skip to content

Commit eb665c3

Browse files
author
Andreas Henrik Frederiksen
committed
Add selectable 3D mortar triangulation options
- add triangulation selection for 3D mortar contact - add triangulate_triangles control for triangular polygons - add regression coverage for centroid, ear_clipping, and delaunay paths refs #32816
1 parent a5a619e commit eb665c3

13 files changed

Lines changed: 1022 additions & 110 deletions

File tree

framework/include/constraints/AutomaticMortarGeneration.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@ class AutomaticMortarGeneration : public ConsoleStreamInterface
7474
bool periodic,
7575
const bool debug,
7676
const bool correct_edge_dropping,
77-
const Real minimum_projection_angle);
77+
const Real minimum_projection_angle,
78+
const MortarSegmentTriangulationMode triangulation_mode,
79+
const bool triangulate_triangles);
7880

7981
/**
8082
* Once the secondary_requested_boundary_ids and
@@ -516,6 +518,12 @@ class AutomaticMortarGeneration : public ConsoleStreamInterface
516518
/// segment mesh in extreme cases. This parameter is mostly intended for mortar mesh debugging purposes in 2D.
517519
const Real _minimum_projection_angle;
518520

521+
/// Triangulation mode used for clipped 3D mortar polygons.
522+
const MortarSegmentTriangulationMode _triangulation_mode;
523+
524+
/// Whether already-triangular clipped polygons should still be centroid-subdivided.
525+
const bool _triangulate_triangles;
526+
519527
/// Storage for the input parameters used by the mortar nodal geometry output
520528
std::unique_ptr<InputParameters> _output_params;
521529

framework/include/constraints/MortarInterfaceWarehouse.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616

1717
#include <unordered_map>
1818
#include <set>
19+
#include <string>
1920

2021
class SubProblem;
2122
class MortarExecutorInterface;
2223
class AutomaticMortarGeneration;
24+
class MooseEnum;
2325

2426
class MortarInterfaceWarehouse : public libMesh::ParallelObject
2527
{
@@ -39,6 +41,9 @@ class MortarInterfaceWarehouse : public libMesh::ParallelObject
3941
* @param correct_edge_dropping edge dropping treatment selection
4042
* @param minimum_projection_angle minimum projection angle allowed for building mortar segment
4143
* mesh
44+
* @param triangulation triangulation strategy used for clipped 3D mortar polygons
45+
* @param triangulate_triangles whether a clipped polygon that is already a triangle should still
46+
* be subdivided
4247
*/
4348
void createMortarInterface(const std::pair<BoundaryID, BoundaryID> & boundary_key,
4449
const std::pair<SubdomainID, SubdomainID> & subdomain_key,
@@ -47,7 +52,9 @@ class MortarInterfaceWarehouse : public libMesh::ParallelObject
4752
bool periodic,
4853
const bool debug,
4954
const bool correct_edge_dropping,
50-
const Real minimum_projection_angle);
55+
const Real minimum_projection_angle,
56+
const MooseEnum & triangulation,
57+
const bool triangulate_triangles);
5158

5259
/**
5360
* Getter to retrieve the AutomaticMortarGeneration object corresponding to the boundary and
@@ -165,6 +172,18 @@ class MortarInterfaceWarehouse : public libMesh::ParallelObject
165172
/// Map from displaced AMG key to whether the displaced AMG object is to output mortar segment mesh
166173
std::unordered_map<MortarKey, bool> _displaced_debug_flag_map;
167174

175+
/// Map from undisplaced AMG key to the selected mortar segment triangulation strategy
176+
std::unordered_map<MortarKey, std::string> _mortar_segment_triangulation_map;
177+
178+
/// Map from displaced AMG key to the selected mortar segment triangulation strategy
179+
std::unordered_map<MortarKey, std::string> _displaced_mortar_segment_triangulation_map;
180+
181+
/// Map from undisplaced AMG key to whether already-triangular polygons are further subdivided
182+
std::unordered_map<MortarKey, bool> _triangulate_triangles_map;
183+
184+
/// Map from displaced AMG key to whether already-triangular polygons are further subdivided
185+
std::unordered_map<MortarKey, bool> _displaced_triangulate_triangles_map;
186+
168187
/// Map from lower dimensional subdomain ids to corresponding higher simensional subdomain ids
169188
/// (e.g. the ids of the interior parents)
170189
std::unordered_map<SubdomainID, std::set<SubdomainID>> _lower_d_sub_to_higher_d_subs;

framework/include/constraints/MortarSegmentHelper.h

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
#pragma once
1111

12+
#include "MortarSegmentInfo.h"
13+
1214
#include "libmesh/point.h"
1315
#include "libmesh/int_range.h"
1416

@@ -28,7 +30,9 @@ class MortarSegmentHelper
2830
public:
2931
MortarSegmentHelper(const std::vector<Point> secondary_nodes,
3032
const Point & center,
31-
const Point & normal);
33+
const Point & normal,
34+
const MortarSegmentTriangulationMode triangulation_mode,
35+
const bool triangulate_triangles);
3236

3337
/**
3438
* Computes the intersection between line segments defined by point pairs (p1,p2) and (q1,q2)
@@ -48,14 +52,19 @@ class MortarSegmentHelper
4852
*/
4953
bool isDisjoint(const std::vector<Point> & poly) const;
5054

55+
/**
56+
* Project a primary polygon into the helper plane while preserving the clipping orientation.
57+
*/
58+
std::vector<Point> projectPrimaryPoly(const std::vector<Point> & primary_nodes) const;
59+
5160
/**
5261
* Clip secondary element (defined in instantiation) against given primary polygon
5362
* result is a set of 2D nodes defining clipped polygon
5463
*/
5564
std::vector<Point> clipPoly(const std::vector<Point> & primary_nodes) const;
5665

5766
/**
58-
* Triangulate a polygon (currently uses center of polygon to define triangulation)
67+
* Triangulate a polygon according to the configured mortar-segment triangulation mode.
5968
* @param poly_nodes List of 2D nodes defining polygon
6069
* @param offset Current size of 3D nodes array (not poly_nodes)
6170
* @return tri_map List of integer arrays defining which nodes belong to each triangle
@@ -132,6 +141,16 @@ class MortarSegmentHelper
132141
*/
133142
Real _tolerance = 1e-8;
134143

144+
/**
145+
* Triangulation mode used for clipped polygons.
146+
*/
147+
const MortarSegmentTriangulationMode _triangulation_mode;
148+
149+
/**
150+
* Whether already-triangular polygons should still be centroid-subdivided.
151+
*/
152+
const bool _triangulate_triangles;
153+
135154
/**
136155
* Tolerance times secondary area for dimensional consistency
137156
*/

framework/include/constraints/MortarSegmentInfo.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ class Elem;
2525
using libMesh::Elem;
2626
using libMesh::Real;
2727

28+
enum class MortarSegmentTriangulationMode : unsigned char
29+
{
30+
delaunay,
31+
centroid,
32+
ear_clipping,
33+
vertex
34+
};
35+
2836
/**
2937
* Holds xi^(1), xi^(2), and other data for a given mortar segment.
3038
*/

framework/include/problems/FEProblemBase.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1964,7 +1964,9 @@ class FEProblemBase : public SubProblem, public Restartable
19641964
bool periodic,
19651965
const bool debug,
19661966
const bool correct_edge_dropping,
1967-
const Real minimum_projection_angle);
1967+
const Real minimum_projection_angle,
1968+
const MooseEnum & triangulation,
1969+
const bool triangulate_triangles);
19681970

19691971
/**
19701972
* Return the undisplaced or displaced mortar generation object associated with the provided

framework/src/constraints/AutomaticMortarGeneration.C

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,9 @@ AutomaticMortarGeneration::AutomaticMortarGeneration(
223223
bool periodic,
224224
const bool debug,
225225
const bool correct_edge_dropping,
226-
const Real minimum_projection_angle)
226+
const Real minimum_projection_angle,
227+
const MortarSegmentTriangulationMode triangulation_mode,
228+
const bool triangulate_triangles)
227229
: ConsoleStreamInterface(app),
228230
_app(app),
229231
_mesh(mesh_in),
@@ -233,7 +235,9 @@ AutomaticMortarGeneration::AutomaticMortarGeneration(
233235
// We always ghost the entire mortar interface when it is allowed to displace
234236
_distributed(_on_displaced ? false : !_mesh.is_replicated()),
235237
_correct_edge_dropping(correct_edge_dropping),
236-
_minimum_projection_angle(minimum_projection_angle)
238+
_minimum_projection_angle(minimum_projection_angle),
239+
_triangulation_mode(triangulation_mode),
240+
_triangulate_triangles(triangulate_triangles)
237241
{
238242
_primary_secondary_boundary_id_pairs.push_back(boundary_key);
239243
_primary_requested_boundary_ids.insert(boundary_key.first);
@@ -1080,7 +1084,8 @@ AutomaticMortarGeneration::buildMortarSegmentMesh3d()
10801084
normal = normal.unit();
10811085

10821086
// Build and store linearized sub-elements for later use
1083-
mortar_segment_helper[sel] = std::make_unique<MortarSegmentHelper>(nodes, center, normal);
1087+
mortar_segment_helper[sel] = std::make_unique<MortarSegmentHelper>(
1088+
nodes, center, normal, _triangulation_mode, _triangulate_triangles);
10841089
}
10851090

10861091
/**

framework/src/constraints/MortarInterfaceWarehouse.C

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,55 @@
1111
#include "SubProblem.h"
1212
#include "MooseMesh.h"
1313
#include "MooseError.h"
14+
#include "MooseEnum.h"
1415
#include "MortarExecutorInterface.h"
1516
#include "AutomaticMortarGeneration.h"
1617

18+
namespace
19+
{
20+
struct ParsedMortarTriangulationOptions
21+
{
22+
MortarSegmentTriangulationMode mode = MortarSegmentTriangulationMode::vertex;
23+
std::string canonical_name = "vertex";
24+
};
25+
26+
ParsedMortarTriangulationOptions
27+
parseTriangulationOptions(const MooseEnum & triangulation)
28+
{
29+
ParsedMortarTriangulationOptions options;
30+
31+
if (triangulation == "vertex")
32+
{
33+
options.mode = MortarSegmentTriangulationMode::vertex;
34+
options.canonical_name = "vertex";
35+
return options;
36+
}
37+
if (triangulation == "centroid")
38+
{
39+
options.mode = MortarSegmentTriangulationMode::centroid;
40+
options.canonical_name = "centroid";
41+
return options;
42+
}
43+
if (triangulation == "ear_clipping")
44+
{
45+
options.mode = MortarSegmentTriangulationMode::ear_clipping;
46+
options.canonical_name = "ear_clipping";
47+
return options;
48+
}
49+
#if defined(LIBMESH_HAVE_TRIANGLE) || defined(LIBMESH_HAVE_POLY2TRI)
50+
if (triangulation == "delaunay")
51+
{
52+
options.mode = MortarSegmentTriangulationMode::delaunay;
53+
options.canonical_name = "delaunay";
54+
return options;
55+
}
56+
#endif
57+
58+
mooseError("Unsupported mortar triangulation option: ", triangulation);
59+
return options;
60+
}
61+
}
62+
1763
MortarInterfaceWarehouse::MortarInterfaceWarehouse(const libMesh::ParallelObject & other)
1864
: libMesh::ParallelObject(other), _mortar_initd(false)
1965
{
@@ -28,7 +74,9 @@ MortarInterfaceWarehouse::createMortarInterface(
2874
bool periodic,
2975
const bool debug,
3076
const bool correct_edge_dropping,
31-
const Real minimum_projection_angle)
77+
const Real minimum_projection_angle,
78+
const MooseEnum & triangulation,
79+
const bool triangulate_triangles)
3280
{
3381
_mortar_subdomain_coverage.insert(subdomain_key.first);
3482
_mortar_subdomain_coverage.insert(subdomain_key.second);
@@ -40,7 +88,15 @@ MortarInterfaceWarehouse::createMortarInterface(
4088

4189
auto & periodic_map = on_displaced ? _displaced_periodic_map : _periodic_map;
4290
auto & debug_flag_map = on_displaced ? _displaced_debug_flag_map : _debug_flag_map;
91+
auto & mortar_segment_triangulation_map = on_displaced
92+
? _displaced_mortar_segment_triangulation_map
93+
: _mortar_segment_triangulation_map;
94+
auto & triangulate_triangles_map =
95+
on_displaced ? _displaced_triangulate_triangles_map : _triangulate_triangles_map;
4396
auto & mortar_interfaces = on_displaced ? _displaced_mortar_interfaces : _mortar_interfaces;
97+
const auto parsed_options = parseTriangulationOptions(triangulation);
98+
const auto & mortar_segment_triangulation_name = parsed_options.canonical_name;
99+
const auto triangulation_mode = parsed_options.mode;
44100

45101
// Periodic flag
46102
auto periodic_map_iterator = periodic_map.find(boundary_key);
@@ -60,6 +116,26 @@ MortarInterfaceWarehouse::createMortarInterface(
60116
else
61117
debug_flag_map.insert(debug_flag_map_iterator, std::make_pair(boundary_key, debug));
62118

119+
auto mortar_segment_triangulation_map_iterator =
120+
mortar_segment_triangulation_map.find(boundary_key);
121+
if (mortar_segment_triangulation_map_iterator != mortar_segment_triangulation_map.end() &&
122+
mortar_segment_triangulation_map_iterator->second != mortar_segment_triangulation_name)
123+
mooseError("We do not currently support multiple values of 'triangulation' on the same "
124+
"boundary primary-secondary surface pair.");
125+
else
126+
mortar_segment_triangulation_map.insert(
127+
mortar_segment_triangulation_map_iterator,
128+
std::make_pair(boundary_key, mortar_segment_triangulation_name));
129+
130+
auto triangulate_triangles_map_iterator = triangulate_triangles_map.find(boundary_key);
131+
if (triangulate_triangles_map_iterator != triangulate_triangles_map.end() &&
132+
triangulate_triangles_map_iterator->second != triangulate_triangles)
133+
mooseError("We do not currently support multiple values of 'triangulate_triangles' on the "
134+
"same boundary primary-secondary surface pair.");
135+
else
136+
triangulate_triangles_map.insert(triangulate_triangles_map_iterator,
137+
std::make_pair(boundary_key, triangulate_triangles));
138+
63139
// Generate lower-d mesh
64140
if (mortar_interfaces.find(boundary_key) == mortar_interfaces.end())
65141
{
@@ -73,7 +149,9 @@ MortarInterfaceWarehouse::createMortarInterface(
73149
periodic,
74150
debug,
75151
correct_edge_dropping,
76-
minimum_projection_angle));
152+
minimum_projection_angle,
153+
triangulation_mode,
154+
triangulate_triangles));
77155
if (inserted)
78156
it->second->initOutput();
79157
}

0 commit comments

Comments
 (0)