https://mooseframework.inl.gov
Loading...
Searching...
No Matches
Functions
Moose::Mortar Namespace Reference

Functions

std::vector< unsigned intgetMortarSubElementNodeIndices (const Elem &parent_elem, unsigned int sub_elem)
 Return the node indices for a first-order sub-element of a parent face.
 
void projectQPoints3d (const Elem *msm_elem, const Elem *primal_elem, unsigned int sub_elem_index, const QBase &qrule_msm, std::vector< Point > &q_pts)
 3D projection operator for mapping qpoints on mortar segments to secondary or primary elements
 
void mapQPoints3dFromReference (const Elem &mortar_segment_elem, const MortarSegmentReferencePoints &reference_points, const QBase &qrule_msm, std::vector< Point > &secondary_q_pts, std::vector< Point > &primary_q_pts)
 3D mapping operator that interpolates stored parent reference points on each triangular mortar segment.
 
template<typename Iterators , typename Consumers , typename ActionFunctor >
void loopOverMortarSegments (const Iterators &secondary_elems_to_mortar_segments, Assembly &assembly, SubProblem &subproblem, FEProblemBase &fe_problem, const AutomaticMortarGeneration &amg, const bool displaced, const Consumers &consumers, const THREAD_ID tid, const std::map< SubdomainID, std::deque< MaterialBase * > > &secondary_ip_sub_to_mats, const std::map< SubdomainID, std::deque< MaterialBase * > > &primary_ip_sub_to_mats, const std::deque< MaterialBase * > &secondary_boundary_mats, const ActionFunctor act, const bool reinit_mortar_user_objects)
 This method will loop over pairs of secondary elements and their corresponding mortar segments, reinitialize all finite element shape functions, variables, and material properties, and then call a provided action function for each mortar segment.
 
template<typename Consumers >
void setupMortarMaterials (const Consumers &consumers, FEProblemBase &fe_problem, const AutomaticMortarGeneration &amg, const THREAD_ID tid, std::map< SubdomainID, std::deque< MaterialBase * > > &secondary_ip_sub_to_mats, std::map< SubdomainID, std::deque< MaterialBase * > > &primary_ip_sub_to_mats, std::deque< MaterialBase * > &secondary_boundary_mats)
 This function creates containers of materials necessary to execute the mortar method for a supplied set of consumers.
 

Function Documentation

◆ getMortarSubElementNodeIndices()

std::vector< unsigned int > Moose::Mortar::getMortarSubElementNodeIndices ( const Elem &  parent_elem,
unsigned int  sub_elem 
)

Return the node indices for a first-order sub-element of a parent face.

Definition at line 67 of file MortarUtils.C.

68{
69 if (sub_elem >= parent_elem.n_sub_elem())
70 mooseError("Invalid 3D mortar sub-element index ",
71 sub_elem,
72 " for parent element ",
73 parent_elem.id(),
74 " of type ",
75 libMesh::Utility::enum_to_string<ElemType>(parent_elem.type()),
76 ", which has ",
77 parent_elem.n_sub_elem(),
78 " sub-elements.");
79
80 switch (parent_elem.type())
81 {
82 case TRI3:
83 return {0, 1, 2};
84 case QUAD4:
85 return {0, 1, 2, 3};
86 case TRI6:
87 case TRI7:
88 switch (sub_elem)
89 {
90 case 0:
91 return {0, 3, 5};
92 case 1:
93 return {3, 4, 5};
94 case 2:
95 return {3, 1, 4};
96 case 3:
97 return {5, 4, 2};
98 default:
99 mooseError("Invalid 3D mortar triangular sub-element index ", sub_elem, ".");
100 }
101 case QUAD8:
102 switch (sub_elem)
103 {
104 case 0:
105 return {0, 4, 7};
106 case 1:
107 return {4, 1, 5};
108 case 2:
109 return {5, 2, 6};
110 case 3:
111 return {7, 6, 3};
112 case 4:
113 return {4, 5, 6, 7};
114 default:
115 mooseError("Invalid 3D mortar QUAD8 sub-element index ", sub_elem, ".");
116 }
117 case QUAD9:
118 switch (sub_elem)
119 {
120 case 0:
121 return {0, 4, 8, 7};
122 case 1:
123 return {4, 1, 5, 8};
124 case 2:
125 return {8, 5, 2, 6};
126 case 3:
127 return {7, 8, 6, 3};
128 default:
129 mooseError("Invalid 3D mortar QUAD9 sub-element index ", sub_elem, ".");
130 }
131 default:
132 mooseError("Parent face element ",
133 parent_elem.id(),
134 " has unsupported type ",
135 libMesh::Utility::enum_to_string<ElemType>(parent_elem.type()),
136 " for 3D mortar sub-element topology.");
137 }
138}
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311

Referenced by AutomaticMortarGeneration::buildMortarSegmentMesh3d(), and projectQPoints3d().

◆ loopOverMortarSegments()

