https://mooseframework.inl.gov
Public Member Functions | Private Attributes | List of all members
MortarSegmentHelper Class Reference

This class supports defining mortar segment mesh elements in 3D by projecting secondary and primary elements onto a linearized plane, computing the overlapping polygon formed by their projections, and triangulating the resulting nodes. More...

#include <MortarSegmentHelper.h>

Public Member Functions

 MortarSegmentHelper (const std::vector< Point > secondary_nodes, const Point &center, const Point &normal)
 
Point getIntersection (const Point &p1, const Point &p2, const Point &q1, const Point &q2, Real &s) const
 Computes the intersection between line segments defined by point pairs (p1,p2) and (q1,q2) Also computes s, the ratio of distance between (p1,p2) that the intersection falls, quantity s is useful in avoiding adding nearly degenerate nodes. More...
 
bool isInsideSecondary (const Point &pt) const
 Check that a point is inside the secondary polygon (for verification only) More...
 
bool isDisjoint (const std::vector< Point > &poly) const
 Checks whether polygons are disjoint for an easy out. More...
 
std::vector< PointclipPoly (const std::vector< Point > &primary_nodes) const
 Clip secondary element (defined in instantiation) against given primary polygon result is a set of 2D nodes defining clipped polygon. More...
 
void triangulatePoly (std::vector< Point > &poly_nodes, const unsigned int offset, std::vector< std::vector< unsigned int >> &tri_map) const
 Triangulate a polygon (currently uses center of polygon to define triangulation) More...
 
void getMortarSegments (const std::vector< Point > &primary_nodes, std::vector< Point > &nodes, std::vector< std::vector< unsigned int >> &elem_to_nodes)
 Get mortar segments generated by a secondary and primary element pair. More...
 
Real area (const std::vector< Point > &nodes) const
 Compute area of polygon. More...
 
const Pointcenter () const
 Get center point of secondary element. More...
 
Real remainder () const
 Get area fraction remaining after clipping against primary elements. More...
 
Point point (unsigned int i) const
 Get 3D position of node of linearized secondary element. More...
 

Private Attributes

Point _center
 Geometric center of secondary element. More...
 
Point _normal
 Normal at geometric center of secondary element. More...
 
Point _u
 Vectors orthogonal to normal that span the plane projection will be performed on. More...
 
Point _v
 
Real _secondary_area
 Area of projected secondary element. More...
 
Real _remaining_area_fraction
 Fraction of area remaining after overlapping primary polygons clipped. More...
 
bool _debug
 
Real _tolerance = 1e-8
 Tolerance for intersection and clipping. More...
 
Real _area_tol
 Tolerance times secondary area for dimensional consistency. More...
 
Real _length_tol
 Tolerance times secondary area for dimensional consistency. More...
 
std::vector< Point_secondary_poly
 List of projected points on the linearized secondary element. More...
 

Detailed Description

This class supports defining mortar segment mesh elements in 3D by projecting secondary and primary elements onto a linearized plane, computing the overlapping polygon formed by their projections, and triangulating the resulting nodes.

Definition at line 26 of file MortarSegmentHelper.h.

Constructor & Destructor Documentation

◆ MortarSegmentHelper()

MortarSegmentHelper::MortarSegmentHelper ( const std::vector< Point secondary_nodes,
const Point center,
const Point normal 
)

Definition at line 16 of file MortarSegmentHelper.C.

