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 : #include "MortarInterfaceWarehouse.h"
11 : #include "SubProblem.h"
12 : #include "MooseMesh.h"
13 : #include "MooseError.h"
14 : #include "MooseEnum.h"
15 : #include "MooseUtils.h"
16 : #include "MortarExecutorInterface.h"
17 : #include "AutomaticMortarGeneration.h"
18 :
19 : namespace
20 : {
21 : MortarSegmentTriangulationMode
22 1481 : toTriangulationMode(const MooseEnum & triangulation)
23 : {
24 1481 : if (triangulation == "vertex")
25 12 : return MortarSegmentTriangulationMode::Vertex;
26 1469 : if (triangulation == "centroid")
27 1445 : return MortarSegmentTriangulationMode::Centroid;
28 24 : if (triangulation == "ear_clipping")
29 12 : return MortarSegmentTriangulationMode::EarClipping;
30 : #if defined(LIBMESH_HAVE_TRIANGLE) || defined(LIBMESH_HAVE_POLY2TRI)
31 12 : if (triangulation == "delaunay")
32 12 : return MortarSegmentTriangulationMode::Delaunay;
33 : #endif
34 0 : mooseError("Unsupported mortar triangulation option: ", triangulation);
35 : }
36 : }
37 :
38 63000 : MortarInterfaceWarehouse::MortarInterfaceWarehouse(const libMesh::ParallelObject & other)
39 63000 : : libMesh::ParallelObject(other), _mortar_initd(false)
40 : {
41 63000 : }
42 :
43 : void
44 1481 : MortarInterfaceWarehouse::createMortarInterface(
45 : const std::pair<BoundaryID, BoundaryID> & boundary_key,
46 : const std::pair<SubdomainID, SubdomainID> & subdomain_key,
47 : SubProblem & subproblem,
48 : bool on_displaced,
49 : bool periodic,
50 : const bool debug,
51 : const bool correct_edge_dropping,
52 : const Real minimum_projection_angle,
53 : const Mortar3DSubpatchPlane mortar_3d_subpatch_plane,
54 : const MooseEnum & triangulation,
55 : const bool triangulate_triangles,
56 : const Mortar3DQuadraturePointMapping mortar_3d_qp_mapping)
57 : {
58 1481 : _mortar_subdomain_coverage.insert(subdomain_key.first);
59 1481 : _mortar_subdomain_coverage.insert(subdomain_key.second);
60 :
61 1481 : _mortar_boundary_coverage.insert(boundary_key.first);
62 1481 : _mortar_boundary_coverage.insert(boundary_key.second);
63 :
64 1481 : MeshBase & mesh = subproblem.mesh().getMesh();
65 :
66 1481 : auto & mortar_interfaces = on_displaced ? _displaced_mortar_interfaces : _mortar_interfaces;
67 1481 : const auto triangulation_mode = toTriangulationMode(triangulation);
68 :
69 1481 : auto interface_iterator = mortar_interfaces.find(boundary_key);
70 1481 : if (interface_iterator != mortar_interfaces.end())
71 : {
72 : // Existing entry: every per-interface flag must agree across constraints sharing the same
73 : // primary-secondary surface pair.
74 402 : const auto & existing = interface_iterator->second;
75 402 : if (existing.periodic != periodic)
76 0 : mooseError("We do not currently support enforcing both periodic and non-periodic constraints "
77 : "on the same boundary primary-secondary pair");
78 402 : if (existing.debug != debug)
79 0 : mooseError(
80 : "We do not currently support generating and not generating debug output "
81 : "on the same boundary primary-secondary surface pair. Please set debug_mesh = true for "
82 : "all constraints sharing the same primary-secondary surface pairs");
83 402 : if (!MooseUtils::absoluteFuzzyEqual(existing.minimum_projection_angle,
84 : minimum_projection_angle))
85 3 : mooseError("We do not currently support multiple values of 'minimum_projection_angle' on "
86 : "the same boundary primary-secondary surface pair.");
87 399 : if (existing.mortar_3d_subpatch_plane != mortar_3d_subpatch_plane)
88 3 : mooseError("Mortar constraints sharing the same primary/secondary mortar interface must use "
89 : "the same 'mortar_3d_subpatch_plane' value.");
90 396 : if (existing.triangulation != triangulation_mode)
91 0 : mooseError("We do not currently support multiple values of 'triangulation' on the same "
92 : "boundary primary-secondary surface pair.");
93 396 : if (existing.triangulate_triangles != triangulate_triangles)
94 0 : mooseError("We do not currently support multiple values of 'triangulate_triangles' on the "
95 : "same boundary primary-secondary surface pair.");
96 396 : if (existing.mortar_3d_qp_mapping != mortar_3d_qp_mapping)
97 0 : mooseError("We do not currently support multiple values of 'mortar_3d_qp_mapping' on the "
98 : "same boundary primary-secondary surface pair.");
99 : }
100 : else
101 : {
102 : MortarInterfaceConfig config{
103 : std::make_unique<AutomaticMortarGeneration>(subproblem.getMooseApp(),
104 : mesh,
105 : boundary_key,
106 : subdomain_key,
107 : on_displaced,
108 : periodic,
109 : debug,
110 : correct_edge_dropping,
111 : minimum_projection_angle,
112 : mortar_3d_subpatch_plane,
113 : triangulation_mode,
114 : triangulate_triangles,
115 : mortar_3d_qp_mapping),
116 : periodic,
117 : debug,
118 : minimum_projection_angle,
119 : mortar_3d_subpatch_plane,
120 : triangulation_mode,
121 : triangulate_triangles,
122 1079 : mortar_3d_qp_mapping};
123 1079 : config.amg->initOutput();
124 1079 : mortar_interfaces.emplace(boundary_key, std::move(config));
125 1079 : }
126 :
127 : // See whether to query the mesh
128 1475 : SubdomainID key1 = subdomain_key.first;
129 1475 : SubdomainID key2 = subdomain_key.second;
130 :
131 : // it(1,2) is a a pair consisting of an iterator to the inserted element (or to the element that
132 : // prevented the insertion) and a bool denoting whether the insertion took place.
133 1475 : auto it1 = _lower_d_sub_to_higher_d_subs.insert(std::make_pair(key1, std::set<SubdomainID>{}));
134 1475 : auto it2 = _lower_d_sub_to_higher_d_subs.insert(std::make_pair(key2, std::set<SubdomainID>{}));
135 :
136 : // Each entry in this vector will be a pair. The first member of the pair corresponds to
137 : // the lower dimensional subomain ID. The second member of the pair corresponds to the higher
138 : // dimensional subdomain ids of the lower dimeionsal interior parents
139 1475 : std::vector<std::pair<SubdomainID, std::set<SubdomainID> *>> subdomains_to_probe;
140 :
141 1475 : if (it1.second)
142 1079 : subdomains_to_probe.push_back(std::make_pair(key1, &it1.first->second));
143 1475 : if (it2.second)
144 1079 : subdomains_to_probe.push_back(std::make_pair(key2, &it2.first->second));
145 :
146 3633 : for (auto & pr : subdomains_to_probe)
147 : {
148 4316 : for (const Elem * lower_d_elem : as_range(mesh.active_local_subdomain_elements_begin(pr.first),
149 31627 : mesh.active_local_subdomain_elements_end(pr.first)))
150 : {
151 25153 : const Elem * ip = lower_d_elem->interior_parent();
152 : mooseAssert(
153 : ip,
154 : "Lower dimensional elements should always have an interior parent set when using mortar");
155 25153 : pr.second->insert(ip->subdomain_id());
156 2158 : }
157 :
158 : // Make sure that we get this right in parallel
159 2158 : _communicator.set_union(*pr.second);
160 : }
161 1475 : }
162 :
163 : const AutomaticMortarGeneration &
164 256642 : MortarInterfaceWarehouse::getMortarInterface(
165 : const std::pair<BoundaryID, BoundaryID> & boundary_key,
166 : const std::pair<SubdomainID, SubdomainID> & /*subdomain_key*/,
167 : bool on_displaced) const
168 : {
169 256642 : auto & mortar_interfaces = on_displaced ? _displaced_mortar_interfaces : _mortar_interfaces;
170 256642 : auto it = mortar_interfaces.find(boundary_key);
171 256642 : if (it == mortar_interfaces.end())
172 0 : mooseError(
173 : "The requested mortar interface AutomaticMortarGeneration object does not yet exist!");
174 513284 : return *it->second.amg;
175 : }
176 :
177 : AutomaticMortarGeneration &
178 256642 : MortarInterfaceWarehouse::getMortarInterface(
179 : const std::pair<BoundaryID, BoundaryID> & boundary_key,
180 : const std::pair<SubdomainID, SubdomainID> & subdomain_key,
181 : bool on_displaced)
182 : {
183 : return const_cast<AutomaticMortarGeneration &>(
184 256642 : const_cast<const MortarInterfaceWarehouse *>(this)->getMortarInterface(
185 256642 : boundary_key, subdomain_key, on_displaced));
186 : }
187 :
188 : void
189 71591 : MortarInterfaceWarehouse::update()
190 : {
191 72643 : for (auto & mortar_pair : _mortar_interfaces)
192 1058 : update(*mortar_pair.second.amg);
193 75151 : for (auto & mortar_pair : _displaced_mortar_interfaces)
194 3566 : update(*mortar_pair.second.amg);
195 :
196 71585 : _mortar_initd = true;
197 71585 : }
198 :
199 : void
200 7044 : MortarInterfaceWarehouse::meshChanged()
201 : {
202 7146 : for (auto & mortar_pair : _mortar_interfaces)
203 102 : mortar_pair.second.amg->meshChanged();
204 7114 : for (auto & mortar_pair : _displaced_mortar_interfaces)
205 70 : mortar_pair.second.amg->meshChanged();
206 7044 : update();
207 7044 : }
208 :
209 : void
210 4624 : MortarInterfaceWarehouse::update(AutomaticMortarGeneration & amg)
211 : {
212 : // Clear exiting data
213 4624 : amg.clear();
214 :
215 4624 : const auto dim = amg.dim();
216 :
217 4624 : if (dim == 1)
218 3 : mooseError("Mortar constraints are not currently supported for 1D meshes");
219 4621 : else if (dim != 2 && dim != 3)
220 0 : mooseError("Invalid mesh dimension for mortar constraint");
221 :
222 : // Construct maps from nodes -> lower dimensional elements on the primary and secondary
223 : // boundaries.
224 4621 : amg.buildNodeToElemMaps();
225 :
226 : // Compute nodal geometry (normals and tangents).
227 4621 : amg.computeNodalGeometry();
228 :
229 4621 : if (dim == 2)
230 : {
231 : // Project secondary nodes (find xi^(2) values).
232 4263 : amg.projectSecondaryNodes();
233 :
234 : // Project primary nodes (find xi^(1) values).
235 4263 : amg.projectPrimaryNodes();
236 :
237 : // Build the mortar segment mesh on the secondary boundary.
238 4263 : amg.buildMortarSegmentMesh();
239 : }
240 : else // dim == 3
241 358 : amg.buildMortarSegmentMesh3d();
242 :
243 4618 : amg.computeInactiveLMNodes();
244 4618 : amg.computeInactiveLMElems();
245 4618 : }
246 :
247 : const std::set<SubdomainID> &
248 2950 : MortarInterfaceWarehouse::getHigherDimSubdomainIDs(SubdomainID lower_d_subdomain_id) const
249 : {
250 2950 : if (_lower_d_sub_to_higher_d_subs.find(lower_d_subdomain_id) ==
251 5900 : _lower_d_sub_to_higher_d_subs.end())
252 0 : mooseError("The lower dimensional ID ",
253 : lower_d_subdomain_id,
254 : " has not been added to MortarInterfaceWarehouse yet");
255 2950 : return _lower_d_sub_to_higher_d_subs.at(lower_d_subdomain_id);
256 : }
257 :
258 : void
259 0 : MortarInterfaceWarehouse::notifyWhenMortarSetup(MortarExecutorInterface * const mei_obj)
260 : {
261 0 : _mei_objs.insert(mei_obj);
262 0 : }
263 :
264 : void
265 0 : MortarInterfaceWarehouse::dontNotifyWhenMortarSetup(MortarExecutorInterface * const mei_obj)
266 : {
267 0 : _mei_objs.erase(mei_obj);
268 0 : }
|