template<typename Iterators , typename Consumers , typename ActionFunctor >
void Moose::Mortar::loopOverMortarSegments ( const Iterators &  secondary_elems_to_mortar_segments,
Assembly assembly,
SubProblem subproblem,
FEProblemBase fe_problem,
const AutomaticMortarGeneration amg,
const bool  displaced,
const Consumers &  consumers,
const THREAD_ID  tid,
const std::map< SubdomainID, std::deque< MaterialBase * > > &  secondary_ip_sub_to_mats,
const std::map< SubdomainID, std::deque< MaterialBase * > > &  primary_ip_sub_to_mats,
const std::deque< MaterialBase * > &  secondary_boundary_mats,
const ActionFunctor  act,
const bool  reinit_mortar_user_objects 
)

This method will loop over pairs of secondary elements and their corresponding mortar segments, reinitialize all finite element shape functions, variables, and material properties, and then call a provided action function for each mortar segment.

Parameters
secondary_elems_to_mortar_segmentsThis is a container of iterators. Each iterator should point to a pair. The first member of the pair should be a pointer to a secondary face element and the second member of the pair should correspond to a container of mortar segment element pointers that correspond to the secondary face element.
assemblyThe object we will to use to reinitalize finite element data
subproblemThe object we will use to reinitialize variables
fe_problemThe object we will use to reinitialize material properties
amgThe mortar mesh generation object which holds all the mortar mesh data
displacedWhether the mortar mesh was built from a displaced parent mesh
consumersA container of objects that are going to be using all the data that we are reinitializing within this function. This may be, for instance, a container of mortar constraints or auxiliary kernels. This consumers parameter is important as it allows us to build up variable and material property dependencies that we must make sure we reinit
actThe action functor that we will call for each mortar segment after we have reinitalized all of our prereq data. This functor may, for instance, call computeResidual or computeJacobian on mortar constraints, or computeValue for an auxiliary kernel

Definition at line 91 of file MortarUtils.h.

