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 "MortarExecutorInterface.h" 15 : #include "AutomaticMortarGeneration.h" 16 : 17 62032 : MortarInterfaceWarehouse::MortarInterfaceWarehouse(const libMesh::ParallelObject & other) 18 62032 : : libMesh::ParallelObject(other), _mortar_initd(false) 19 : { 20 62032 : } 21 : 22 : void 23 1329 : MortarInterfaceWarehouse::createMortarInterface( 24 : const std::pair<BoundaryID, BoundaryID> & boundary_key, 25 : const std::pair<SubdomainID, SubdomainID> & subdomain_key, 26 : SubProblem & subproblem, 27 : bool on_displaced, 28 : bool periodic, 29 : const bool debug, 30 : const bool correct_edge_dropping, 31 : const Real minimum_projection_angle) 32 : { 33 1329 : _mortar_subdomain_coverage.insert(subdomain_key.first); 34 1329 : _mortar_subdomain_coverage.insert(subdomain_key.second); 35 : 36 1329 : _mortar_boundary_coverage.insert(boundary_key.first); 37 1329 : _mortar_boundary_coverage.insert(boundary_key.second); 38 : 39 1329 : MeshBase & mesh = subproblem.mesh().getMesh(); 40 : 41 1329 : auto & periodic_map = on_displaced ? _displaced_periodic_map : _periodic_map; 42 1329 : auto & debug_flag_map = on_displaced ? _displaced_debug_flag_map : _debug_flag_map; 43 1329 : auto & mortar_interfaces = on_displaced ? _displaced_mortar_interfaces : _mortar_interfaces; 44 : 45 : // Periodic flag 46 1329 : auto periodic_map_iterator = periodic_map.find(boundary_key); 47 1329 : if (periodic_map_iterator != periodic_map.end() && periodic_map_iterator->second != periodic) 48 0 : mooseError("We do not currently support enforcing both periodic and non-periodic constraints " 49 : "on the same boundary primary-secondary pair"); 50 : else 51 1329 : periodic_map.insert(periodic_map_iterator, std::make_pair(boundary_key, periodic)); 52 : 53 : // Debug mesh flag displaced 54 1329 : auto debug_flag_map_iterator = debug_flag_map.find(boundary_key); 55 1329 : if (debug_flag_map_iterator != debug_flag_map.end() && debug_flag_map_iterator->second != debug) 56 0 : mooseError( 57 : "We do not currently support generating and not generating debug output " 58 : "on the same boundary primary-secondary surface pair. Please set debug_mesh = true for " 59 : "all constraints sharing the same primary-secondary surface pairs"); 60 : else 61 1329 : debug_flag_map.insert(debug_flag_map_iterator, std::make_pair(boundary_key, debug)); 62 : 63 : // Generate lower-d mesh 64 1329 : if (mortar_interfaces.find(boundary_key) == mortar_interfaces.end()) 65 : { 66 1866 : auto [it, inserted] = mortar_interfaces.emplace( 67 : boundary_key, 68 1866 : std::make_unique<AutomaticMortarGeneration>(subproblem.getMooseApp(), 69 : mesh, 70 : boundary_key, 71 : subdomain_key, 72 : on_displaced, 73 : periodic, 74 : debug, 75 : correct_edge_dropping, 76 : minimum_projection_angle)); 77 933 : if (inserted) 78 933 : it->second->initOutput(); 79 : } 80 : 81 : // See whether to query the mesh 82 1329 : SubdomainID key1 = subdomain_key.first; 83 1329 : SubdomainID key2 = subdomain_key.second; 84 : 85 : // it(1,2) is a a pair consisting of an iterator to the inserted element (or to the element that 86 : // prevented the insertion) and a bool denoting whether the insertion took place. 87 1329 : auto it1 = _lower_d_sub_to_higher_d_subs.insert(std::make_pair(key1, std::set<SubdomainID>{})); 88 1329 : auto it2 = _lower_d_sub_to_higher_d_subs.insert(std::make_pair(key2, std::set<SubdomainID>{})); 89 : 90 : // Each entry in this vector will be a pair. The first member of the pair corresponds to 91 : // the lower dimensional subomain ID. The second member of the pair corresponds to the higher 92 : // dimensional subdomain ids of the lower dimeionsal interior parents 93 1329 : std::vector<std::pair<SubdomainID, std::set<SubdomainID> *>> subdomains_to_probe; 94 : 95 1329 : if (it1.second) 96 933 : subdomains_to_probe.push_back(std::make_pair(key1, &it1.first->second)); 97 1329 : if (it2.second) 98 933 : subdomains_to_probe.push_back(std::make_pair(key2, &it2.first->second)); 99 : 100 3195 : for (auto & pr : subdomains_to_probe) 101 : { 102 3732 : for (const Elem * lower_d_elem : as_range(mesh.active_local_subdomain_elements_begin(pr.first), 103 20237 : mesh.active_local_subdomain_elements_end(pr.first))) 104 : { 105 14639 : const Elem * ip = lower_d_elem->interior_parent(); 106 : mooseAssert( 107 : ip, 108 : "Lower dimensional elements should always have an interior parent set when using mortar"); 109 14639 : pr.second->insert(ip->subdomain_id()); 110 1866 : } 111 : 112 : // Make sure that we get this right in parallel 113 1866 : _communicator.set_union(*pr.second); 114 : } 115 1329 : } 116 : 117 : const AutomaticMortarGeneration & 118 165402 : MortarInterfaceWarehouse::getMortarInterface( 119 : const std::pair<BoundaryID, BoundaryID> & boundary_key, 120 : const std::pair<SubdomainID, SubdomainID> & /*subdomain_key*/, 121 : bool on_displaced) const 122 : { 123 165402 : auto & mortar_interfaces = on_displaced ? _displaced_mortar_interfaces : _mortar_interfaces; 124 165402 : auto it = mortar_interfaces.find(boundary_key); 125 165402 : if (it == mortar_interfaces.end()) 126 0 : mooseError( 127 : "The requested mortar interface AutomaticMortarGeneration object does not yet exist!"); 128 330804 : return *it->second; 129 : } 130 : 131 : AutomaticMortarGeneration & 132 165402 : MortarInterfaceWarehouse::getMortarInterface( 133 : const std::pair<BoundaryID, BoundaryID> & boundary_key, 134 : const std::pair<SubdomainID, SubdomainID> & subdomain_key, 135 : bool on_displaced) 136 : { 137 : return const_cast<AutomaticMortarGeneration &>( 138 165402 : const_cast<const MortarInterfaceWarehouse *>(this)->getMortarInterface( 139 165402 : boundary_key, subdomain_key, on_displaced)); 140 : } 141 : 142 : void 143 70653 : MortarInterfaceWarehouse::update() 144 : { 145 71568 : for (auto & mortar_pair : _mortar_interfaces) 146 918 : update(*mortar_pair.second); 147 74216 : for (auto & mortar_pair : _displaced_mortar_interfaces) 148 3566 : update(*mortar_pair.second); 149 : 150 70650 : _mortar_initd = true; 151 70650 : } 152 : 153 : void 154 7002 : MortarInterfaceWarehouse::meshChanged() 155 : { 156 7104 : for (auto & mortar_pair : _mortar_interfaces) 157 102 : mortar_pair.second->meshChanged(); 158 7072 : for (auto & mortar_pair : _displaced_mortar_interfaces) 159 70 : mortar_pair.second->meshChanged(); 160 7002 : update(); 161 7002 : } 162 : 163 : void 164 4484 : MortarInterfaceWarehouse::update(AutomaticMortarGeneration & amg) 165 : { 166 : // Clear exiting data 167 4484 : amg.clear(); 168 : 169 4484 : const auto dim = amg.dim(); 170 : 171 4484 : if (dim == 1) 172 3 : mooseError("Mortar constraints are not currently supported for 1D meshes"); 173 4481 : else if (dim != 2 && dim != 3) 174 0 : mooseError("Invalid mesh dimension for mortar constraint"); 175 : 176 : // Construct maps from nodes -> lower dimensional elements on the primary and secondary 177 : // boundaries. 178 4481 : amg.buildNodeToElemMaps(); 179 : 180 : // Compute nodal geometry (normals and tangents). 181 4481 : amg.computeNodalGeometry(); 182 : 183 4481 : if (dim == 2) 184 : { 185 : // Project secondary nodes (find xi^(2) values). 186 4263 : amg.projectSecondaryNodes(); 187 : 188 : // Project primary nodes (find xi^(1) values). 189 4263 : amg.projectPrimaryNodes(); 190 : 191 : // Build the mortar segment mesh on the secondary boundary. 192 4263 : amg.buildMortarSegmentMesh(); 193 : } 194 : else // dim == 3 195 218 : amg.buildMortarSegmentMesh3d(); 196 : 197 4481 : amg.computeInactiveLMNodes(); 198 4481 : amg.computeInactiveLMElems(); 199 4481 : } 200 : 201 : const std::set<SubdomainID> & 202 2658 : MortarInterfaceWarehouse::getHigherDimSubdomainIDs(SubdomainID lower_d_subdomain_id) const 203 : { 204 2658 : if (_lower_d_sub_to_higher_d_subs.find(lower_d_subdomain_id) == 205 5316 : _lower_d_sub_to_higher_d_subs.end()) 206 0 : mooseError("The lower dimensional ID ", 207 : lower_d_subdomain_id, 208 : " has not been added to MortarInterfaceWarehouse yet"); 209 2658 : return _lower_d_sub_to_higher_d_subs.at(lower_d_subdomain_id); 210 : } 211 : 212 : void 213 0 : MortarInterfaceWarehouse::notifyWhenMortarSetup(MortarExecutorInterface * const mei_obj) 214 : { 215 0 : _mei_objs.insert(mei_obj); 216 0 : } 217 : 218 : void 219 0 : MortarInterfaceWarehouse::dontNotifyWhenMortarSetup(MortarExecutorInterface * const mei_obj) 220 : { 221 0 : _mei_objs.erase(mei_obj); 222 0 : }