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