105{
106 const auto & primary_secondary_boundary_id_pair = amg.primarySecondaryBoundaryIDPair();
107
108 const auto primary_boundary_id = primary_secondary_boundary_id_pair.first;
109 const auto secondary_boundary_id = primary_secondary_boundary_id_pair.second;
110
111 // For 3D mortar get index for retrieving sub-element info
112 unsigned int secondary_sub_elem_index = 0, primary_sub_elem_index = 0;
113 if (amg.dim() == 3)
114 {
115 secondary_sub_elem_index = amg.mortarSegmentMesh().get_elem_integer_index("secondary_sub_elem");
116 primary_sub_elem_index = amg.mortarSegmentMesh().get_elem_integer_index("primary_sub_elem");
117 }
118
119 // The mortar quadrature rule. Necessary for sizing the number of custom points for re-init'ing
120 // the secondary interior, primary interior, and secondary face elements
121 const auto & qrule_msm = assembly.qRuleMortar();
122
123 // The element Jacobian times weights
124 const auto & JxW_msm = assembly.jxWMortar();
125
126 // Set required material properties
127 std::unordered_set<unsigned int> needed_mat_props;
128 for (const auto & consumer : consumers)
129 {
130 const auto & mp_deps = consumer->getMatPropDependencies();
131 needed_mat_props.insert(mp_deps.begin(), mp_deps.end());
132 }
133 fe_problem.setActiveMaterialProperties(needed_mat_props, /*tid=*/tid);
134
135 // Loop through secondary elements, accumulating quadrature points for all corresponding mortar
136 // segments
137 for (const auto elem_to_msm : secondary_elems_to_mortar_segments)
138 {
139 const Elem * secondary_face_elem = subproblem.mesh().getMesh().elem_ptr(elem_to_msm->first);
140 // Set the secondary interior parent and side ids
141 const Elem * secondary_ip = secondary_face_elem->interior_parent();
142 unsigned int secondary_side_id = secondary_ip->which_side_am_i(secondary_face_elem);
143 const auto & secondary_ip_mats =
144 libmesh_map_find(secondary_ip_sub_to_mats, secondary_ip->subdomain_id());
145
146 const auto & msm_elems = elem_to_msm->second;
147
148 // Need to be able to check if there's edge dropping, in 3D we can't just compare
149
150 // Map mortar segment integration points to primary and secondary sides
151 // Note points for segments will be held contiguously to allow reinit without moving
152 // cleaner way to do this would be with contiguously allocated 2D array but would either
153 // need to move into vector for calling
154 std::vector<Point> secondary_xi_pts, primary_xi_pts;
155
156 std::vector<Real> JxW;
157
158#ifndef NDEBUG
159 unsigned int expected_length = 0;
160#endif
161
162 // Loop through contributing msm elements
163 for (const auto msm_elem : msm_elems)
164 {
165 // Initialize mortar segment quadrature and compute JxW
166 subproblem.reinitMortarElem(msm_elem, tid);
167
168 // Get a reference to the MortarSegmentInfo for this Elem.
169 const MortarSegmentInfo & msinfo = amg.mortarSegmentMeshElemToInfo().at(msm_elem);
170
171 if (msm_elem->dim() == 1)
172 {
173 for (unsigned int qp = 0; qp < qrule_msm->n_points(); qp++)
174 {
175 const Real eta = qrule_msm->qp(qp)(0);
176
177 // Map quadrature points to secondary side
178 const Real xi1_eta = 0.5 * (1 - eta) * msinfo.xi1_a + 0.5 * (1 + eta) * msinfo.xi1_b;
179 secondary_xi_pts.push_back(xi1_eta);
180
181 // Map quadrature points to primary side
182 const Real xi2_eta = 0.5 * (1 - eta) * msinfo.xi2_a + 0.5 * (1 + eta) * msinfo.xi2_b;
183 primary_xi_pts.push_back(xi2_eta);
184 }
185 }
186 else
187 {
188 if (amg.mortar3DQpMapping() == Mortar3DQuadraturePointMapping::REFERENCE_INTERPOLATION)
190 amg.mortarSegmentReferencePoints(*msm_elem),
191 *qrule_msm,
192 secondary_xi_pts,
193 primary_xi_pts);
194 else
195 {
196 // Map independently because the parent-face linearizations differ.
197 projectQPoints3d(msm_elem,
198 msinfo.secondary_elem,
199 secondary_sub_elem_index,
200 *qrule_msm,
201 secondary_xi_pts);
203 msm_elem, msinfo.primary_elem, primary_sub_elem_index, *qrule_msm, primary_xi_pts);
204 }
205 }
206
207 // If edge dropping case we need JxW on the msm to compute dual shape functions
208 if (assembly.needDual())
209 std::copy(std::begin(JxW_msm), std::end(JxW_msm), std::back_inserter(JxW));
210
211#ifndef NDEBUG
212 // Verify that the expected number of quadrature points have been inserted
213 expected_length += qrule_msm->n_points();
214 mooseAssert(secondary_xi_pts.size() == expected_length,
215 "Fewer than expected secondary quadrature points");
216 mooseAssert(primary_xi_pts.size() == expected_length,
217 "Fewer than expected primary quadrature points");
218
219 if (assembly.needDual())
220 mooseAssert(JxW.size() == expected_length, "Fewer than expected JxW values computed");
221#endif
222 } // end loop over msm_elems
223
224 // Reinit dual shape coeffs if dual shape functions needed
225 // lindsayad: is there any need to make sure we do this on both reference and displaced?
226 if (assembly.needDual())
227 assembly.reinitDual(secondary_face_elem, secondary_xi_pts, JxW);
228
229 unsigned int n_segment = 0;
230
231 // Loop through contributing msm elements, computing residual and Jacobian this time
232 for (const auto msm_elem : msm_elems)
233 {
234 n_segment++;
235
236 // These will hold quadrature points for each segment
237 std::vector<Point> xi1_pts, xi2_pts;
238
239 // Get a reference to the MortarSegmentInfo for this Elem.
240 const MortarSegmentInfo & msinfo = amg.mortarSegmentMeshElemToInfo().at(msm_elem);
241
242 // Set the primary interior parent and side ids
243 const Elem * primary_ip = msinfo.primary_elem->interior_parent();
244 unsigned int primary_side_id = primary_ip->which_side_am_i(msinfo.primary_elem);
245 const auto & primary_ip_mats =
246 libmesh_map_find(primary_ip_sub_to_mats, primary_ip->subdomain_id());
247
248 // Compute a JxW for the actual mortar segment element (not the lower dimensional element on
249 // the secondary face!)
250 subproblem.reinitMortarElem(msm_elem, tid);
251
252 // Extract previously computed mapped quadrature points for secondary and primary face
253 // elements
254 const unsigned int start = (n_segment - 1) * qrule_msm->n_points();
255 const unsigned int end = n_segment * qrule_msm->n_points();
256 xi1_pts.insert(
257 xi1_pts.begin(), secondary_xi_pts.begin() + start, secondary_xi_pts.begin() + end);
258 xi2_pts.insert(xi2_pts.begin(), primary_xi_pts.begin() + start, primary_xi_pts.begin() + end);
259
260 const Elem * reinit_secondary_elem = secondary_ip;
261
262 // If we're on the displaced mesh, we need to get the corresponding undisplaced elem before
263 // calling fe_problem.reinitElemFaceRef
264 if (displaced)
265 reinit_secondary_elem = fe_problem.mesh().elemPtr(reinit_secondary_elem->id());
266
267 // NOTE to future developers: it can be tempting to try and change calls on fe_problem to
268 // calls on subproblem because it seems wasteful to reinit data on both the reference and
269 // displaced problems regardless of whether we are running on a "reference" or displaced
270 // mortar mesh. But making such changes opens a can of worms. For instance, a user may define
271 // constant material properties that are used by mortar constraints and not think about
272 // whether they should set `use_displaced_mesh` for the material (and indeed the user may want
273 // those constant properties usable by both reference and displaced consumer objects). If we
274 // reinit that material and we haven't reinit'd it's assembly member, then we will get things
275 // like segmentation faults. Moreover, one can easily imagine that a material may couple in
276 // variables so we need to make sure those are reinit'd too. So even though it's inefficient,
277 // it's safest to keep making calls on fe_problem instead of subproblem
278
279 // reinit the variables/residuals/jacobians on the secondary interior
280 fe_problem.reinitElemFaceRef(
281 reinit_secondary_elem, secondary_side_id, TOLERANCE, &xi1_pts, nullptr, tid);
282
283 const Elem * reinit_primary_elem = primary_ip;
284
285 // If we're on the displaced mesh, we need to get the corresponding undisplaced elem before
286 // calling fe_problem.reinitElemFaceRef
287 if (displaced)
288 reinit_primary_elem = fe_problem.mesh().elemPtr(reinit_primary_elem->id());
289
290 // reinit the variables/residuals/jacobians on the primary interior
291 fe_problem.reinitNeighborFaceRef(
292 reinit_primary_elem, primary_side_id, TOLERANCE, &xi2_pts, nullptr, tid);
293
294 // reinit neighbor materials, but be careful not to execute stateful materials since
295 // conceptually they don't make sense with mortar (they're not interpolary)
296 fe_problem.reinitMaterialsNeighbor(primary_ip->subdomain_id(),
297 /*tid=*/tid,
298 /*swap_stateful=*/false,
299 &primary_ip_mats);
300
301 // reinit the variables/residuals/jacobians on the lower dimensional element corresponding to
302 // the secondary face. This must be done last after the dof indices have been prepared for the
303 // secondary (element) and primary (neighbor)
304 subproblem.reinitLowerDElem(secondary_face_elem, /*tid=*/tid, &xi1_pts);
305
306 // All this does currently is sets the neighbor/primary lower dimensional elem in Assembly and
307 // computes its volume for potential use in the MortarConstraints. Solution continuity
308 // stabilization for example relies on being able to access the volume
309 subproblem.reinitNeighborLowerDElem(msinfo.primary_elem, tid);
310
311 // reinit higher-dimensional secondary face/boundary materials. Do this after we reinit
312 // lower-d variables in case we want to pull the lower-d variable values into the secondary
313 // face/boundary materials. Be careful not to execute stateful materials since conceptually
314 // they don't make sense with mortar (they're not interpolary)
315 fe_problem.reinitMaterialsFace(secondary_ip->subdomain_id(),
316 /*tid=*/tid,
317 /*swap_stateful=*/false,
318 &secondary_ip_mats);
319 fe_problem.reinitMaterialsBoundary(
320 secondary_boundary_id, /*tid=*/tid, /*swap_stateful=*/false, &secondary_boundary_mats);
321
322 if (reinit_mortar_user_objects)
323 fe_problem.reinitMortarUserObjects(primary_boundary_id, secondary_boundary_id, displaced);
324
325 act();
326
327 } // End loop over msm segments on secondary face elem
328 } // End loop over (active) secondary elems
329}
Point eta
Definition MortarUtils.C:60
const libMesh::QBase *const & qRuleMortar() const
Returns a reference to the quadrature rule for the mortar segments.
Definition Assembly.h:712
void reinitDual(const Elem *elem, const std::vector< Point > &pts, const std::vector< Real > &JxW)
Reintialize dual basis coefficients based on a customized quadrature rule.
Definition Assembly.C:2274
const std::vector< Real > & jxWMortar() const
Returns a reference to JxW for mortar segment elements.
Definition Assembly.h:707
bool needDual() const
Indicates whether dual shape functions are used (computation is now repeated on each element so expen...
Definition Assembly.h:623
const MortarSegmentReferencePoints & mortarSegmentReferencePoints(const Elem &mortar_segment_elem) const
Return the parent-face reference coordinates for a mortar segment.
Mortar3DQuadraturePointMapping mortar3DQpMapping() const
Return the 3D mortar quadrature-point mapping method.
const std::pair< BoundaryID, BoundaryID > & primarySecondaryBoundaryIDPair() const
const MeshBase & mortarSegmentMesh() const
const std::unordered_map< const Elem *, MortarSegmentInfo > & mortarSegmentMeshElemToInfo() const
virtual void reinitElemFaceRef(const Elem *elem, unsigned int side, Real tolerance, const std::vector< Point > *const pts, const std::vector< Real > *const weights=nullptr, const THREAD_ID tid=0) override
reinitialize FE objects on a given element on a given side at a given set of reference points and the...
void reinitMaterialsFace(SubdomainID blk_id, const THREAD_ID tid, bool swap_stateful=true, const std::deque< MaterialBase * > *reinit_mats=nullptr)
reinit materials on element faces
void reinitMaterialsNeighbor(SubdomainID blk_id, const THREAD_ID tid, bool swap_stateful=true, const std::deque< MaterialBase * > *reinit_mats=nullptr)
reinit materials on the neighboring element face
virtual MooseMesh & mesh() override
void setActiveMaterialProperties(const std::unordered_set< unsigned int > &mat_prop_ids, const THREAD_ID tid)
Record and set the material properties required by the current computing thread.
virtual void reinitNeighborFaceRef(const Elem *neighbor_elem, unsigned int neighbor_side, Real tolerance, const std::vector< Point > *const pts, const std::vector< Real > *const weights=nullptr, const THREAD_ID tid=0) override
reinitialize FE objects on a given neighbor element on a given side at a given set of reference point...
void reinitMaterialsBoundary(BoundaryID boundary_id, const THREAD_ID tid, bool swap_stateful=true, const std::deque< MaterialBase * > *reinit_mats=nullptr)
reinit materials on a boundary
void reinitMortarUserObjects(BoundaryID primary_boundary_id, BoundaryID secondary_boundary_id, bool displaced)
Call reinit on mortar user objects with matching primary boundary ID, secondary boundary ID,...
virtual Elem * elemPtr(const dof_id_type i)
Definition MooseMesh.C:3214
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition MooseMesh.C:3549
virtual MooseMesh & mesh()=0
void reinitNeighborLowerDElem(const Elem *elem, const THREAD_ID tid=0)
reinitialize a neighboring lower dimensional element
Definition SubProblem.C:988
void reinitMortarElem(const Elem *elem, const THREAD_ID tid=0)
Reinit a mortar element to obtain a valid JxW.
Definition SubProblem.C:995
virtual void reinitLowerDElem(const Elem *lower_d_elem, const THREAD_ID tid, const std::vector< Point > *const pts=nullptr, const std::vector< Real > *const weights=nullptr)
Definition SubProblem.C:958
unsigned int which_side_am_i(const Elem *e) const
const Elem * interior_parent() const
unsigned int get_elem_integer_index(std::string_view name) const
void projectQPoints3d(const Elem *msm_elem, const Elem *primal_elem, unsigned int sub_elem_index, const QBase &qrule_msm, std::vector< Point > &q_pts)
3D projection operator for mapping qpoints on mortar segments to secondary or primary elements
void mapQPoints3dFromReference(const Elem &mortar_segment_elem, const MortarSegmentReferencePoints &reference_points, const QBase &qrule_msm, std::vector< Point > &secondary_q_pts, std::vector< Point > &primary_q_pts)
3D mapping operator that interpolates stored parent reference points on each triangular mortar segmen...
Holds xi^(1), xi^(2), and other data for a given mortar segment.
const Elem * primary_elem
const Elem * secondary_elem

Referenced by MortarNodalAuxKernelTempl< ComputeValueType >::compute(), MortarUserObjectThread::operator()(), and ComputeMortarFunctor::operator()().

◆ mapQPoints3dFromReference()

void Moose::Mortar::mapQPoints3dFromReference ( const Elem &  mortar_segment_elem,
const MortarSegmentReferencePoints reference_points,
const QBase &  qrule_msm,
std::vector< Point > &  secondary_q_pts,
std::vector< Point > &  primary_q_pts 
)

3D mapping operator that interpolates stored parent reference points on each triangular mortar segment.

Parameters
mortar_segment_elemThe triangular mortar segment carrying the quadrature rule
reference_pointsParent-face reference points stored for the mortar segment
qrule_msmThe rule that governs quadrature on the mortar segment element
secondary_q_ptsReference-space quadrature points on the secondary face
primary_q_ptsReference-space quadrature points on the primary face

Definition at line 523 of file MortarUtils.C.

528{
529 mooseAssert(mortar_segment_elem.type() == TRI3,
530 "Reference interpolation expects triangular mortar segments.");
531 const FEType fe_type(FIRST, LAGRANGE);
532
533 for (const auto qp : make_range(qrule_msm.n_points()))
534 {
535 Point secondary_qp;
536 Point primary_qp;
537
538 for (const auto n : index_range(reference_points.secondary_reference_points))
539 {
540 const auto phi =
541 FEInterface::shape(fe_type, &mortar_segment_elem, n, qrule_msm.qp(qp), false);
542 secondary_qp += phi * reference_points.secondary_reference_points[n];
543 primary_qp += phi * reference_points.primary_reference_points[n];
544 }
545
546 secondary_q_pts.push_back(secondary_qp);
547 primary_q_pts.push_back(primary_qp);
548 }
549}
std::array< Point, 3 > primary_reference_points
std::array< Point, 3 > secondary_reference_points

Referenced by loopOverMortarSegments().

◆ projectQPoints3d()

void Moose::Mortar::projectQPoints3d ( const Elem *  msm_elem,
const Elem *  primal_elem,
unsigned int  sub_elem_index,
const QBase &  qrule_msm,
std::vector< Point > &  q_pts 
)

3D projection operator for mapping qpoints on mortar segments to secondary or primary elements

Parameters
msm_elemThe mortar segment element that we will be mapping quadrature points from
primal_elemThe "persistent" mesh element (e.g. it exists on the simulation's MooseMesh) that we will be mapping quadrature points for. This can be either an element on the secondary or primary face
sub_elem_indexWe will call msm_elem->get_extra_integer(sub_elem_index) in the implementation in order to determine which sub-element of the primal element the mortar segment element corresponds to. This sub_elem_index should correspond to the secondary element index if primal_elem is a secondary face element and the primary element index if primal_elem is a primary face element
qrule_msmThe rule that governs quadrature on the mortar segment element
q_ptsThe output of this function. This will correspond to the the (reference space) quadrature points that we wish to evaluate shape functions, etc., at on the primal element

Definition at line 552 of file MortarUtils.C.

557{
558 const auto msm_elem_order = msm_elem->default_order();
559 const auto msm_elem_type = msm_elem->type();
560
561 // Get normal to linearized element, could store and query but computation is easy
562 const Point e1 = msm_elem->point(0) - msm_elem->point(1);
563 const Point e2 = msm_elem->point(2) - msm_elem->point(1);
564 const Point normal = e2.cross(e1).unit();
565
566 // Get sub-elem (for second order meshes, otherwise trivial)
567 const auto sub_elem = msm_elem->get_extra_integer(sub_elem_index);
568 const ElemType primal_type = primal_elem->type();
569 const ElemType sub_elem_type = subElementType(primal_type, sub_elem);
570
571 // Transforms quadrature point from first order sub-elements (in case of second-order)
572 // to primal element
573 auto transform_qp = [primal_type, sub_elem](const Real nu, const Real xi)
574 {
575 switch (primal_type)
576 {
577 case TRI3:
578 return Point(nu, xi, 0);
579 case QUAD4:
580 return Point(nu, xi, 0);
581 case TRI6:
582 case TRI7:
583 switch (sub_elem)
584 {
585 case 0:
586 return Point(0.5 * nu, 0.5 * xi, 0);
587 case 1:
588 return Point(0.5 * (1 - xi), 0.5 * (nu + xi), 0);
589 case 2:
590 return Point(0.5 * (1 + nu), 0.5 * xi, 0);
591 case 3:
592 return Point(0.5 * nu, 0.5 * (1 + xi), 0);
593 default:
594 mooseError("get_sub_elem_indices: Invalid sub_elem: ", sub_elem);
595 }
596 case QUAD8:
597 switch (sub_elem)
598 {
599 case 0:
600 return Point(nu - 1, xi - 1, 0);
601 case 1:
602 return Point(nu + xi, xi - 1, 0);
603 case 2:
604 return Point(1 - xi, nu + xi, 0);
605 case 3:
606 return Point(nu - 1, nu + xi, 0);
607 case 4:
608 return Point(0.5 * (nu - xi), 0.5 * (nu + xi), 0);
609 default:
610 mooseError("get_sub_elem_indices: Invalid sub_elem: ", sub_elem);
611 }
612 case QUAD9:
613 switch (sub_elem)
614 {
615 case 0:
616 return Point(0.5 * (nu - 1), 0.5 * (xi - 1), 0);
617 case 1:
618 return Point(0.5 * (nu + 1), 0.5 * (xi - 1), 0);
619 case 2:
620 return Point(0.5 * (nu + 1), 0.5 * (xi + 1), 0);
621 case 3:
622 return Point(0.5 * (nu - 1), 0.5 * (xi + 1), 0);
623 default:
624 mooseError("get_sub_elem_indices: Invalid sub_elem: ", sub_elem);
625 }
626 default:
627 mooseError("transform_qp: Face element type: ",
628 libMesh::Utility::enum_to_string<ElemType>(primal_type),
629 " invalid for 3D mortar");
630 }
631 };
632
633 // Get sub-elem node indices
634 const auto sub_elem_node_indices = getMortarSubElementNodeIndices(*primal_elem, sub_elem);
635
636 // Loop through quadrature points on msm_elem
637 for (auto qp : make_range(qrule_msm.n_points()))
638 {
639 // Get physical point on msm_elem to project
640 Point x0;
641 for (auto n : make_range(msm_elem->n_nodes()))
642 x0 += Moose::fe_lagrange_2D_shape(msm_elem_type,
643 msm_elem_order,
644 n,
645 static_cast<const TypeVector<Real> &>(qrule_msm.qp(qp))) *
646 msm_elem->point(n);
647
648 if (sub_elem_type == TRI3)
649 {
650 const Point sub_elem_point = analyticalTriangleInverse(
651 *msm_elem, *primal_elem, sub_elem_node_indices, normal, x0, sub_elem, qp);
652 const Point parent_point = transform_qp(sub_elem_point(0), sub_elem_point(1));
653 if (!MooseUtils::isFinitePoint(parent_point) ||
654 !primal_elem->on_reference_element(parent_point, mortar_reference_tolerance))
655 projectionFailure(*msm_elem,
656 *primal_elem,
657 sub_elem,
658 qp,
659 "the recovered TRI3 point is outside the parent face");
660 q_pts.push_back(parent_point);
661 continue;
662 }
663
664 // Use msm_elem quadrature point as initial guess
665 // (will be correct for aligned meshes)
666 Dual2 xi1{};
667 xi1.value() = qrule_msm.qp(qp)(0);
668 xi1.derivatives()[0] = 1.0;
669 Dual2 xi2{};
670 xi2.value() = qrule_msm.qp(qp)(1);
671 xi2.derivatives()[1] = 1.0;
672 VectorValue<Dual2> xi(xi1, xi2, 0);
673 unsigned int current_iterate = 0, max_iterates = 10;
674
675 // Project qp from mortar segments to first order sub-elements (elements in case of first order
676 // geometry)
677 do
678 {
679 VectorValue<Dual2> x1;
680 for (auto n : make_range(sub_elem_node_indices.size()))
681 x1 += Moose::fe_lagrange_2D_shape(sub_elem_type, FIRST, n, xi) *
682 primal_elem->point(sub_elem_node_indices[n]);
683 auto u = x1 - x0;
684
685 VectorValue<Dual2> F(u(1) * normal(2) - u(2) * normal(1),
686 u(2) * normal(0) - u(0) * normal(2),
687 u(0) * normal(1) - u(1) * normal(0));
688
689 Real projection_tolerance(1e-10);
690
691 // Normalize tolerance with quantities involved in the projection.
692 // Absolute projection tolerance is loosened for displacements larger than those on the order
693 // of one. Tightening the tolerance for displacements of smaller orders causes this tolerance
694 // to not be reached in a number of tests.
695 if (!u.is_zero() && u.norm().value() > 1.0)
696 projection_tolerance *= u.norm().value();
697
698 if (MetaPhysicL::raw_value(F).norm() < projection_tolerance)
699 break;
700
701 RealEigenMatrix J(3, 2);
702 J << F(0).derivatives()[0], F(0).derivatives()[1], F(1).derivatives()[0],
703 F(1).derivatives()[1], F(2).derivatives()[0], F(2).derivatives()[1];
704 RealEigenVector f(3);
705 f << F(0).value(), F(1).value(), F(2).value();
706 const RealEigenVector dxi = -J.colPivHouseholderQr().solve(f);
707
708 xi(0) += dxi(0);
709 xi(1) += dxi(1);
710 } while (++current_iterate < max_iterates);
711
712 const Point newton_sub_elem_point(xi(0).value(), xi(1).value());
713 const Point newton_parent_point =
714 transform_qp(newton_sub_elem_point(0), newton_sub_elem_point(1));
715 const bool newton_point_is_valid =
716 current_iterate < max_iterates && MooseUtils::isFinitePoint(newton_sub_elem_point) &&
717 MooseUtils::isFinitePoint(newton_parent_point) &&
718 quadrilateralReferenceViolation(newton_sub_elem_point) == 0 &&
719 primal_elem->on_reference_element(newton_parent_point, mortar_reference_tolerance);
720
721 if (newton_point_is_valid)
722 {
723 q_pts.push_back(newton_parent_point);
724 continue;
725 }
726
727 if (sub_elem_type == QUAD4)
728 {
729 // Newton can converge to the exterior root of a distorted bilinear QUAD.
730 const Point fallback_point = analyticalQuadrilateralInverse(
731 *msm_elem, *primal_elem, sub_elem_node_indices, normal, x0, sub_elem, qp);
732 const Point parent_point = transform_qp(fallback_point(0), fallback_point(1));
733 if (!MooseUtils::isFinitePoint(parent_point) ||
734 !primal_elem->on_reference_element(parent_point, mortar_reference_tolerance))
735 projectionFailure(*msm_elem,
736 *primal_elem,
737 sub_elem,
738 qp,
739 "the recovered point is outside the parent face");
740 q_pts.push_back(parent_point);
741 continue;
742 }
743
744 if (current_iterate == max_iterates)
745 mooseError("Newton iteration for mortar quadrature mapping msm element: ",
746 msm_elem->id(),
747 " to elem: ",
748 primal_elem->id(),
749 " didn't converge. MSM element volume: ",
750 msm_elem->volume());
751
752 projectionFailure(
753 *msm_elem, *primal_elem, sub_elem, qp, "the Newton result is outside the parent face");
754 }
755}
Point xi
Definition MortarUtils.C:59
DualNumber< Real, NumberArray< 2, Real > > Dual2
Definition MortarUtils.C:27
auto raw_value(const Eigen::Map< T > &in)
bool isFinitePoint(const Point &point)
Definition MooseUtils.C:60
std::vector< unsigned int > getMortarSubElementNodeIndices(const Elem &parent_elem, unsigned int sub_elem)
Return the node indices for a first-order sub-element of a parent face.
Definition MortarUtils.C:67
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
T fe_lagrange_2D_shape(const libMesh::ElemType type, const Order order, const unsigned int i, const VectorType< T > &p)
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
auto norm(const T &a)
Eigen::Matrix< Real, Eigen::Dynamic, Eigen::Dynamic > RealEigenMatrix
Definition MooseTypes.h:151
Eigen::Matrix< Real, Eigen::Dynamic, 1 > RealEigenVector
Definition MooseTypes.h:147
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)
const dof_id_type n_nodes

Referenced by loopOverMortarSegments().

◆ setupMortarMaterials()

template<typename Consumers >
void Moose::Mortar::setupMortarMaterials ( const Consumers &  consumers,
FEProblemBase fe_problem,
const AutomaticMortarGeneration amg,
const THREAD_ID  tid,
std::map< SubdomainID, std::deque< MaterialBase * > > &  secondary_ip_sub_to_mats,
std::map< SubdomainID, std::deque< MaterialBase * > > &  primary_ip_sub_to_mats,
std::deque< MaterialBase * > &  secondary_boundary_mats 
)

This function creates containers of materials necessary to execute the mortar method for a supplied set of consumers.

Parameters
consumersThe objects that we're building the material dependencies for. This could be a container of mortar constraints or a "mortar" auxiliary kernel for example
fe_problemThe finite element problem that we'll be querying for material warehouses
tidThe thread ID that we will use for pulling the material warehouse
secondary_ip_sub_to_matsA map from the secondary interior parent subdomain IDs to the required secondary block materials we will need to evaluate for the consumers
primary_ip_sub_to_matsA map from the primary interior parent subdomain IDs to the required primary block materials we will need to evaluate for the consumers
secondary_boundary_matsThe secondary boundary materials we will need to evaluate for the consumers

Definition at line 347 of file MortarUtils.h.

354{
355 secondary_ip_sub_to_mats.clear();
356 primary_ip_sub_to_mats.clear();
357 secondary_boundary_mats.clear();
358
359 auto & mat_warehouse = fe_problem.getRegularMaterialsWarehouse();
360 auto get_required_sub_mats =
361 [&mat_warehouse, tid, &consumers](
362 const SubdomainID sub_id,
363 const Moose::MaterialDataType mat_data_type) -> std::deque<MaterialBase *>
364 {
365 if (mat_warehouse[mat_data_type].hasActiveBlockObjects(sub_id, tid))
366 {
367 auto & sub_mats = mat_warehouse[mat_data_type].getActiveBlockObjects(sub_id, tid);
368 return MaterialBase::buildRequiredMaterials(consumers, sub_mats, /*allow_stateful=*/false);
369 }
370 else
371 return {};
372 };
373
374 // Construct secondary *block* materials container
375 const auto & secondary_ip_sub_ids = amg.secondaryIPSubIDs();
376 for (const auto secondary_ip_sub : secondary_ip_sub_ids)
377 secondary_ip_sub_to_mats.emplace(
378 secondary_ip_sub, get_required_sub_mats(secondary_ip_sub, Moose::FACE_MATERIAL_DATA));
379
380 // Construct primary *block* materials container
381 const auto & primary_ip_sub_ids = amg.primaryIPSubIDs();
382 for (const auto primary_ip_sub : primary_ip_sub_ids)
383 primary_ip_sub_to_mats.emplace(
384 primary_ip_sub, get_required_sub_mats(primary_ip_sub, Moose::NEIGHBOR_MATERIAL_DATA));
385
386 // Construct secondary *boundary* materials container
387 const auto & boundary_pr = amg.primarySecondaryBoundaryIDPair();
388 const auto secondary_boundary = boundary_pr.second;
389 if (mat_warehouse.hasActiveBoundaryObjects(secondary_boundary, tid))
390 {
391 auto & boundary_mats = mat_warehouse.getActiveBoundaryObjects(secondary_boundary, tid);
392 secondary_boundary_mats =
393 MaterialBase::buildRequiredMaterials(consumers, boundary_mats, /*allow_stateful=*/false);
394 }
395}
const std::set< SubdomainID > & secondaryIPSubIDs() const
const std::set< SubdomainID > & primaryIPSubIDs() const
const MaterialWarehouse & getRegularMaterialsWarehouse() const
static std::deque< MaterialBase * > buildRequiredMaterials(const Consumers &mat_consumers, const std::vector< std::shared_ptr< MaterialBase > > &mats, const bool allow_stateful)
Build the materials required by a set of consumer objects.
const std::map< SubdomainID, std::vector< std::shared_ptr< T > > > & getActiveBlockObjects(THREAD_ID tid=0) const
MaterialDataType
MaterialData types.
Definition MooseTypes.h:746
@ NEIGHBOR_MATERIAL_DATA
Definition MooseTypes.h:750
@ FACE_MATERIAL_DATA
Definition MooseTypes.h:749

Referenced by ComputeMortarFunctor::ComputeMortarFunctor(), MortarNodalAuxKernelTempl< ComputeValueType >::initialSetup(), MortarUserObjectThread::MortarUserObjectThread(), and ComputeMortarFunctor::setupMortarMaterials().