LCOV - code coverage report
Current view: top level - src/constraints - MortarInterfaceWarehouse.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #33359 (04c914) with base 7b3324 Lines: 90 104 86.5 %
Date: 2026-07-16 14:28:29 Functions: 9 11 81.8 %
Legend: Lines: hit not hit

          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 : }

Generated by: LCOV version 1.14