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