LCOV - code coverage report
Current view: top level - src/constraints - MortarInterfaceWarehouse.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #31730 (e8b711) with base e0c998 Lines: 73 84 86.9 %
Date: 2025-10-29 16:49:47 Functions: 7 9 77.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 "MortarExecutorInterface.h"
      15             : #include "AutomaticMortarGeneration.h"
      16             : 
      17       64599 : MortarInterfaceWarehouse::MortarInterfaceWarehouse(const libMesh::ParallelObject & other)
      18       64599 :   : libMesh::ParallelObject(other), _mortar_initd(false)
      19             : {
      20       64599 : }
      21             : 
      22             : void
      23        1448 : 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        1448 :   _mortar_subdomain_coverage.insert(subdomain_key.first);
      34        1448 :   _mortar_subdomain_coverage.insert(subdomain_key.second);
      35             : 
      36        1448 :   _mortar_boundary_coverage.insert(boundary_key.first);
      37        1448 :   _mortar_boundary_coverage.insert(boundary_key.second);
      38             : 
      39        1448 :   MeshBase & mesh = subproblem.mesh().getMesh();
      40             : 
      41        1448 :   auto & periodic_map = on_displaced ? _displaced_periodic_map : _periodic_map;
      42        1448 :   auto & debug_flag_map = on_displaced ? _displaced_debug_flag_map : _debug_flag_map;
      43        1448 :   auto & mortar_interfaces = on_displaced ? _displaced_mortar_interfaces : _mortar_interfaces;
      44             : 
      45             :   // Periodic flag
      46        1448 :   auto periodic_map_iterator = periodic_map.find(boundary_key);
      47        1448 :   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        1448 :     periodic_map.insert(periodic_map_iterator, std::make_pair(boundary_key, periodic));
      52             : 
      53             :   // Debug mesh flag displaced
      54        1448 :   auto debug_flag_map_iterator = debug_flag_map.find(boundary_key);
      55        1448 :   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        1448 :     debug_flag_map.insert(debug_flag_map_iterator, std::make_pair(boundary_key, debug));
      62             : 
      63             :   // Generate lower-d mesh
      64        1448 :   if (mortar_interfaces.find(boundary_key) == mortar_interfaces.end())
      65             :   {
      66        2048 :     auto [it, inserted] = mortar_interfaces.emplace(
      67             :         boundary_key,
      68        2048 :         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        1024 :     if (inserted)
      78        1024 :       it->second->initOutput();
      79             :   }
      80             : 
      81             :   // See whether to query the mesh
      82        1448 :   SubdomainID key1 = subdomain_key.first;
      83        1448 :   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        1448 :   auto it1 = _lower_d_sub_to_higher_d_subs.insert(std::make_pair(key1, std::set<SubdomainID>{}));
      88        1448 :   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        1448 :   std::vector<std::pair<SubdomainID, std::set<SubdomainID> *>> subdomains_to_probe;
      94             : 
      95        1448 :   if (it1.second)
      96        1024 :     subdomains_to_probe.push_back(std::make_pair(key1, &it1.first->second));
      97        1448 :   if (it2.second)
      98        1024 :     subdomains_to_probe.push_back(std::make_pair(key2, &it2.first->second));
      99             : 
     100        3496 :   for (auto & pr : subdomains_to_probe)
     101             :   {
     102        4096 :     for (const Elem * lower_d_elem : as_range(mesh.active_local_subdomain_elements_begin(pr.first),
     103       23573 :                                               mesh.active_local_subdomain_elements_end(pr.first)))
     104             :     {
     105       17429 :       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       17429 :       pr.second->insert(ip->subdomain_id());
     110        2048 :     }
     111             : 
     112             :     // Make sure that we get this right in parallel
     113        2048 :     _communicator.set_union(*pr.second);
     114             :   }
     115        1448 : }
     116             : 
     117             : const AutomaticMortarGeneration &
     118      258234 : 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      258234 :   auto & mortar_interfaces = on_displaced ? _displaced_mortar_interfaces : _mortar_interfaces;
     124      258234 :   auto it = mortar_interfaces.find(boundary_key);
     125      258234 :   if (it == mortar_interfaces.end())
     126           0 :     mooseError(
     127             :         "The requested mortar interface AutomaticMortarGeneration object does not yet exist!");
     128      516468 :   return *it->second;
     129             : }
     130             : 
     131             : AutomaticMortarGeneration &
     132      258234 : 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      258234 :       const_cast<const MortarInterfaceWarehouse *>(this)->getMortarInterface(
     139      258234 :           boundary_key, subdomain_key, on_displaced));
     140             : }
     141             : 
     142             : void
     143       73886 : MortarInterfaceWarehouse::update()
     144             : {
     145       74898 :   for (auto & mortar_pair : _mortar_interfaces)
     146        1012 :     update(*mortar_pair.second);
     147       77811 :   for (auto & mortar_pair : _displaced_mortar_interfaces)
     148        3925 :     update(*mortar_pair.second);
     149             : 
     150       73886 :   _mortar_initd = true;
     151       73886 : }
     152             : 
     153             : void
     154        4937 : MortarInterfaceWarehouse::update(AutomaticMortarGeneration & amg)
     155             : {
     156             :   // Clear exiting data
     157        4937 :   amg.clear();
     158             : 
     159             :   // Construct maps from nodes -> lower dimensional elements on the primary and secondary
     160             :   // boundaries.
     161        4937 :   amg.buildNodeToElemMaps();
     162             : 
     163             :   // Compute nodal geometry (normals and tangents).
     164        4937 :   amg.computeNodalGeometry();
     165             : 
     166        4937 :   const auto dim = amg.dim();
     167        4937 :   if (dim == 2)
     168             :   {
     169             :     // Project secondary nodes (find xi^(2) values).
     170        4719 :     amg.projectSecondaryNodes();
     171             : 
     172             :     // Project primary nodes (find xi^(1) values).
     173        4719 :     amg.projectPrimaryNodes();
     174             : 
     175             :     // Build the mortar segment mesh on the secondary boundary.
     176        4719 :     amg.buildMortarSegmentMesh();
     177             :   }
     178         218 :   else if (dim == 3)
     179         218 :     amg.buildMortarSegmentMesh3d();
     180             :   else
     181           0 :     mooseError("Invalid mesh dimension for mortar constraint");
     182             : 
     183        4937 :   amg.computeInactiveLMNodes();
     184        4937 :   amg.computeInactiveLMElems();
     185        4937 : }
     186             : 
     187             : const std::set<SubdomainID> &
     188        2896 : MortarInterfaceWarehouse::getHigherDimSubdomainIDs(SubdomainID lower_d_subdomain_id) const
     189             : {
     190        2896 :   if (_lower_d_sub_to_higher_d_subs.find(lower_d_subdomain_id) ==
     191        5792 :       _lower_d_sub_to_higher_d_subs.end())
     192           0 :     mooseError("The lower dimensional ID ",
     193             :                lower_d_subdomain_id,
     194             :                " has not been added to MortarInterfaceWarehouse yet");
     195        2896 :   return _lower_d_sub_to_higher_d_subs.at(lower_d_subdomain_id);
     196             : }
     197             : 
     198             : void
     199           0 : MortarInterfaceWarehouse::notifyWhenMortarSetup(MortarExecutorInterface * const mei_obj)
     200             : {
     201           0 :   _mei_objs.insert(mei_obj);
     202           0 : }
     203             : 
     204             : void
     205           0 : MortarInterfaceWarehouse::dontNotifyWhenMortarSetup(MortarExecutorInterface * const mei_obj)
     206             : {
     207           0 :   _mei_objs.erase(mei_obj);
     208           0 : }

Generated by: LCOV version 1.14