Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://mooseframework.inl.gov
3 : //*
4 : //* All rights reserved, see COPYRIGHT for full restrictions
5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 : //*
7 : //* Licensed under LGPL 2.1, please see LICENSE for details
8 : //* https://www.gnu.org/licenses/lgpl-2.1.html
9 :
10 : #pragma once
11 :
12 : #include "MortarSegmentInfo.h"
13 : #include "Mortar3DSubpatchPlane.h"
14 : #include "MooseHashing.h"
15 : #include "ConsoleStreamInterface.h"
16 : #include "MooseError.h"
17 : #include "MooseUtils.h"
18 :
19 : // libMesh includes
20 : #include "libmesh/id_types.h"
21 : #include "libmesh/equation_systems.h"
22 : #include "libmesh/elem.h"
23 : #include "libmesh/int_range.h"
24 : #include "libmesh/vector_value.h"
25 :
26 : #include "metaphysicl/raw_type.h"
27 :
28 : // C++ includes
29 : #include <array>
30 : #include <cmath>
31 : #include <functional>
32 : #include <optional>
33 : #include <set>
34 : #include <memory>
35 : #include <vector>
36 : #include <unordered_map>
37 :
38 : // Forward declarations
39 : namespace libMesh
40 : {
41 : class MeshBase;
42 : class System;
43 : }
44 : class GetPot;
45 :
46 : // Using statements
47 : using libMesh::boundary_id_type;
48 : using libMesh::CompareDofObjectsByID;
49 : using libMesh::dof_id_type;
50 : using libMesh::Elem;
51 : using libMesh::MeshBase;
52 : using libMesh::Node;
53 : using libMesh::Point;
54 : using libMesh::Real;
55 : using libMesh::subdomain_id_type;
56 : using libMesh::VectorValue;
57 :
58 : typedef boundary_id_type BoundaryID;
59 : typedef subdomain_id_type SubdomainID;
60 :
61 : namespace Moose
62 : {
63 : namespace Mortar
64 : {
65 : /**
66 : * Construct the two tangent vectors used by mortar from a unit normal. The template keeps the
67 : * Real-valued and AD contact geometry on the same Householder chart and therefore gives them
68 : * identical values.
69 : * See Lopes, Silva, and Ambrosio, Computer-Aided Design 45(3), 2013, pp. 683-694.
70 : */
71 : template <typename Vector>
72 : std::array<Vector, 2>
73 43060 : householderTangents(const Vector & normal)
74 : {
75 : mooseAssert(MooseUtils::absoluteFuzzyEqual(MetaPhysicL::raw_value(normal.norm()), 1),
76 : "The input nodal normal should have unity norm");
77 :
78 43060 : const Vector h_vector(normal(0) + 1.0, normal(1), normal(2));
79 :
80 : // This chart is singular at (-1, 0, 0), where a constant orthonormal basis with zero
81 : // derivatives is used.
82 43060 : if (std::abs(MetaPhysicL::raw_value(h_vector(0))) < TOLERANCE)
83 1878 : return {{Vector(0, 1, 0), Vector(0, 0, -1)}};
84 :
85 41180 : const auto h = h_vector.norm();
86 41178 : return {{Vector(-2.0 * h_vector(0) * h_vector(1) / (h * h),
87 41178 : 1.0 - 2.0 * h_vector(1) * h_vector(1) / (h * h),
88 41178 : -2.0 * h_vector(1) * h_vector(2) / (h * h)),
89 41178 : Vector(-2.0 * h_vector(0) * h_vector(2) / (h * h),
90 41178 : -2.0 * h_vector(1) * h_vector(2) / (h * h),
91 205878 : 1.0 - 2.0 * h_vector(2) * h_vector(2) / (h * h))}};
92 4 : }
93 : }
94 : }
95 :
96 : /**
97 : * Parent-face reference coordinates associated with the vertices of one triangular mortar segment.
98 : */
99 : struct MortarSegmentReferencePoints
100 : {
101 : std::array<Point, 3> secondary_reference_points;
102 : std::array<Point, 3> primary_reference_points;
103 : };
104 :
105 : /**
106 : * This class is a container/interface for the objects involved in
107 : * automatic generation of mortar spaces.
108 : */
109 : class AutomaticMortarGeneration : public ConsoleStreamInterface
110 : {
111 : public:
112 : /**
113 : * The name of the nodal normals system. We store this in one place
114 : * so it's easy to change later.
115 : */
116 : const static std::string system_name;
117 :
118 : /**
119 : * Must be constructed with a reference to the Mesh we are
120 : * generating mortar spaces for.
121 : */
122 : AutomaticMortarGeneration(MooseApp & app,
123 : MeshBase & mesh_in,
124 : const std::pair<BoundaryID, BoundaryID> & boundary_key,
125 : const std::pair<SubdomainID, SubdomainID> & subdomain_key,
126 : bool on_displaced,
127 : bool periodic,
128 : const bool debug,
129 : const bool correct_edge_dropping,
130 : const Real minimum_projection_angle,
131 : const Mortar3DSubpatchPlane mortar_3d_subpatch_plane,
132 : const MortarSegmentTriangulationMode triangulation_mode,
133 : const bool triangulate_triangles,
134 : const Mortar3DQuadraturePointMapping mortar_3d_qp_mapping =
135 : Mortar3DQuadraturePointMapping::NORMAL_PROJECTION);
136 :
137 : /**
138 : * Once the secondary_requested_boundary_ids and
139 : * primary_requested_boundary_ids containers have been filled in,
140 : * call this function to build node-to-Elem maps for the
141 : * lower-dimensional elements.
142 : */
143 : void buildNodeToElemMaps();
144 :
145 : /**
146 : * Computes and stores the nodal normal/tangent vectors in a local data
147 : * structure instead of using the ExplicitSystem/NumericVector
148 : * approach. This design was triggered by the way that the
149 : * GhostingFunctor operates, but I think it is a better/more
150 : * efficient way to do it anyway.
151 : */
152 : void computeNodalGeometry();
153 :
154 : /**
155 : * Project secondary nodes (find xi^(2) values) to the closest points on
156 : * the primary surface.
157 : * Inputs:
158 : * - The nodal normals values
159 : * - mesh
160 : * - nodes_to_primary_elem_map
161 : *
162 : * Outputs:
163 : * - secondary_node_and_elem_to_xi2_primary_elem
164 : *
165 : * Defined in the file project_secondary_nodes.C.
166 : */
167 : void projectSecondaryNodes();
168 :
169 : /**
170 : * (Inverse) project primary nodes to the points on the secondary surface
171 : * where they would have come from (find (xi^(1) values)).
172 : *
173 : * Inputs:
174 : * - The nodal normals values
175 : * - mesh
176 : * - nodes_to_secondary_elem_map
177 : *
178 : * Outputs:
179 : * - primary_node_and_elem_to_xi1_secondary_elem
180 : *
181 : * Defined in the file project_primary_nodes.C.
182 : */
183 : void projectPrimaryNodes();
184 :
185 : /**
186 : * Builds the mortar segment mesh once the secondary and primary node
187 : * projections have been completed.
188 : *
189 : * Inputs:
190 : * - mesh
191 : * - primary_node_and_elem_to_xi1_secondary_elem
192 : * - secondary_node_and_elem_to_xi2_primary_elem
193 : * - nodes_to_primary_elem_map
194 : *
195 : * Outputs:
196 : * - mortar_segment_mesh
197 : * - msm_elem_to_info
198 : *
199 : * Defined in the file build_mortar_segment_mesh.C.
200 : */
201 : void buildMortarSegmentMesh();
202 :
203 : /**
204 : * Builds the mortar segment mesh once the secondary and primary node
205 : * projections have been completed.
206 : *
207 : * Inputs:
208 : * - mesh
209 : *
210 : * Outputs:
211 : * - mortar_segment_mesh
212 : * - msm_elem_to_info
213 : */
214 : void buildMortarSegmentMesh3d();
215 :
216 : /**
217 : * Statistics for one primary-secondary subdomain pair.
218 : * Secondary/primary lower-d stats reflect local data (all data for replicated meshes).
219 : */
220 : struct MsmSubdomainStats
221 : {
222 : SubdomainID primary_subd_id;
223 : SubdomainID secondary_subd_id;
224 : std::size_t secondary_lower_n_elems;
225 : Real secondary_lower_max_volume;
226 : Real secondary_lower_min_volume;
227 : Real secondary_lower_median_volume;
228 : std::size_t primary_lower_n_elems;
229 : Real primary_lower_max_volume;
230 : Real primary_lower_min_volume;
231 : Real primary_lower_median_volume;
232 : std::size_t msm_n_elems;
233 : Real msm_max_volume;
234 : Real msm_min_volume;
235 : Real msm_median_volume;
236 : };
237 :
238 : /**
239 : * Computes mortar segment mesh statistics and returns one entry per subdomain pair.
240 : * Must be called collectively on all ranks.
241 : */
242 : std::vector<MsmSubdomainStats> computeMsmStatistics();
243 :
244 : /**
245 : * Prints mortar segment mesh statistics to console (calls computeMsmStatistics internally)
246 : */
247 : void msmStatistics();
248 :
249 : /**
250 : * Clears the mortar segment mesh and accompanying data structures
251 : */
252 : void clear();
253 :
254 : /**
255 : * Invalidates the cached MSM node/element ID starting offset so that the next call to
256 : * buildMortarSegmentMesh3d() recomputes it via allgather. Call this when mesh topology changes.
257 : */
258 172 : void meshChanged() { _msm_node_id_start = std::nullopt; }
259 :
260 : /**
261 : * returns whether this object is on the displaced mesh
262 : */
263 : bool onDisplaced() const { return _on_displaced; }
264 :
265 : /**
266 : * @return The nodal normals associated with the provided \p secondary_elem
267 : */
268 : std::vector<Point> getNodalNormals(const Elem & secondary_elem) const;
269 :
270 : /**
271 : * Compute the two nodal tangents, which are built on-the-fly.
272 : * @return The nodal tangents associated with the provided \p secondary_elem
273 : */
274 : std::array<MooseUtils::SemidynamicVector<Point, 9>, 2>
275 : getNodalTangents(const Elem & secondary_elem) const;
276 :
277 : /**
278 : * Build the normalized JxW-weighted secondary nodal normals from AD nodal coordinates.
279 : *
280 : * The coordinate functor combines the node's displacement degrees of freedom with the coordinate
281 : * snapshot used to compute the stored nodal geometry. This keeps residual values and their
282 : * derivatives evaluated at the same geometry state.
283 : */
284 : void
285 : computeADNodalNormals(const std::function<ADPoint(const Node &, const Point &)> & coordinate,
286 : std::unordered_map<const Node *, ADRealVectorValue> & nodal_normals) const;
287 :
288 : /**
289 : * Compute on-the-fly mapping from secondary interior parent nodes to lower dimensional nodes
290 : * @return The map from secondary interior parent nodes to lower dimensional nodes
291 : */
292 : std::map<unsigned int, unsigned int>
293 : getSecondaryIpToLowerElementMap(const Elem & lower_secondary_elem) const;
294 :
295 : /**
296 : * Compute on-the-fly mapping from primary interior parent nodes to its corresponding lower
297 : * dimensional nodes
298 : * @return The map from primary interior parent nodes to its corresponding lower dimensional
299 : * nodes
300 : */
301 : std::map<unsigned int, unsigned int>
302 : getPrimaryIpToLowerElementMap(const Elem & primary_elem,
303 : const Elem & primary_elem_ip,
304 : const Elem & lower_secondary_elem) const;
305 :
306 : /**
307 : * Compute the normals at given reference points on a secondary element
308 : * @param secondary_elem The secondary element used to query for associated nodal normals
309 : * @param xi1_pts The reference points on the secondary element to evaluate the normals at. The
310 : * points should only be non-zero in the zeroth entry because right now our mortar mesh elements
311 : * are always 1D
312 : * @return The normals
313 : */
314 : std::vector<Point> getNormals(const Elem & secondary_elem,
315 : const std::vector<Point> & xi1_pts) const;
316 :
317 : /**
318 : * Compute the normals at given reference points on a secondary element
319 : * @param secondary_elem The secondary element used to query for associated nodal normals
320 : * @param 1d_xi1_pts The reference points on the secondary element to evaluate the normals at. The
321 : * "points" are single reals corresponding to xi because right now our mortar mesh elements are
322 : * always 1D
323 : * @return The normals
324 : */
325 : std::vector<Point> getNormals(const Elem & secondary_elem,
326 : const std::vector<Real> & oned_xi1_pts) const;
327 :
328 : /**
329 : * Return lower dimensional secondary element given its interior parent. Helpful outside the
330 : * mortar generation to locate mortar-related quantities.
331 : * @param secondary_elem_id The secondary interior parent element id used to query for associated
332 : * lower dimensional element
333 : * @return The corresponding lower dimensional secondary element
334 : */
335 : const Elem * getSecondaryLowerdElemFromSecondaryElem(dof_id_type secondary_elem_id) const;
336 :
337 : /**
338 : * Get list of secondary nodes that don't contribute to interaction with any primary element.
339 : * Used to enforce zero values on inactive DoFs of nodal variables.
340 : */
341 : void computeInactiveLMNodes();
342 :
343 : /**
344 : * Computes inactive secondary nodes when incorrect edge dropping behavior is enabled
345 : * (any node touching a partially or fully dropped element is dropped)
346 : */
347 : void computeIncorrectEdgeDroppingInactiveLMNodes();
348 :
349 : /**
350 : * Get list of secondary elems without any corresponding primary elements.
351 : * Used to enforce zero values on inactive DoFs of elemental variables.
352 : */
353 : void computeInactiveLMElems();
354 :
355 : /**
356 : * @return The mortar interface coupling
357 : */
358 : const std::unordered_map<dof_id_type, std::unordered_set<dof_id_type>> &
359 491460 : mortarInterfaceCoupling() const
360 : {
361 491460 : return _mortar_interface_coupling;
362 : }
363 :
364 : /**
365 : * @return The primary-secondary boundary ID pair
366 : */
367 : const std::pair<BoundaryID, BoundaryID> & primarySecondaryBoundaryIDPair() const;
368 :
369 : /**
370 : * @return The mortar segment mesh
371 : */
372 2194 : const MeshBase & mortarSegmentMesh() const { return *_mortar_segment_mesh; }
373 :
374 : /**
375 : * @return The mortar segment element to corresponding information
376 : */
377 1128008 : const std::unordered_map<const Elem *, MortarSegmentInfo> & mortarSegmentMeshElemToInfo() const
378 : {
379 1128008 : return _msm_elem_to_info;
380 : }
381 :
382 23389 : int dim() const { return _mesh.mesh_dimension(); }
383 :
384 : /// Return the 3D mortar quadrature-point mapping method.
385 499816 : Mortar3DQuadraturePointMapping mortar3DQpMapping() const { return _mortar_3d_qp_mapping; }
386 :
387 : /// Return the parent-face reference coordinates for a mortar segment.
388 : const MortarSegmentReferencePoints &
389 : mortarSegmentReferencePoints(const Elem & mortar_segment_elem) const;
390 :
391 : /**
392 : * @return The set of nodes on which mortar constraints are not active
393 : */
394 21873 : const std::unordered_set<const Node *> & getInactiveLMNodes() const
395 : {
396 21873 : return _inactive_local_lm_nodes;
397 : }
398 :
399 : /**
400 : * @return The list of secondary elems on which mortar constraint is not active
401 : */
402 15414 : const std::unordered_set<const Elem *> & getInactiveLMElems() const
403 : {
404 15414 : return _inactive_local_lm_elems;
405 : }
406 :
407 15414 : bool incorrectEdgeDropping() const { return !_correct_edge_dropping; }
408 :
409 : using MortarFilterIter =
410 : std::unordered_map<dof_id_type, std::set<Elem *, CompareDofObjectsByID>>::const_iterator;
411 :
412 : /**
413 : * @return A vector of iterators that point to the lower dimensional secondary elements and their
414 : * associated mortar segment elements that would have nonzero values for a Lagrange shape function
415 : * associated with the provided node. This method may return an empty container if the node is
416 : * away from the mortar mesh
417 : */
418 : std::vector<MortarFilterIter> secondariesToMortarSegments(const Node & node) const;
419 :
420 : /**
421 : * @return the lower dimensional secondary element ids and their associated mortar segment
422 : * elements
423 : */
424 : const std::unordered_map<dof_id_type, std::set<Elem *, CompareDofObjectsByID>> &
425 12744 : secondariesToMortarSegments() const
426 : {
427 12744 : return _secondary_elems_to_mortar_segments;
428 : }
429 :
430 : /**
431 : * @return All the secondary interior parent subdomain IDs associated with the mortar mesh
432 : */
433 1300 : const std::set<SubdomainID> & secondaryIPSubIDs() const { return _secondary_ip_sub_ids; }
434 :
435 : /**
436 : * @return All the primary interior parent subdomain IDs associated with the mortar mesh
437 : */
438 1300 : const std::set<SubdomainID> & primaryIPSubIDs() const { return _primary_ip_sub_ids; }
439 :
440 : /**
441 : * @return Map from node id to secondary lower-d element pointer
442 : */
443 : const std::unordered_map<dof_id_type, std::vector<const Elem *>> & nodesToSecondaryElem() const
444 : {
445 : return _nodes_to_secondary_elem_map;
446 : }
447 :
448 : /**
449 : * initialize mortar-mesh based output
450 : */
451 : void initOutput();
452 :
453 : private:
454 : /**
455 : * Write the mortar segment mesh to exodus
456 : */
457 : void outputMortarMesh();
458 :
459 : /**
460 : * @returns A string uniquely identifying this mortar interface
461 : */
462 : std::string mortarInterfaceName() const;
463 :
464 : /**
465 : * build the \p _mortar_interface_coupling data
466 : */
467 : void buildCouplingInformation();
468 :
469 : /// The Moose app
470 : MooseApp & _app;
471 :
472 : /// Reference to the mesh stored in equation_systems.
473 : MeshBase & _mesh;
474 :
475 : /// The boundary ids corresponding to all the secondary surfaces.
476 : std::set<BoundaryID> _secondary_requested_boundary_ids;
477 :
478 : /// The boundary ids corresponding to all the primary surfaces.
479 : std::set<BoundaryID> _primary_requested_boundary_ids;
480 :
481 : /// A list of primary/secondary boundary id pairs corresponding to each
482 : /// side of the mortar interface.
483 : std::vector<std::pair<BoundaryID, BoundaryID>> _primary_secondary_boundary_id_pairs;
484 :
485 : /// Map from nodes to connected lower-dimensional elements on the secondary/primary subdomains.
486 : std::unordered_map<dof_id_type, std::vector<const Elem *>> _nodes_to_secondary_elem_map;
487 : std::unordered_map<dof_id_type, std::vector<const Elem *>> _nodes_to_primary_elem_map;
488 :
489 : /// Similar to the map above, but associates a (Secondary Node, Secondary Elem)
490 : /// pair to a (xi^(2), primary Elem) pair. This allows a single secondary node, which is
491 : /// potentially connected to two elements on the secondary side, to be associated with
492 : /// multiple primary Elem/xi^(2) values to handle the case where the primary and secondary
493 : /// nodes are "matching".
494 : /// In this configuration:
495 : ///
496 : /// A B
497 : /// o-----o-----o (secondary orientation ->)
498 : /// |
499 : /// v
500 : /// ------x------ (primary orientation <-)
501 : /// C D
502 : ///
503 : /// The entries in the map should be:
504 : /// (Elem A, Node 1) -> (Elem C, xi^(2)=-1)
505 : /// (Elem B, Node 0) -> (Elem D, xi^(2)=+1)
506 : std::unordered_map<std::pair<const Node *, const Elem *>, std::pair<Real, const Elem *>>
507 : _secondary_node_and_elem_to_xi2_primary_elem;
508 :
509 : /// Same type of container, but for mapping (Primary Node ID, Primary Node,
510 : /// Primary Elem) -> (xi^(1), Secondary Elem) where they are inverse-projected along
511 : /// the nodal normal direction. Note that the first item of the key, the primary
512 : /// node ID, is important for storing the key-value pairs in a consistent order
513 : /// across processes, e.g. this container has to be ordered!
514 : std::map<std::tuple<dof_id_type, const Node *, const Elem *>, std::pair<Real, const Elem *>>
515 : _primary_node_and_elem_to_xi1_secondary_elem;
516 :
517 : /// 1D Mesh of mortar segment elements which gets built by the call
518 : /// to build_mortar_segment_mesh().
519 : std::unique_ptr<MeshBase> _mortar_segment_mesh;
520 :
521 : /// Map between Elems in the mortar segment mesh and their info
522 : /// structs. This gets filled in by the call to
523 : /// build_mortar_segment_mesh().
524 : std::unordered_map<const Elem *, MortarSegmentInfo> _msm_elem_to_info;
525 :
526 : /// Keeps track of the mapping between lower-dimensional elements and
527 : /// the side_id of the interior_parent which they are.
528 : std::unordered_map<const Elem *, unsigned int> _lower_elem_to_side_id;
529 :
530 : /// A list of primary/secondary subdomain id pairs corresponding to each
531 : /// side of the mortar interface.
532 : std::vector<std::pair<SubdomainID, SubdomainID>> _primary_secondary_subdomain_id_pairs;
533 :
534 : /// The secondary/primary lower-dimensional boundary subdomain ids are the
535 : /// secondary/primary *boundary* ids
536 : std::set<SubdomainID> _secondary_boundary_subdomain_ids;
537 : std::set<SubdomainID> _primary_boundary_subdomain_ids;
538 :
539 : /// Used by the AugmentSparsityOnInterface functor to determine
540 : /// whether a given Elem is coupled to any others across the gap, and
541 : /// to explicitly set up the dependence between interior_parent()
542 : /// elements on the secondary side and their lower-dimensional sides
543 : /// which are on the interface. This latter type of coupling must be
544 : /// explicitly declared when there is no primary_elem for a given
545 : /// mortar segment and you are using e.g. a P^1-P^0 discretization
546 : /// which does not induce the coupling automatically.
547 : std::unordered_map<dof_id_type, std::unordered_set<dof_id_type>> _mortar_interface_coupling;
548 :
549 : /// Container for storing the nodal normal vector associated with each secondary node.
550 : std::unordered_map<const Node *, Point> _secondary_node_to_nodal_normal;
551 :
552 : /// Container for storing the nodal tangent/binormal vectors associated with each secondary node
553 : /// (Householder approach).
554 : std::unordered_map<const Node *, std::array<Point, 2>> _secondary_node_to_hh_nodal_tangents;
555 :
556 : /// Coordinates used to construct the stored nodal normals
557 : std::unordered_map<const Node *, Point> _nodal_geometry_coordinate_snapshot;
558 :
559 : /// Map from full dimensional secondary element id to lower dimensional secondary element
560 : std::unordered_map<dof_id_type, const Elem *> _secondary_element_to_secondary_lowerd_element;
561 :
562 : // List of inactive lagrange multiplier nodes (for nodal variables)
563 : std::unordered_set<const Node *> _inactive_local_lm_nodes;
564 :
565 : /// List of inactive lagrange multiplier nodes (for elemental variables)
566 : std::unordered_set<const Elem *> _inactive_local_lm_elems;
567 :
568 : /// We maintain a mapping from lower-dimensional secondary elements in the original mesh to (sets
569 : /// of) elements in mortar_segment_mesh. This allows us to quickly determine which elements need
570 : /// to be split.
571 : std::unordered_map<dof_id_type, std::set<Elem *, CompareDofObjectsByID>>
572 : _secondary_elems_to_mortar_segments;
573 :
574 : /// All the secondary interior parent subdomain IDs associated with the mortar mesh
575 : std::set<SubdomainID> _secondary_ip_sub_ids;
576 :
577 : /// All the primary interior parent subdomain IDs associated with the mortar mesh
578 : std::set<SubdomainID> _primary_ip_sub_ids;
579 :
580 : /**
581 : * Helper function responsible for projecting secondary nodes
582 : * onto primary elements for a single primary/secondary pair. Called by the class member
583 : * AutomaticMortarGeneration::project_secondary_nodes().
584 : */
585 : void projectSecondaryNodesSinglePair(SubdomainID lower_dimensional_primary_subdomain_id,
586 : SubdomainID lower_dimensional_secondary_subdomain_id);
587 :
588 : /**
589 : * Helper function used internally by AutomaticMortarGeneration::project_primary_nodes().
590 : */
591 : void projectPrimaryNodesSinglePair(SubdomainID lower_dimensional_primary_subdomain_id,
592 : SubdomainID lower_dimensional_secondary_subdomain_id);
593 :
594 : /**
595 : * Process aligned nodes
596 : * @returns whether mortar segment(s) were created
597 : */
598 : bool processAlignedNodes(const Node & secondary_node,
599 : const Node & primary_node,
600 : const std::vector<const Elem *> * secondary_node_neighbors,
601 : const std::vector<const Elem *> * primary_node_neighbors,
602 : const VectorValue<Real> & nodal_normal,
603 : const Elem & candidate_element,
604 : std::set<const Elem *> & rejected_element_candidates);
605 :
606 : /// Whether to print debug output
607 : const bool _debug;
608 :
609 : /// Whether this object is on the displaced mesh
610 : const bool _on_displaced;
611 :
612 : /// Whether this object will be generating a mortar segment mesh for periodic constraints
613 : const bool _periodic;
614 :
615 : /// Whether the mortar segment mesh is distributed
616 : const bool _distributed;
617 :
618 : /// Newton solve tolerance for node projections
619 : Real _newton_tolerance = 1e-12;
620 :
621 : /// Tolerance for checking projection xi values. Usually we are checking whether we projected onto
622 : /// a certain element (in which case -1 <= xi <= 1) or whether we should have *already* projected
623 : /// a primary node (in which case we error if abs(xi) is sufficiently close to 1)
624 : Real _xi_tolerance = 1e-6;
625 :
626 : /// Flag to enable regressed treatment of edge dropping where all LM DoFs on edge dropping element
627 : /// are strongly set to 0.
628 : const bool _correct_edge_dropping;
629 :
630 : /// Parameter to control which angle (in degrees) is admissible for the creation of mortar segments.
631 : /// If set to a value close to zero, very oblique projections are allowed, which can result in mortar
632 : /// segments solving physics not meaningfully and overprojection of primary nodes onto the mortar
633 : /// segment mesh in extreme cases. This parameter is mostly intended for mortar mesh debugging purposes in 2D.
634 : const Real _minimum_projection_angle;
635 :
636 : /// Method used to define the local projection planes for 3D secondary subpatches.
637 : const Mortar3DSubpatchPlane _mortar_3d_subpatch_plane;
638 :
639 : /// Triangulation mode used for clipped 3D mortar polygons.
640 : const MortarSegmentTriangulationMode _triangulation_mode;
641 :
642 : /// Whether already-triangular clipped polygons should still be centroid-subdivided.
643 : const bool _triangulate_triangles;
644 :
645 : /// Method used to map 3D mortar segment quadrature points to primary and secondary faces.
646 : const Mortar3DQuadraturePointMapping _mortar_3d_qp_mapping;
647 :
648 : /// Reference-coordinate data used only by the reference-interpolation mapping mode.
649 : std::unordered_map<const Elem *, MortarSegmentReferencePoints> _msm_elem_to_reference_points;
650 :
651 : /// Storage for the input parameters used by the mortar nodal geometry output
652 : std::unique_ptr<InputParameters> _output_params;
653 :
654 : /// Cached per-rank starting ID for 3D MSM nodes/elements. nullopt forces recomputation on next
655 : /// buildMortarSegmentMesh3d() call. Reset by meshChanged() on topology change so the allgather
656 : /// is skipped for displaced-mesh residual updates that only move nodes.
657 : std::optional<dof_id_type> _msm_node_id_start;
658 :
659 : /// Debugging container for printing information about fraction of successful projections for
660 : /// secondary nodes. If !_debug then this should always be empty
661 : std::unordered_set<dof_id_type> _projected_secondary_nodes;
662 :
663 : /// Secondary nodes that failed to project
664 : std::unordered_set<dof_id_type> _failed_secondary_node_projections;
665 :
666 : friend class MortarNodalGeometryOutput;
667 : friend class AugmentSparsityOnInterface;
668 : };
669 :
670 : inline const std::pair<BoundaryID, BoundaryID> &
671 14639 : AutomaticMortarGeneration::primarySecondaryBoundaryIDPair() const
672 : {
673 : mooseAssert(_primary_secondary_boundary_id_pairs.size() == 1,
674 : "We currently only support a single boundary pair per mortar generation object");
675 :
676 14639 : return _primary_secondary_boundary_id_pairs.front();
677 : }
|