https://mooseframework.inl.gov
MortarInterfaceWarehouse.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 
11 #include "SubProblem.h"
12 #include "MooseMesh.h"
13 #include "MooseError.h"
14 #include "MooseEnum.h"
15 #include "MooseUtils.h"
18 
19 namespace
20 {
22 toTriangulationMode(const MooseEnum & triangulation)
23 {
24  if (triangulation == "vertex")
26  if (triangulation == "centroid")
28  if (triangulation == "ear_clipping")
30 #if defined(LIBMESH_HAVE_TRIANGLE) || defined(LIBMESH_HAVE_POLY2TRI)
31  if (triangulation == "delaunay")
33 #endif
34  mooseError("Unsupported mortar triangulation option: ", triangulation);
35 }
36 }
37 
39  : libMesh::ParallelObject(other), _mortar_initd(false)
40 {
41 }
42 
43 void
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  _mortar_subdomain_coverage.insert(subdomain_key.first);
59  _mortar_subdomain_coverage.insert(subdomain_key.second);
60 
61  _mortar_boundary_coverage.insert(boundary_key.first);
62  _mortar_boundary_coverage.insert(boundary_key.second);
63 
64  MeshBase & mesh = subproblem.mesh().getMesh();
65 
66  auto & mortar_interfaces = on_displaced ? _displaced_mortar_interfaces : _mortar_interfaces;
67  const auto triangulation_mode = toTriangulationMode(triangulation);
68 
69  auto interface_iterator = mortar_interfaces.find(boundary_key);
70  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  const auto & existing = interface_iterator->second;
75  if (existing.periodic != periodic)
76  mooseError("We do not currently support enforcing both periodic and non-periodic constraints "
77  "on the same boundary primary-secondary pair");
78  if (existing.debug != debug)
79  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  if (!MooseUtils::absoluteFuzzyEqual(existing.minimum_projection_angle,
84  minimum_projection_angle))
85  mooseError("We do not currently support multiple values of 'minimum_projection_angle' on "
86  "the same boundary primary-secondary surface pair.");
87  if (existing.mortar_3d_subpatch_plane != mortar_3d_subpatch_plane)
88  mooseError("Mortar constraints sharing the same primary/secondary mortar interface must use "
89  "the same 'mortar_3d_subpatch_plane' value.");
90  if (existing.triangulation != triangulation_mode)
91  mooseError("We do not currently support multiple values of 'triangulation' on the same "
92  "boundary primary-secondary surface pair.");
93  if (existing.triangulate_triangles != triangulate_triangles)
94  mooseError("We do not currently support multiple values of 'triangulate_triangles' on the "
95  "same boundary primary-secondary surface pair.");
96  if (existing.mortar_3d_qp_mapping != mortar_3d_qp_mapping)
97  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  mortar_3d_qp_mapping};
123  config.amg->initOutput();
124  mortar_interfaces.emplace(boundary_key, std::move(config));
125  }
126 
127  // See whether to query the mesh
128  SubdomainID key1 = subdomain_key.first;
129  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  auto it1 = _lower_d_sub_to_higher_d_subs.insert(std::make_pair(key1, std::set<SubdomainID>{}));
134  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  std::vector<std::pair<SubdomainID, std::set<SubdomainID> *>> subdomains_to_probe;
140 
141  if (it1.second)
142  subdomains_to_probe.push_back(std::make_pair(key1, &it1.first->second));
143  if (it2.second)
144  subdomains_to_probe.push_back(std::make_pair(key2, &it2.first->second));
145 
146  for (auto & pr : subdomains_to_probe)
147  {
148  for (const Elem * lower_d_elem : as_range(mesh.active_local_subdomain_elements_begin(pr.first),
149  mesh.active_local_subdomain_elements_end(pr.first)))
150  {
151  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  pr.second->insert(ip->subdomain_id());
156  }
157 
158  // Make sure that we get this right in parallel
159  _communicator.set_union(*pr.second);
160  }
161 }
162 
165  const std::pair<BoundaryID, BoundaryID> & boundary_key,
166  const std::pair<SubdomainID, SubdomainID> & /*subdomain_key*/,
167  bool on_displaced) const
168 {
169  auto & mortar_interfaces = on_displaced ? _displaced_mortar_interfaces : _mortar_interfaces;
170  auto it = mortar_interfaces.find(boundary_key);
171  if (it == mortar_interfaces.end())
172  mooseError(
173  "The requested mortar interface AutomaticMortarGeneration object does not yet exist!");
174  return *it->second.amg;
175 }
176 
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  const_cast<const MortarInterfaceWarehouse *>(this)->getMortarInterface(
185  boundary_key, subdomain_key, on_displaced));
186 }
187 
188 void
190 {
191  for (auto & mortar_pair : _mortar_interfaces)
192  update(*mortar_pair.second.amg);
193  for (auto & mortar_pair : _displaced_mortar_interfaces)
194  update(*mortar_pair.second.amg);
195 
196  _mortar_initd = true;
197 }
198 
199 void
201 {
202  for (auto & mortar_pair : _mortar_interfaces)
203  mortar_pair.second.amg->meshChanged();
204  for (auto & mortar_pair : _displaced_mortar_interfaces)
205  mortar_pair.second.amg->meshChanged();
206  update();
207 }
208 
209 void
211 {
212  // Clear exiting data
213  amg.clear();
214 
215  const auto dim = amg.dim();
216 
217  if (dim == 1)
218  mooseError("Mortar constraints are not currently supported for 1D meshes");
219  else if (dim != 2 && dim != 3)
220  mooseError("Invalid mesh dimension for mortar constraint");
221 
222  // Construct maps from nodes -> lower dimensional elements on the primary and secondary
223  // boundaries.
224  amg.buildNodeToElemMaps();
225 
226  // Compute nodal geometry (normals and tangents).
227  amg.computeNodalGeometry();
228 
229  if (dim == 2)
230  {
231  // Project secondary nodes (find xi^(2) values).
232  amg.projectSecondaryNodes();
233 
234  // Project primary nodes (find xi^(1) values).
235  amg.projectPrimaryNodes();
236 
237  // Build the mortar segment mesh on the secondary boundary.
239  }
240  else // dim == 3
242 
245 }
246 
247 const std::set<SubdomainID> &
249 {
250  if (_lower_d_sub_to_higher_d_subs.find(lower_d_subdomain_id) ==
252  mooseError("The lower dimensional ID ",
253  lower_d_subdomain_id,
254  " has not been added to MortarInterfaceWarehouse yet");
255  return _lower_d_sub_to_higher_d_subs.at(lower_d_subdomain_id);
256 }
257 
258 void
260 {
261  _mei_objs.insert(mei_obj);
262 }
263 
264 void
266 {
267  _mei_objs.erase(mei_obj);
268 }
virtual MooseMesh & mesh()=0
void dontNotifyWhenMortarSetup(MortarExecutorInterface *mei)
Removes mei from the container of objects that will have their mortarSetup method called as soon as t...
void createMortarInterface(const std::pair< BoundaryID, BoundaryID > &boundary_key, const std::pair< SubdomainID, SubdomainID > &subdomain_key, SubProblem &subproblem, bool on_displaced, bool periodic, const bool debug, const bool correct_edge_dropping, const Real minimum_projection_angle, const Mortar3DSubpatchPlane mortar_3d_subpatch_plane, const MooseEnum &triangulation, const bool triangulate_triangles, const Mortar3DQuadraturePointMapping mortar_3d_qp_mapping=Mortar3DQuadraturePointMapping::NORMAL_PROJECTION)
Create mortar generation object.
void computeInactiveLMNodes()
Get list of secondary nodes that don&#39;t contribute to interaction with any primary element...
void clear()
Clears the mortar segment mesh and accompanying data structures.
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311
Interface for notifications that the mortar mesh has been setup.
std::set< MortarExecutorInterface * > _mei_objs
A container of objects for whom the mortarSetup method will be called after the mortar mesh has been ...
MeshBase & mesh
void buildMortarSegmentMesh()
Builds the mortar segment mesh once the secondary and primary node projections have been completed...
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
Definition: Moose.h:165
const Parallel::Communicator & _communicator
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
bool _mortar_initd
Whether we have performed any mortar mesh construction.
MooseApp & getMooseApp() const
Get the MooseApp this class is associated with.
Definition: MooseBase.h:87
void projectSecondaryNodes()
Project secondary nodes (find xi^(2) values) to the closest points on the primary surface...
Per-mortar-interface configuration.
This class is a container/interface for the objects involved in automatic generation of mortar spaces...
MortarSegmentTriangulationMode
void notifyWhenMortarSetup(MortarExecutorInterface *mei)
Adds mei to the container of objects that will have their mortarSetup method called as soon as the mo...
void projectPrimaryNodes()
(Inverse) project primary nodes to the points on the secondary surface where they would have come fro...
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition: MooseMesh.C:3548
const std::set< SubdomainID > & getHigherDimSubdomainIDs(SubdomainID lower_d_subdomain_id) const
Returns the higher dimensional subdomain ids of the interior parents of the given lower-d subdomain i...
void buildNodeToElemMaps()
Once the secondary_requested_boundary_ids and primary_requested_boundary_ids containers have been fil...
std::unordered_map< SubdomainID, std::set< SubdomainID > > _lower_d_sub_to_higher_d_subs
Map from lower dimensional subdomain ids to corresponding higher simensional subdomain ids (e...
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
std::unordered_map< MortarKey, MortarInterfaceConfig > _mortar_interfaces
Map from primary-secondary (in that order) boundary ID pair to the configuration of the undisplaced m...
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition: MooseEnum.h:54
void computeNodalGeometry()
Computes and stores the nodal normal/tangent vectors in a local data structure instead of using the E...
void buildMortarSegmentMesh3d()
Builds the mortar segment mesh once the secondary and primary node projections have been completed...
void update()
Builds mortar segment meshes for each mortar interface.
Generic class for solving transient nonlinear problems.
Definition: SubProblem.h:78
std::set< SubdomainID > _mortar_subdomain_coverage
A set containing the subdomain ids covered by all the mortar interfaces in this MortarInterfaceWareho...
std::unordered_map< MortarKey, MortarInterfaceConfig > _displaced_mortar_interfaces
Map from primary-secondary (in that order) boundary ID pair to the configuration of the displaced mor...
const AutomaticMortarGeneration & getMortarInterface(const std::pair< BoundaryID, BoundaryID > &boundary_key, const std::pair< SubdomainID, SubdomainID > &, bool on_displaced) const
Getter to retrieve the AutomaticMortarGeneration object corresponding to the boundary and subdomain k...
void meshChanged()
Invalidates cached MSM node/element ID offsets on all mortar interfaces so they are recomputed on the...
std::set< BoundaryID > _mortar_boundary_coverage
A set containing the boundary ids covered by all the mortar interfaces in this MortarInterfaceWarehou...
std::unique_ptr< AutomaticMortarGeneration > amg
MortarInterfaceWarehouse(const libMesh::ParallelObject &other)
void computeInactiveLMElems()
Get list of secondary elems without any corresponding primary elements.
void set_union(T &data, const unsigned int root_id) const