19  : _center(center), _normal(normal), _debug(false)
20 {
21  _secondary_poly.clear();
22  _secondary_poly.reserve(secondary_nodes.size());
23 
24  // Get orientation of secondary poly
25  const Point e1 = secondary_nodes[0] - secondary_nodes[1];
26  const Point e2 = secondary_nodes[2] - secondary_nodes[1];
27  const Real orient = e2.cross(e1) * _normal;
28 
29  // u and v define the tangent plane of the element (at center)
30  // Note we embed orientation into our transformation to make 2D poly always
31  // positively oriented
32  _u = _normal.cross(secondary_nodes[0] - center).unit();
33  _v = (orient > 0) ? _normal.cross(_u).unit() : _u.cross(_normal).unit();
34 
35  // Transform problem to 2D plane spanned by u and v
36  for (const auto & node : secondary_nodes)
37  {
38  Point pt = node - _center;
39  _secondary_poly.emplace_back(pt * _u, pt * _v, 0);
40  }
41 
42  // Initialize area of secondary polygon
45 
46  // Tolerance for quantities with area dimensions
48 
49  // Tolerance for quantites with length dimensions
51 }
Point _center
Geometric center of secondary element.
Real _area_tol
Tolerance times secondary area for dimensional consistency.
Real _length_tol
Tolerance times secondary area for dimensional consistency.
std::vector< Point > _secondary_poly
List of projected points on the linearized secondary element.
Real _tolerance
Tolerance for intersection and clipping.
Point _u
Vectors orthogonal to normal that span the plane projection will be performed on. ...
Real _secondary_area
Area of projected secondary element.
Point _normal
Normal at geometric center of secondary element.
const Point & center() const
Get center point of secondary element.
Real area(const std::vector< Point > &nodes) const
Compute area of polygon.
TypeVector< typename CompareTypes< Real, T2 >::supertype > cross(const TypeVector< T2 > &v) const
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sqrt(_arg)) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tanh
Real _remaining_area_fraction
Fraction of area remaining after overlapping primary polygons clipped.

Member Function Documentation

◆ area()

Real MortarSegmentHelper::area ( const std::vector< Point > &  nodes) const

Compute area of polygon.

Definition at line 320 of file MortarSegmentHelper.C.

Referenced by getMortarSegments(), and MortarSegmentHelper().

321 {
322  Real poly_area = 0;
323  for (auto i : index_range(nodes))
324  poly_area += nodes[i](0) * nodes[(i + 1) % nodes.size()](1) -
325  nodes[i](1) * nodes[(i + 1) % nodes.size()](0);
326  poly_area *= 0.5;
327  return poly_area;
328 }
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
auto index_range(const T &sizable)

◆ center()

const Point& MortarSegmentHelper::center ( ) const
inline

Get center point of secondary element.

Definition at line 85 of file MortarSegmentHelper.h.

Referenced by MortarSegmentHelper().

85 { return _center; }
Point _center
Geometric center of secondary element.

◆ clipPoly()

std::vector< Point > MortarSegmentHelper::clipPoly ( const std::vector< Point > &  primary_nodes) const

Clip secondary element (defined in instantiation) against given primary polygon result is a set of 2D nodes defining clipped polygon.

Definition at line 122 of file MortarSegmentHelper.C.

Referenced by getMortarSegments().

