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 : // MOOSE Includes
11 : #include "MortarConsumerInterface.h"
12 : #include "InputParameters.h"
13 : #include "MooseObject.h"
14 : #include "FEProblemBase.h"
15 : #include "MooseMesh.h"
16 : #include "MortarInterfaceWarehouse.h"
17 : #include "Assembly.h"
18 : #include "AutomaticMortarGeneration.h"
19 : #include "libmesh/quadrature.h"
20 :
21 : #include <algorithm>
22 :
23 : InputParameters
24 57939 : MortarConsumerInterface::validParams()
25 : {
26 : // Create InputParameters object that will be appended to the parameters for the inheriting object
27 57939 : InputParameters params = emptyInputParameters();
28 : // On a displaced mesh this will geometrically and algebraically ghost the entire interface
29 173817 : params.addRelationshipManager(
30 : "AugmentSparsityOnInterface",
31 : Moose::RelationshipManagerType::GEOMETRIC | Moose::RelationshipManagerType::ALGEBRAIC,
32 57939 : [](const InputParameters & obj_params, InputParameters & rm_params)
33 : {
34 8580 : rm_params.set<bool>("use_displaced_mesh") = obj_params.get<bool>("use_displaced_mesh");
35 8580 : rm_params.set<BoundaryName>("secondary_boundary") =
36 8580 : obj_params.get<BoundaryName>("secondary_boundary");
37 8580 : rm_params.set<BoundaryName>("primary_boundary") =
38 8580 : obj_params.get<BoundaryName>("primary_boundary");
39 8580 : rm_params.set<SubdomainName>("secondary_subdomain") =
40 8580 : obj_params.get<SubdomainName>("secondary_subdomain");
41 8580 : rm_params.set<SubdomainName>("primary_subdomain") =
42 8580 : obj_params.get<SubdomainName>("primary_subdomain");
43 4290 : rm_params.set<bool>("ghost_point_neighbors") =
44 4290 : obj_params.get<bool>("ghost_point_neighbors");
45 4290 : rm_params.set<bool>("ghost_higher_d_neighbors") =
46 4290 : obj_params.get<bool>("ghost_higher_d_neighbors");
47 4290 : });
48 :
49 231756 : params.addRequiredParam<BoundaryName>("primary_boundary",
50 : "The name of the primary boundary sideset.");
51 231756 : params.addRequiredParam<BoundaryName>("secondary_boundary",
52 : "The name of the secondary boundary sideset.");
53 231756 : params.addRequiredParam<SubdomainName>("primary_subdomain", "The name of the primary subdomain.");
54 231756 : params.addRequiredParam<SubdomainName>("secondary_subdomain",
55 : "The name of the secondary subdomain.");
56 173817 : params.addParam<bool>(
57 : "periodic",
58 115878 : false,
59 : "Whether this constraint is going to be used to enforce a periodic condition. This has the "
60 : "effect of changing the normals vector for projection from outward to inward facing");
61 :
62 173817 : params.addParam<bool>(
63 : "debug_mesh",
64 115878 : false,
65 : "Whether this constraint is going to enable mortar segment mesh debug information. An exodus"
66 : "file will be generated if the user sets this flag to true");
67 :
68 173817 : params.addParam<bool>(
69 : "correct_edge_dropping",
70 115878 : false,
71 : "Whether to enable correct edge dropping treatment for mortar constraints. When disabled "
72 : "any Lagrange Multiplier degree of freedom on a secondary element without full primary "
73 : "contributions will be set (strongly) to 0.");
74 :
75 173817 : params.addParam<bool>(
76 : "interpolate_normals",
77 115878 : true,
78 : "Whether to interpolate the nodal normals (e.g. classic idea of evaluating field at "
79 : "quadrature points). If this is set to false, then non-interpolated nodal normals will be "
80 : "used, and then the _normals member should be indexed with _i instead of _qp");
81 :
82 173817 : params.addParam<bool>("ghost_point_neighbors",
83 115878 : false,
84 : "Whether we should ghost point neighbors of secondary face elements, and "
85 : "consequently also their mortar interface couples.");
86 115878 : params.addParam<Real>(
87 : "minimum_projection_angle",
88 173817 : 40.0,
89 : "Parameter to control which angle (in degrees) is admissible for the creation of mortar "
90 : "segments. If set to a value close to zero, very oblique projections are allowed, which "
91 : "can result in mortar segments solving physics not meaningfully, and overprojection of "
92 : "primary nodes onto the mortar segment mesh in extreme cases. This parameter is mostly "
93 : "intended for mortar mesh debugging purposes in two dimensions.");
94 57939 : params += MortarConsumerInterface::triangulationParams();
95 :
96 115878 : params.addParam<bool>(
97 : "ghost_higher_d_neighbors",
98 115878 : false,
99 : "Whether we should ghost higher-dimensional neighbors. This is necessary when we are doing "
100 : "second order mortar with finite volume primal variables, because in order for the method to "
101 : "be second order we must use cell gradients, which couples in the neighbor cells.");
102 :
103 57939 : return params;
104 0 : }
105 :
106 : InputParameters
107 57939 : MortarConsumerInterface::triangulationParams()
108 : {
109 57939 : InputParameters params = emptyInputParameters();
110 :
111 : MooseEnum triangulation(
112 : #if defined(LIBMESH_HAVE_TRIANGLE) || defined(LIBMESH_HAVE_POLY2TRI)
113 : "vertex centroid ear_clipping delaunay",
114 : #else
115 : "vertex centroid ear_clipping",
116 : #endif
117 231756 : "centroid");
118 231756 : triangulation.addDocumentation(
119 : "vertex",
120 : "Triangulate clipped 3D mortar polygons by forming a fan from an existing polygon vertex.");
121 231756 : triangulation.addDocumentation(
122 : "centroid",
123 : "Triangulate clipped 3D mortar polygons by forming a fan from a polygon centroid.");
124 231756 : triangulation.addDocumentation(
125 : "ear_clipping", "Triangulate clipped 3D mortar polygons with an ear-clipping algorithm.");
126 : #if defined(LIBMESH_HAVE_TRIANGLE) || defined(LIBMESH_HAVE_POLY2TRI)
127 231756 : triangulation.addDocumentation(
128 : "delaunay",
129 : "Triangulate clipped 3D mortar polygons using libMesh's constrained-Delaunay PSLG "
130 : "triangulation backend while preserving polygon boundary edges.");
131 : #endif
132 231756 : params.addParam<MooseEnum>(
133 : "triangulation",
134 : triangulation,
135 : "Strategy used to triangulate clipped 3D mortar polygons into mortar segments. The default "
136 : "is 'centroid' to preserve the legacy 3D mortar segmentation behavior.");
137 115878 : params.addParam<bool>(
138 : "triangulate_triangles",
139 115878 : false,
140 : "Whether a clipped 3D mortar polygon that is already a triangle should still be subdivided "
141 : "during triangulation. When enabled, already-triangular polygons are subdivided with the "
142 : "centroid-based path because the vertex-fan, ear-clipping, and Delaunay backends cannot "
143 : "refine a triangle any further on their own.");
144 :
145 115878 : return params;
146 57939 : }
147 :
148 : // Standard constructor
149 1414 : MortarConsumerInterface::MortarConsumerInterface(const MooseObject * moose_object)
150 5656 : : _mci_fe_problem(*moose_object->getCheckedPointerParam<FEProblemBase *>("_fe_problem_base")),
151 5656 : _mci_subproblem(*moose_object->getCheckedPointerParam<SubProblem *>("_subproblem")),
152 2828 : _mci_tid(moose_object->getParam<THREAD_ID>("_tid")),
153 1414 : _mci_mesh(_mci_subproblem.mesh()),
154 : // all geometric assembly information should be correct for nl system number 0
155 1414 : _mci_assembly(_mci_subproblem.assembly(_mci_tid, 0)),
156 1414 : _mortar_data(_mci_fe_problem.mortarData()),
157 1414 : _secondary_id(
158 2828 : _mci_mesh.getBoundaryID(moose_object->getParam<BoundaryName>("secondary_boundary"))),
159 2828 : _primary_id(_mci_mesh.getBoundaryID(moose_object->getParam<BoundaryName>("primary_boundary"))),
160 1414 : _secondary_subdomain_id(
161 2828 : _mci_mesh.getSubdomainID(moose_object->getParam<SubdomainName>("secondary_subdomain"))),
162 1414 : _primary_subdomain_id(
163 2828 : _mci_mesh.getSubdomainID(moose_object->getParam<SubdomainName>("primary_subdomain"))),
164 2828 : _secondary_set({_secondary_id}),
165 2828 : _interpolate_normals(moose_object->getParam<bool>("interpolate_normals")),
166 1414 : _phys_points_secondary(_mci_assembly.qPointsFace()),
167 1414 : _phys_points_primary(_mci_assembly.qPointsFaceNeighbor()),
168 1414 : _qrule_msm(_mci_assembly.qRuleMortar()),
169 1414 : _qrule_face(_mci_assembly.qRuleFace()),
170 1414 : _lower_secondary_elem(_mci_assembly.lowerDElem()),
171 1414 : _lower_primary_elem(_mci_assembly.neighborLowerDElem()),
172 1414 : _JxW_msm(_mci_assembly.jxWMortar()),
173 2828 : _msm_elem(_mci_assembly.msmElem())
174 : {
175 2828 : const bool displaced = moose_object->isParamValid("use_displaced_mesh")
176 5656 : ? moose_object->getParam<bool>("use_displaced_mesh")
177 1414 : : false;
178 :
179 : // Create the mortar interface if it hasn't already been created
180 2828 : _mci_fe_problem.createMortarInterface(
181 1414 : std::make_pair(_primary_id, _secondary_id),
182 0 : std::make_pair(_primary_subdomain_id, _secondary_subdomain_id),
183 : displaced,
184 2828 : moose_object->getParam<bool>("periodic"),
185 2828 : moose_object->getParam<bool>("debug_mesh"),
186 2828 : moose_object->getParam<bool>("correct_edge_dropping"),
187 5656 : moose_object->getParam<Real>("minimum_projection_angle"),
188 : moose_object->getParam<MooseEnum>("triangulation"),
189 4242 : moose_object->getParam<bool>("triangulate_triangles"));
190 :
191 1414 : _amg = &_mci_fe_problem.getMortarInterface(
192 1414 : std::make_pair(_primary_id, _secondary_id),
193 1414 : std::make_pair(_primary_subdomain_id, _secondary_subdomain_id),
194 : displaced);
195 :
196 1414 : const auto & secondary_set = _mortar_data.getHigherDimSubdomainIDs(_secondary_subdomain_id);
197 1414 : const auto & primary_set = _mortar_data.getHigherDimSubdomainIDs(_primary_subdomain_id);
198 :
199 2828 : std::set_union(secondary_set.begin(),
200 : secondary_set.end(),
201 : primary_set.begin(),
202 : primary_set.end(),
203 1414 : std::inserter(_higher_dim_subdomain_ids, _higher_dim_subdomain_ids.begin()));
204 1414 : _boundary_ids = {_secondary_id, _primary_id};
205 1414 : }
206 :
207 : void
208 492178 : MortarConsumerInterface::setNormals()
209 : {
210 492178 : if (interpolateNormals())
211 490982 : _normals = amg().getNormals(*_lower_secondary_elem, _qrule_face->get_points());
212 : else
213 1196 : _normals = amg().getNodalNormals(*_lower_secondary_elem);
214 492178 : }
215 :
216 : void
217 196448 : MortarConsumerInterface::trimDerivative(const dof_id_type remove_derivative_index,
218 : ADReal & dual_number)
219 : {
220 196448 : auto md_it = dual_number.derivatives().nude_data().begin();
221 196448 : auto mi_it = dual_number.derivatives().nude_indices().begin();
222 :
223 196448 : auto d_it = dual_number.derivatives().nude_data().begin();
224 :
225 196448 : for (auto i_it = dual_number.derivatives().nude_indices().begin();
226 554252 : i_it != dual_number.derivatives().nude_indices().end();
227 357804 : ++i_it, ++d_it)
228 357804 : if (*i_it != remove_derivative_index)
229 : {
230 333806 : *mi_it = *i_it;
231 333806 : *md_it = *d_it;
232 333806 : ++mi_it;
233 333806 : ++md_it;
234 : }
235 :
236 196448 : std::size_t n_indices = md_it - dual_number.derivatives().nude_data().begin();
237 196448 : dual_number.derivatives().nude_indices().resize(n_indices);
238 196448 : dual_number.derivatives().nude_data().resize(n_indices);
239 196448 : }
|