https://mooseframework.inl.gov
Loading...
Searching...
No Matches
MortarConsumerInterface.C
Go to the documentation of this file.
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// MOOSE Includes
12#include "InputParameters.h"
13#include "MooseObject.h"
14#include "FEProblemBase.h"
15#include "MooseMesh.h"
18#include "Assembly.h"
21#include "libmesh/quadrature.h"
22
23#include <algorithm>
24
27{
28 // Create InputParameters object that will be appended to the parameters for the inheriting object
30 // On a displaced mesh this will geometrically and algebraically ghost the entire interface
32 "AugmentSparsityOnInterface",
34 [](const InputParameters & obj_params, InputParameters & rm_params)
35 {
36 rm_params.set<bool>("use_displaced_mesh") = obj_params.get<bool>("use_displaced_mesh");
37 rm_params.set<BoundaryName>("secondary_boundary") =
38 obj_params.get<BoundaryName>("secondary_boundary");
39 rm_params.set<BoundaryName>("primary_boundary") =
40 obj_params.get<BoundaryName>("primary_boundary");
41 rm_params.set<SubdomainName>("secondary_subdomain") =
42 obj_params.get<SubdomainName>("secondary_subdomain");
43 rm_params.set<SubdomainName>("primary_subdomain") =
44 obj_params.get<SubdomainName>("primary_subdomain");
45 rm_params.set<bool>("ghost_point_neighbors") =
46 obj_params.get<bool>("ghost_point_neighbors");
47 rm_params.set<bool>("ghost_higher_d_neighbors") =
48 obj_params.get<bool>("ghost_higher_d_neighbors");
49 });
50
51 params.addRequiredParam<BoundaryName>("primary_boundary",
52 "The name of the primary boundary sideset.");
53 params.addRequiredParam<BoundaryName>("secondary_boundary",
54 "The name of the secondary boundary sideset.");
55 params.addRequiredParam<SubdomainName>("primary_subdomain", "The name of the primary subdomain.");
56 params.addRequiredParam<SubdomainName>("secondary_subdomain",
57 "The name of the secondary subdomain.");
58 params.addParam<bool>(
59 "periodic",
60 false,
61 "Whether this constraint is going to be used to enforce a periodic condition. This has the "
62 "effect of changing the normals vector for projection from outward to inward facing");
63
64 params.addParam<bool>(
65 "debug_mesh",
66 false,
67 "Whether this constraint is going to enable mortar segment mesh debug information. An exodus"
68 "file will be generated if the user sets this flag to true");
69
70 params.addParam<bool>(
71 "correct_edge_dropping",
72 false,
73 "Whether to enable correct edge dropping treatment for mortar constraints. When disabled "
74 "any Lagrange Multiplier degree of freedom on a secondary element without full primary "
75 "contributions will be set (strongly) to 0.");
76
77 params.addParam<bool>(
78 "interpolate_normals",
79 true,
80 "Whether to interpolate the nodal normals (e.g. classic idea of evaluating field at "
81 "quadrature points). If this is set to false, then non-interpolated nodal normals will be "
82 "used, and then the _normals member should be indexed with _i instead of _qp");
83
84 params.addParam<bool>("ghost_point_neighbors",
85 false,
86 "Whether we should ghost point neighbors of secondary face elements, their "
87 "interior parents, and their mortar interface couples.");
88 params.addParam<Real>(
89 "minimum_projection_angle",
90 40.0,
91 "Parameter to control which angle (in degrees) is admissible for the creation of mortar "
92 "segments. If set to a value close to zero, very oblique projections are allowed, which "
93 "can result in mortar segments solving physics not meaningfully, and overprojection of "
94 "primary nodes onto the mortar segment mesh in extreme cases. In 3D with "
95 "mortar_3d_subpatch_plane = GEOMETRIC_NORMAL, this parameter also controls which primary "
96 "and secondary subpatch normal pairings are admissible before polygon clipping.");
97 params.addParam<MooseEnum>(
98 "mortar_3d_subpatch_plane",
99 MooseEnum(getMortar3DSubpatchPlaneOptions(), "GEOMETRIC_NORMAL"),
100 "Method used to construct the local 3D mortar subpatch planes used for projection and "
101 "clipping. GEOMETRIC_NORMAL uses the geometric normal of each linear or bilinear secondary "
102 "subpatch. AVERAGED_NODAL_NORMAL uses the averaged nodal normal on each secondary subpatch.");
104
105 MooseEnum mortar_3d_qp_mapping(getMortar3DQuadraturePointMappingOptions(), "normal_projection");
106 mortar_3d_qp_mapping.addDocumentation(
107 "normal_projection",
108 "Project each mortar-segment quadrature point onto the linearized primary and secondary "
109 "sub-elements along the mortar-segment normal.");
110 mortar_3d_qp_mapping.addDocumentation(
111 "reference_interpolation",
112 "Interpolate stored primary and secondary parent-face reference coordinates over each "
113 "triangular mortar segment.");
114 params.addParam<MooseEnum>(
115 "mortar_3d_qp_mapping",
116 mortar_3d_qp_mapping,
117 "Method used to map quadrature points on 3D mortar segments to primary and secondary "
118 "parent-face reference coordinates. This parameter has no effect for 2D mortar.");
119
120 params.addParam<bool>(
121 "ghost_higher_d_neighbors",
122 false,
123 "Whether we should ghost higher-dimensional neighbors. This is necessary when we are doing "
124 "second order mortar with finite volume primal variables, because in order for the method to "
125 "be second order we must use cell gradients, which couples in the neighbor cells.");
126
127 return params;
128}
129
132{
134
135 MooseEnum triangulation(
136#if defined(LIBMESH_HAVE_TRIANGLE) || defined(LIBMESH_HAVE_POLY2TRI)
137 "vertex centroid ear_clipping delaunay",
138#else
139 "vertex centroid ear_clipping",
140#endif
141 "centroid");
142 triangulation.addDocumentation(
143 "vertex",
144 "Triangulate clipped 3D mortar polygons by forming a fan from an existing polygon vertex.");
145 triangulation.addDocumentation(
146 "centroid",
147 "Triangulate clipped 3D mortar polygons by forming a fan from a polygon centroid.");
148 triangulation.addDocumentation(
149 "ear_clipping", "Triangulate clipped 3D mortar polygons with an ear-clipping algorithm.");
150#if defined(LIBMESH_HAVE_TRIANGLE) || defined(LIBMESH_HAVE_POLY2TRI)
151 triangulation.addDocumentation(
152 "delaunay",
153 "Triangulate clipped 3D mortar polygons using libMesh's constrained-Delaunay PSLG "
154 "triangulation backend while preserving polygon boundary edges.");
155#endif
156 params.addParam<MooseEnum>(
157 "triangulation",
158 triangulation,
159 "Strategy used to triangulate clipped 3D mortar polygons into mortar segments. The default "
160 "is 'centroid' to preserve the legacy 3D mortar segmentation behavior.");
161 params.addParam<bool>(
162 "triangulate_triangles",
163 false,
164 "Whether a clipped 3D mortar polygon that is already a triangle should still be subdivided "
165 "during triangulation. When enabled, already-triangular polygons are subdivided with the "
166 "centroid-based path because the vertex-fan, ear-clipping, and Delaunay backends cannot "
167 "refine a triangle any further on their own.");
168
169 return params;
170}
171
172// Standard constructor
174 : _mci_fe_problem(*moose_object->getCheckedPointerParam<FEProblemBase *>("_fe_problem_base")),
175 _mci_subproblem(*moose_object->getCheckedPointerParam<SubProblem *>("_subproblem")),
176 _mci_tid(moose_object->getParam<THREAD_ID>("_tid")),
177 _mci_mesh(_mci_subproblem.mesh()),
178 // all geometric assembly information should be correct for nl system number 0
179 _mci_assembly(_mci_subproblem.assembly(_mci_tid, 0)),
180 _mortar_data(_mci_fe_problem.mortarData()),
181 _secondary_id(
182 _mci_mesh.getBoundaryID(moose_object->getParam<BoundaryName>("secondary_boundary"))),
183 _primary_id(_mci_mesh.getBoundaryID(moose_object->getParam<BoundaryName>("primary_boundary"))),
184 _secondary_subdomain_id(
185 _mci_mesh.getSubdomainID(moose_object->getParam<SubdomainName>("secondary_subdomain"))),
186 _primary_subdomain_id(
187 _mci_mesh.getSubdomainID(moose_object->getParam<SubdomainName>("primary_subdomain"))),
188 _secondary_set({_secondary_id}),
189 _interpolate_normals(moose_object->getParam<bool>("interpolate_normals")),
190 _phys_points_secondary(_mci_assembly.qPointsFace()),
191 _phys_points_primary(_mci_assembly.qPointsFaceNeighbor()),
192 _qrule_msm(_mci_assembly.qRuleMortar()),
193 _qrule_face(_mci_assembly.qRuleFace()),
194 _lower_secondary_elem(_mci_assembly.lowerDElem()),
195 _lower_primary_elem(_mci_assembly.neighborLowerDElem()),
196 _JxW_msm(_mci_assembly.jxWMortar()),
197 _msm_elem(_mci_assembly.msmElem())
198{
199 const bool displaced = moose_object->isParamValid("use_displaced_mesh")
200 ? moose_object->getParam<bool>("use_displaced_mesh")
201 : false;
202 const auto minimum_projection_angle = moose_object->getParam<Real>("minimum_projection_angle");
203 const auto mortar_3d_subpatch_plane =
204 moose_object->getParam<MooseEnum>("mortar_3d_subpatch_plane")
205 .getEnum<Mortar3DSubpatchPlane>();
206
207 // Only geometric 3D mode interprets this value as an angle between subpatch normals. Averaged
208 // normal and 2D interfaces continue to use the other projection-angle checks.
209 if (_mci_mesh.dimension() == 3 &&
210 mortar_3d_subpatch_plane == Mortar3DSubpatchPlane::GEOMETRIC_NORMAL &&
211 (minimum_projection_angle < 0.0 || minimum_projection_angle > 90.0))
212 moose_object->paramError("minimum_projection_angle",
213 "Must be between 0 and 90 degrees when "
214 "mortar_3d_subpatch_plane = GEOMETRIC_NORMAL.");
215
216 // Create the mortar interface if it hasn't already been created
217 _mci_fe_problem.createMortarInterface(
218 std::make_pair(_primary_id, _secondary_id),
219 std::make_pair(_primary_subdomain_id, _secondary_subdomain_id),
220 displaced,
221 moose_object->getParam<bool>("periodic"),
222 moose_object->getParam<bool>("debug_mesh"),
223 moose_object->getParam<bool>("correct_edge_dropping"),
224 minimum_projection_angle,
225 mortar_3d_subpatch_plane,
226 moose_object->getParam<MooseEnum>("triangulation"),
227 moose_object->getParam<bool>("triangulate_triangles"),
228 moose_object->getParam<MooseEnum>("mortar_3d_qp_mapping")
229 .getEnum<Mortar3DQuadraturePointMapping>());
230
231 _amg = &_mci_fe_problem.getMortarInterface(
232 std::make_pair(_primary_id, _secondary_id),
233 std::make_pair(_primary_subdomain_id, _secondary_subdomain_id),
234 displaced);
235
236 const auto & secondary_set = _mortar_data.getHigherDimSubdomainIDs(_secondary_subdomain_id);
237 const auto & primary_set = _mortar_data.getHigherDimSubdomainIDs(_primary_subdomain_id);
238
239 std::set_union(secondary_set.begin(),
240 secondary_set.end(),
241 primary_set.begin(),
242 primary_set.end(),
243 std::inserter(_higher_dim_subdomain_ids, _higher_dim_subdomain_ids.begin()));
244 _boundary_ids = {_secondary_id, _primary_id};
245}
246
247void
255
256void
258 const MooseObject & moose_object, const MooseVariableFieldBase & lm_var) const
259{
260 if (!lm_var.useDual() || lm_var.feType().family != LAGRANGE || lm_var.feType().order != SECOND)
261 return;
262
263 for (const auto * const lower_elem :
264 _mci_mesh.getMesh().active_local_subdomain_elements_ptr_range(_secondary_subdomain_id))
265 if (lower_elem->type() == QUAD8 || lower_elem->type() == TRI6)
266 moose_object.paramError(
267 "use_petrov_galerkin",
268 "The Petrov-Galerkin approach is not supported for a SECOND order dual Lagrange "
269 "multiplier on QUAD8 or TRI6 secondary faces. Use a FIRST order multiplier or disable "
270 "`use_petrov_galerkin`.");
271}
272
273void
274MortarConsumerInterface::trimDerivative(const dof_id_type remove_derivative_index,
275 ADReal & dual_number)
276{
277 auto md_it = dual_number.derivatives().nude_data().begin();
278 auto mi_it = dual_number.derivatives().nude_indices().begin();
279
280 auto d_it = dual_number.derivatives().nude_data().begin();
281
282 for (auto i_it = dual_number.derivatives().nude_indices().begin();
283 i_it != dual_number.derivatives().nude_indices().end();
284 ++i_it, ++d_it)
285 if (*i_it != remove_derivative_index)
286 {
287 *mi_it = *i_it;
288 *md_it = *d_it;
289 ++mi_it;
290 ++md_it;
291 }
292
293 std::size_t n_indices = md_it - dual_number.derivatives().nude_data().begin();
294 dual_number.derivatives().nude_indices().resize(n_indices);
295 dual_number.derivatives().nude_data().resize(n_indices);
296}
DualNumber< Real, DNDerivativeType, true > ADReal
InputParameters emptyInputParameters()
unsigned int THREAD_ID
Definition MooseTypes.h:237
std::vector< Point > getNormals(const Elem &secondary_elem, const std::vector< Point > &xi1_pts) const
Compute the normals at given reference points on a secondary element.
std::vector< Point > getNodalNormals(const Elem &secondary_elem) const
Specialization of SubProblem for solving nonlinear equations plus auxiliary equations.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object.
void addRequiredParam(const std::string &name, const std::string &doc_string)
This method adds a parameter and documentation string to the InputParameters object that will be extr...
std::vector< std::pair< R1, R2 > > get(const std::string &param1, const std::string &param2) const
Combine two vector parameters into a single vector of pairs.
void addRelationshipManager(const std::string &name, Moose::RelationshipManagerType rm_type, Moose::RelationshipManagerInputParameterCallback input_parameter_callback=nullptr)
Tells MOOSE about a RelationshipManager that this object needs.
T & set(const std::string &name, bool quiet_mode=false)
Returns a writable reference to the named parameters.
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
Definition MooseBase.h:457
void addDocumentation(const std::string &name, const std::string &doc)
Add an item documentation string.
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition MooseEnum.h:55
T getEnum() const
get the current value cast to the enum type T
Definition MooseEnum.h:172
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition MooseMesh.C:3546
Every object that can be built by the factory should be derived from this class.
Definition MooseObject.h:31
const libMesh::FEType & feType() const
Get the type of finite element object.
bool useDual() const
Get dual mortar option.
This class provides an interface for common operations on field variables of both FE and FV types wit...
static InputParameters validParams()
static InputParameters triangulationParams()
Elem const *const & _lower_secondary_elem
The secondary face lower dimensional element (not the mortar element!).
MortarConsumerInterface(const MooseObject *moose_object)
const libMesh::QBase *const & _qrule_face
The arbitrary quadrature rule on the lower dimensional secondary face.
static void trimDerivative(dof_id_type remove_derivative_index, ADReal &dual_number)
Get rid of AD derivative entries by dof index.
void setNormals()
Set the normals vector.
const AutomaticMortarGeneration & amg() const
Retrieve the automatic mortar generation object associated with this constraint.
void checkPetrovGalerkinQuadraticFaces(const MooseObject &moose_object, const MooseVariableFieldBase &lm_var) const
Report an error if Petrov-Galerkin weights the gap of a SECOND order dual Lagrange multiplier with th...
const SubdomainID _secondary_subdomain_id
Subdomain ID for the secondary surface.
MooseMesh & _mci_mesh
Mesh to query for boundary and subdomain ID information.
std::vector< Point > _normals
the normals
const BoundaryID _secondary_id
Boundary ID for the secondary surface.
bool interpolateNormals() const
Whether to interpolate the nodal normals (e.g.
Generic class for solving transient nonlinear problems.
Definition SubProblem.h:79
OrderWrapper order
const std::vector< Point > & get_points() const
MeshBase & mesh