123 {
124  // Check orientation of primary_poly
125  const Point e1 = primary_nodes[0] - primary_nodes[1];
126  const Point e2 = primary_nodes[2] - primary_nodes[1];
127 
128  // Note we use u x v here instead of normal because it may be flipped if secondary elem was
129  // negatively oriented
130  const Real orient = e2.cross(e1) * _u.cross(_v);
131 
132  // Get primary_poly (primary is clipping poly). If negatively oriented, reverse
133  std::vector<Point> primary_poly;
134  const int n_verts = primary_nodes.size();
135  for (auto n : index_range(primary_nodes))
136  {
137  Point pt = (orient > 0) ? primary_nodes[n] - _center : primary_nodes[n_verts - 1 - n] - _center;
138  primary_poly.emplace_back(pt * _u, pt * _v, 0.);
139  }
140 
141  if (isDisjoint(primary_poly))
142  {
143  primary_poly.clear();
144  return primary_poly;
145  }
146 
147  // Initialize clipped poly with secondary poly (secondary is target poly)
148  std::vector<Point> clipped_poly = _secondary_poly;
149 
150  // Loop through clipping edges
151  for (auto i : index_range(primary_poly))
152  {
153  // If clipped poly trivial, return
154  if (clipped_poly.size() < 3)
155  {
156  clipped_poly.clear();
157  return clipped_poly;
158  }
159 
160  // Set input poly to current clipped poly
161  std::vector<Point> input_poly(clipped_poly);
162  clipped_poly.clear();
163 
164  // Get clipping edge
165  const Point & clip_pt1 = primary_poly[i];
166  const Point & clip_pt2 = primary_poly[(i + 1) % primary_poly.size()];
167  const Point edg = clip_pt2 - clip_pt1;
168  const Real cp = clip_pt2(0) * clip_pt1(1) - clip_pt2(1) * clip_pt1(0);
169 
170  // Check if point is to the left of (or on) clip_edge
171  /*
172  * Note that use of tolerance here is to avoid degenerate case when lines are
173  * essentially on top of each other (common when meshes match across interface)
174  * since finding intersection is ill-conditioned in this case.
175  */
176  auto is_inside = [&edg, cp](const Point & pt, Real tol)
177  { return pt(0) * edg(1) - pt(1) * edg(0) + cp < tol; };
178 
179  // Loop through edges of target polygon (with previous clippings already included)
180  for (auto j : index_range(input_poly))
181  {
182  // Get target edge
183  const Point curr_pt = input_poly[(j + 1) % input_poly.size()];
184  const Point prev_pt = input_poly[j];
185 
186  // TODO: Don't need to calculate both each loop
187  const bool is_current_inside = is_inside(curr_pt, _area_tol);
188  const bool is_previous_inside = is_inside(prev_pt, _area_tol);
189 
190  if (is_current_inside)
191  {
192  if (!is_previous_inside)
193  {
194  Real s;
195  Point intersect = getIntersection(prev_pt, curr_pt, clip_pt1, clip_pt2, s);
196 
197  /*
198  * s is the fraction of distance along clip poly edge that intersection lies
199  * It is used here to avoid degenerate polygon cases. For example, consider a
200  * case like:
201  * o
202  * | (inside)
203  * ------|------
204  * | (outside)
205  * when the distance is small (< 1e-7) we don't want to to add both the point
206  * and intersection. Also note that when distance on the scale of 1e-7,
207  * area on scale of 1e-14 so is insignificant if this results in dropping
208  * a tri (for example if next edge crosses again)
209  */
210  if (s < (1 - _tolerance))
211  clipped_poly.push_back(intersect);
212  }
213  clipped_poly.push_back(curr_pt);
214  }
215  else if (is_previous_inside)
216  {
217  Real s;
218  Point intersect = getIntersection(prev_pt, curr_pt, clip_pt1, clip_pt2, s);
219  if (s > _tolerance)
220  clipped_poly.push_back(intersect);
221  }
222  }
223  }
224 
225  // return clipped_poly;
226  // Make sure final clipped poly is not trivial
227  if (clipped_poly.size() < 3)
228  {
229  clipped_poly.clear();
230  return clipped_poly;
231  }
232 
233  // Clean up result by removing any duplicate nodes
234  std::vector<Point> cleaned_poly;
235 
236  cleaned_poly.push_back(clipped_poly.back());
237  for (auto i : make_range(clipped_poly.size() - 1))
238  {
239  const Point prev_pt = cleaned_poly.back();
240  const Point curr_pt = clipped_poly[i];
241 
242  // If points are sufficiently distanced, add to output
243  if ((curr_pt - prev_pt).norm() > _length_tol)
244  cleaned_poly.push_back(curr_pt);
245  }
246 
247  return cleaned_poly;
248 }
Point _center
Geometric center of secondary element.
Real _area_tol
Tolerance times secondary area for dimensional consistency.
Real _length_tol
Tolerance times secondary area for dimensional consistency.
std::vector< Point > _secondary_poly
List of projected points on the linearized secondary element.
Real _tolerance
Tolerance for intersection and clipping.
Point _u
Vectors orthogonal to normal that span the plane projection will be performed on. ...
bool isDisjoint(const std::vector< Point > &poly) const
Checks whether polygons are disjoint for an easy out.
TypeVector< typename CompareTypes< Real, T2 >::supertype > cross(const TypeVector< T2 > &v) const
auto norm(const T &a) -> decltype(std::abs(a))
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)
Point getIntersection(const Point &p1, const Point &p2, const Point &q1, const Point &q2, Real &s) const
Computes the intersection between line segments defined by point pairs (p1,p2) and (q1...
auto index_range(const T &sizable)

◆ getIntersection()

Point MortarSegmentHelper::getIntersection ( const Point p1,
const Point p2,
const Point q1,
const Point q2,
Real s 
) const

Computes the intersection between line segments defined by point pairs (p1,p2) and (q1,q2) Also computes s, the ratio of distance between (p1,p2) that the intersection falls, quantity s is useful in avoiding adding nearly degenerate nodes.

Definition at line 54 of file MortarSegmentHelper.C.

Referenced by clipPoly().

56 {
57  const Point dp = p2 - p1;
58  const Point dq = q2 - q1;
59  const Real cp1q1 = p1(0) * q1(1) - p1(1) * q1(0);
60  const Real cp1q2 = p1(0) * q2(1) - p1(1) * q2(0);
61  const Real cq1q2 = q1(0) * q2(1) - q1(1) * q2(0);
62  const Real alpha = 1. / (dp(0) * dq(1) - dp(1) * dq(0));
63  s = -alpha * (cp1q2 - cp1q1 - cq1q2);
64 
65  // Intersection should be between p1 and p2, if it's not (due to poor conditioning), simply
66  // move it to one of the end points
67  s = s > 1 ? 1. : s;
68  s = s < 0 ? 0. : s;
69  return p1 + s * dp;
70 }
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

◆ getMortarSegments()

void MortarSegmentHelper::getMortarSegments ( const std::vector< Point > &  primary_nodes,
std::vector< Point > &  nodes,
std::vector< std::vector< unsigned int >> &  elem_to_nodes 
)

Get mortar segments generated by a secondary and primary element pair.

Parameters
primary_nodesList of primary element 3D nodes
Returns
nodes List of 3D mortar segment nodes
tri_map List of integer arrays defining which nodes belong to each mortar segment

Definition at line 294 of file MortarSegmentHelper.C.

297 {
298  // Clip primary elem against secondary elem
299  std::vector<Point> clipped_poly = clipPoly(primary_nodes);
300  if (clipped_poly.size() < 3)
301  return;
302 
303  if (_debug)
304  for (auto pt : clipped_poly)
305  if (!isInsideSecondary(pt))
306  mooseError("Clipped polygon not inside linearized secondary element");
307 
308  // Compute area of clipped polygon, update remaining area fraction
309  _remaining_area_fraction -= area(clipped_poly) / _secondary_area;
310 
311  // Triangulate clip polygon
312  triangulatePoly(clipped_poly, nodes.size(), elem_to_nodes);
313 
314  // Transform clipped poly back to (linearized) 3d and append to list
315  for (auto pt : clipped_poly)
316  nodes.emplace_back((pt(0) * _u) + (pt(1) * _v) + _center);
317 }
Point _center
Geometric center of secondary element.
bool isInsideSecondary(const Point &pt) const
Check that a point is inside the secondary polygon (for verification only)
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:302
std::vector< Point > clipPoly(const std::vector< Point > &primary_nodes) const
Clip secondary element (defined in instantiation) against given primary polygon result is a set of 2D...
Point _u
Vectors orthogonal to normal that span the plane projection will be performed on. ...
Real _secondary_area
Area of projected secondary element.
Real area(const std::vector< Point > &nodes) const
Compute area of polygon.
Real _remaining_area_fraction
Fraction of area remaining after overlapping primary polygons clipped.
void triangulatePoly(std::vector< Point > &poly_nodes, const unsigned int offset, std::vector< std::vector< unsigned int >> &tri_map) const
Triangulate a polygon (currently uses center of polygon to define triangulation)

◆ isDisjoint()

bool MortarSegmentHelper::isDisjoint ( const std::vector< Point > &  poly) const

Checks whether polygons are disjoint for an easy out.

Definition at line 95 of file MortarSegmentHelper.C.

Referenced by clipPoly().

96 {
97  for (auto i : index_range(_secondary_poly))
98  {
99  // Get edge to check
100  const Point & q1 = _secondary_poly[i];
101  const Point & q2 = _secondary_poly[(i + 1) % _secondary_poly.size()];
102  const Point edg = q2 - q1;
103  const Real cp = q2(0) * q1(1) - q2(1) * q1(0);
104 
105  // If more optimization needed, could store these values for later
106  // Check if point is to the left of (or on) clip_edge
107  auto is_inside = [&edg, cp](Point & pt, Real tol)
108  { return pt(0) * edg(1) - pt(1) * edg(0) + cp < -tol; };
109 
110  bool all_outside = true;
111  for (auto pt : poly)
112  if (is_inside(pt, _area_tol))
113  all_outside = false;
114 
115  if (all_outside)
116  return true;
117  }
118  return false;
119 }
Real _area_tol
Tolerance times secondary area for dimensional consistency.
R poly(const C &c, const T x, const bool derivative=false)
Evaluate a polynomial with the coefficients c at x.
Definition: MathUtils.h:237
std::vector< Point > _secondary_poly
List of projected points on the linearized secondary element.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
auto index_range(const T &sizable)

◆ isInsideSecondary()

bool MortarSegmentHelper::isInsideSecondary ( const Point pt) const

Check that a point is inside the secondary polygon (for verification only)

Definition at line 73 of file MortarSegmentHelper.C.

Referenced by getMortarSegments().

74 {
75  for (auto i : index_range(_secondary_poly))
76  {
77  const Point & q1 = _secondary_poly[i];
78  const Point & q2 = _secondary_poly[(i + 1) % _secondary_poly.size()];
79 
80  const Point e1 = q2 - q1;
81  const Point e2 = pt - q1;
82 
83  // If point corresponds to one of the secondary vertices, skip
84  if (e2.norm() < _tolerance)
85  return true;
86 
87  bool inside = (e1(0) * e2(1) - e1(1) * e2(0)) < _area_tol;
88  if (!inside)
89  return false;
90  }
91  return true;
92 }
Real _area_tol
Tolerance times secondary area for dimensional consistency.
auto norm() const -> decltype(std::norm(Real()))
std::vector< Point > _secondary_poly
List of projected points on the linearized secondary element.
Real _tolerance
Tolerance for intersection and clipping.
auto index_range(const T &sizable)

◆ point()

Point MortarSegmentHelper::point ( unsigned int  i) const
inline

Get 3D position of node of linearized secondary element.

Definition at line 95 of file MortarSegmentHelper.h.

96  {
97  return (_secondary_poly[i](0) * _u) + (_secondary_poly[i](1) * _v) + _center;
98  }
Point _center
Geometric center of secondary element.
std::vector< Point > _secondary_poly
List of projected points on the linearized secondary element.
Point _u
Vectors orthogonal to normal that span the plane projection will be performed on. ...

◆ remainder()

Real MortarSegmentHelper::remainder ( ) const
inline

Get area fraction remaining after clipping against primary elements.

Definition at line 90 of file MortarSegmentHelper.h.

90 { return _remaining_area_fraction; }
Real _remaining_area_fraction
Fraction of area remaining after overlapping primary polygons clipped.

◆ triangulatePoly()

void MortarSegmentHelper::triangulatePoly ( std::vector< Point > &  poly_nodes,
const unsigned int  offset,
std::vector< std::vector< unsigned int >> &  tri_map 
) const

Triangulate a polygon (currently uses center of polygon to define triangulation)

Parameters
poly_nodesList of 2D nodes defining polygon
offsetCurrent size of 3D nodes array (not poly_nodes)
Returns
tri_map List of integer arrays defining which nodes belong to each triangle

Definition at line 251 of file MortarSegmentHelper.C.

Referenced by getMortarSegments().

254 {
255  // Note offset is important because it converts from list of nodes on local poly to list of
256  // nodes on entire element. This is a sloppy and error-prone way to do this.
257  // Could be redesigned by just building and adding elements inside helper, but leaving for now
258  // to keep buildMortarSegmentMesh similar for 2D and 3D
259 
260  // Fewer than 3 nodes can't be triangulated
261  if (poly_nodes.size() < 3)
262  mooseError("Can't triangulate poly with fewer than 3 nodes");
263  // If 3 nodes, already a triangle, simply pass back map
264  else if (poly_nodes.size() == 3)
265  {
266  tri_map.push_back({0 + offset, 1 + offset, 2 + offset});
267  return;
268  }
269  // Otherwise use simple center point triangulation
270  // Note: Could use better algorithm to reduce number of triangles
271  // - Delaunay produces good quality triangulation but might be a bit overkill
272  // - Monotone polygon triangulation algorithm is O(N) but quality is not guaranteed
273  else
274  {
275  Point poly_center;
276  const unsigned int n_verts = poly_nodes.size();
277 
278  // Get geometric center of polygon
279  for (auto node : poly_nodes)
280  poly_center += node;
281  poly_center /= n_verts;
282 
283  // Add triangles formed by outer edge and center point
284  for (auto i : make_range(n_verts))
285  tri_map.push_back({i + offset, (i + 1) % n_verts + offset, n_verts + offset});
286 
287  // Add center point to list of polygon nodes
288  poly_nodes.push_back(poly_center);
289  return;
290  }
291 }
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:302
IntRange< T > make_range(T beg, T end)

Member Data Documentation

◆ _area_tol

Real MortarSegmentHelper::_area_tol
private

Tolerance times secondary area for dimensional consistency.

Definition at line 138 of file MortarSegmentHelper.h.

Referenced by clipPoly(), isDisjoint(), isInsideSecondary(), and MortarSegmentHelper().

◆ _center

Point MortarSegmentHelper::_center
private

Geometric center of secondary element.

Definition at line 104 of file MortarSegmentHelper.h.

Referenced by center(), clipPoly(), getMortarSegments(), MortarSegmentHelper(), and point().

◆ _debug

bool MortarSegmentHelper::_debug
private

Definition at line 128 of file MortarSegmentHelper.h.

Referenced by getMortarSegments().

◆ _length_tol

Real MortarSegmentHelper::_length_tol
private

Tolerance times secondary area for dimensional consistency.

Definition at line 143 of file MortarSegmentHelper.h.

Referenced by clipPoly(), and MortarSegmentHelper().

◆ _normal

Point MortarSegmentHelper::_normal
private

Normal at geometric center of secondary element.

Definition at line 109 of file MortarSegmentHelper.h.

Referenced by MortarSegmentHelper().

◆ _remaining_area_fraction

Real MortarSegmentHelper::_remaining_area_fraction
private

Fraction of area remaining after overlapping primary polygons clipped.

Definition at line 126 of file MortarSegmentHelper.h.

Referenced by getMortarSegments(), MortarSegmentHelper(), and remainder().

◆ _secondary_area

Real MortarSegmentHelper::_secondary_area
private

Area of projected secondary element.

Definition at line 121 of file MortarSegmentHelper.h.

Referenced by getMortarSegments(), and MortarSegmentHelper().

◆ _secondary_poly

std::vector<Point> MortarSegmentHelper::_secondary_poly
private

List of projected points on the linearized secondary element.

Definition at line 148 of file MortarSegmentHelper.h.

Referenced by clipPoly(), isDisjoint(), isInsideSecondary(), MortarSegmentHelper(), and point().

◆ _tolerance

Real MortarSegmentHelper::_tolerance = 1e-8
private

Tolerance for intersection and clipping.

Definition at line 133 of file MortarSegmentHelper.h.

Referenced by clipPoly(), isInsideSecondary(), and MortarSegmentHelper().

◆ _u

Point MortarSegmentHelper::_u
private

Vectors orthogonal to normal that span the plane projection will be performed on.

These vectors are used to project the polygon clipping problem on a 2D plane, they are defined so the nodes of the projected polygon are listed with positive orientation

Definition at line 116 of file MortarSegmentHelper.h.

Referenced by clipPoly(), getMortarSegments(), MortarSegmentHelper(), and point().

◆ _v

Point MortarSegmentHelper::_v
private

Definition at line 116 of file MortarSegmentHelper.h.

Referenced by clipPoly(), getMortarSegments(), MortarSegmentHelper(), and point().


The documentation for this class was generated from the following files: