LCOV - code coverage report
Current view: top level - src/interfaces - MortarConsumerInterface.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #33358 (34476d) with base 4fcf7b Lines: 114 116 98.3 %
Date: 2026-07-17 19:50:30 Functions: 7 7 100.0 %
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             : // MOOSE Includes
      11             : #include "MortarConsumerInterface.h"
      12             : #include "InputParameters.h"
      13             : #include "MooseObject.h"
      14             : #include "FEProblemBase.h"
      15             : #include "MooseMesh.h"
      16             : #include "MortarInterfaceWarehouse.h"
      17             : #include "Assembly.h"
      18             : #include "AutomaticMortarGeneration.h"
      19             : #include "libmesh/quadrature.h"
      20             : 
      21             : #include <algorithm>
      22             : 
      23             : InputParameters
      24       57939 : MortarConsumerInterface::validParams()
      25             : {
      26             :   // Create InputParameters object that will be appended to the parameters for the inheriting object
      27       57939 :   InputParameters params = emptyInputParameters();
      28             :   // On a displaced mesh this will geometrically and algebraically ghost the entire interface
      29      173817 :   params.addRelationshipManager(
      30             :       "AugmentSparsityOnInterface",
      31             :       Moose::RelationshipManagerType::GEOMETRIC | Moose::RelationshipManagerType::ALGEBRAIC,
      32       57939 :       [](const InputParameters & obj_params, InputParameters & rm_params)
      33             :       {
      34        8580 :         rm_params.set<bool>("use_displaced_mesh") = obj_params.get<bool>("use_displaced_mesh");
      35        8580 :         rm_params.set<BoundaryName>("secondary_boundary") =
      36        8580 :             obj_params.get<BoundaryName>("secondary_boundary");
      37        8580 :         rm_params.set<BoundaryName>("primary_boundary") =
      38        8580 :             obj_params.get<BoundaryName>("primary_boundary");
      39        8580 :         rm_params.set<SubdomainName>("secondary_subdomain") =
      40        8580 :             obj_params.get<SubdomainName>("secondary_subdomain");
      41        8580 :         rm_params.set<SubdomainName>("primary_subdomain") =
      42        8580 :             obj_params.get<SubdomainName>("primary_subdomain");
      43        4290 :         rm_params.set<bool>("ghost_point_neighbors") =
      44        4290 :             obj_params.get<bool>("ghost_point_neighbors");
      45        4290 :         rm_params.set<bool>("ghost_higher_d_neighbors") =
      46        4290 :             obj_params.get<bool>("ghost_higher_d_neighbors");
      47        4290 :       });
      48             : 
      49      231756 :   params.addRequiredParam<BoundaryName>("primary_boundary",
      50             :                                         "The name of the primary boundary sideset.");
      51      231756 :   params.addRequiredParam<BoundaryName>("secondary_boundary",
      52             :                                         "The name of the secondary boundary sideset.");
      53      231756 :   params.addRequiredParam<SubdomainName>("primary_subdomain", "The name of the primary subdomain.");
      54      231756 :   params.addRequiredParam<SubdomainName>("secondary_subdomain",
      55             :                                          "The name of the secondary subdomain.");
      56      173817 :   params.addParam<bool>(
      57             :       "periodic",
      58      115878 :       false,
      59             :       "Whether this constraint is going to be used to enforce a periodic condition. This has the "
      60             :       "effect of changing the normals vector for projection from outward to inward facing");
      61             : 
      62      173817 :   params.addParam<bool>(
      63             :       "debug_mesh",
      64      115878 :       false,
      65             :       "Whether this constraint is going to enable mortar segment mesh debug information. An exodus"
      66             :       "file will be generated if the user sets this flag to true");
      67             : 
      68      173817 :   params.addParam<bool>(
      69             :       "correct_edge_dropping",
      70      115878 :       false,
      71             :       "Whether to enable correct edge dropping treatment for mortar constraints. When disabled "
      72             :       "any Lagrange Multiplier degree of freedom on a secondary element without full primary "
      73             :       "contributions will be set (strongly) to 0.");
      74             : 
      75      173817 :   params.addParam<bool>(
      76             :       "interpolate_normals",
      77      115878 :       true,
      78             :       "Whether to interpolate the nodal normals (e.g. classic idea of evaluating field at "
      79             :       "quadrature points). If this is set to false, then non-interpolated nodal normals will be "
      80             :       "used, and then the _normals member should be indexed with _i instead of _qp");
      81             : 
      82      173817 :   params.addParam<bool>("ghost_point_neighbors",
      83      115878 :                         false,
      84             :                         "Whether we should ghost point neighbors of secondary face elements, and "
      85             :                         "consequently also their mortar interface couples.");
      86      115878 :   params.addParam<Real>(
      87             :       "minimum_projection_angle",
      88      173817 :       40.0,
      89             :       "Parameter to control which angle (in degrees) is admissible for the creation of mortar "
      90             :       "segments.  If set to a value close to zero, very oblique projections are allowed, which "
      91             :       "can result in mortar segments solving physics not meaningfully, and overprojection of "
      92             :       "primary nodes onto the mortar segment mesh in extreme cases. This parameter is mostly "
      93             :       "intended for mortar mesh debugging purposes in two dimensions.");
      94       57939 :   params += MortarConsumerInterface::triangulationParams();
      95             : 
      96      115878 :   params.addParam<bool>(
      97             :       "ghost_higher_d_neighbors",
      98      115878 :       false,
      99             :       "Whether we should ghost higher-dimensional neighbors. This is necessary when we are doing "
     100             :       "second order mortar with finite volume primal variables, because in order for the method to "
     101             :       "be second order we must use cell gradients, which couples in the neighbor cells.");
     102             : 
     103       57939 :   return params;
     104           0 : }
     105             : 
     106             : InputParameters
     107       57939 : MortarConsumerInterface::triangulationParams()
     108             : {
     109       57939 :   InputParameters params = emptyInputParameters();
     110             : 
     111             :   MooseEnum triangulation(
     112             : #if defined(LIBMESH_HAVE_TRIANGLE) || defined(LIBMESH_HAVE_POLY2TRI)
     113             :       "vertex centroid ear_clipping delaunay",
     114             : #else
     115             :       "vertex centroid ear_clipping",
     116             : #endif
     117      231756 :       "centroid");
     118      231756 :   triangulation.addDocumentation(
     119             :       "vertex",
     120             :       "Triangulate clipped 3D mortar polygons by forming a fan from an existing polygon vertex.");
     121      231756 :   triangulation.addDocumentation(
     122             :       "centroid",
     123             :       "Triangulate clipped 3D mortar polygons by forming a fan from a polygon centroid.");
     124      231756 :   triangulation.addDocumentation(
     125             :       "ear_clipping", "Triangulate clipped 3D mortar polygons with an ear-clipping algorithm.");
     126             : #if defined(LIBMESH_HAVE_TRIANGLE) || defined(LIBMESH_HAVE_POLY2TRI)
     127      231756 :   triangulation.addDocumentation(
     128             :       "delaunay",
     129             :       "Triangulate clipped 3D mortar polygons using libMesh's constrained-Delaunay PSLG "
     130             :       "triangulation backend while preserving polygon boundary edges.");
     131             : #endif
     132      231756 :   params.addParam<MooseEnum>(
     133             :       "triangulation",
     134             :       triangulation,
     135             :       "Strategy used to triangulate clipped 3D mortar polygons into mortar segments. The default "
     136             :       "is 'centroid' to preserve the legacy 3D mortar segmentation behavior.");
     137      115878 :   params.addParam<bool>(
     138             :       "triangulate_triangles",
     139      115878 :       false,
     140             :       "Whether a clipped 3D mortar polygon that is already a triangle should still be subdivided "
     141             :       "during triangulation. When enabled, already-triangular polygons are subdivided with the "
     142             :       "centroid-based path because the vertex-fan, ear-clipping, and Delaunay backends cannot "
     143             :       "refine a triangle any further on their own.");
     144             : 
     145      115878 :   return params;
     146       57939 : }
     147             : 
     148             : // Standard constructor
     149        1414 : MortarConsumerInterface::MortarConsumerInterface(const MooseObject * moose_object)
     150        5656 :   : _mci_fe_problem(*moose_object->getCheckedPointerParam<FEProblemBase *>("_fe_problem_base")),
     151        5656 :     _mci_subproblem(*moose_object->getCheckedPointerParam<SubProblem *>("_subproblem")),
     152        2828 :     _mci_tid(moose_object->getParam<THREAD_ID>("_tid")),
     153        1414 :     _mci_mesh(_mci_subproblem.mesh()),
     154             :     // all geometric assembly information should be correct for nl system number 0
     155        1414 :     _mci_assembly(_mci_subproblem.assembly(_mci_tid, 0)),
     156        1414 :     _mortar_data(_mci_fe_problem.mortarData()),
     157        1414 :     _secondary_id(
     158        2828 :         _mci_mesh.getBoundaryID(moose_object->getParam<BoundaryName>("secondary_boundary"))),
     159        2828 :     _primary_id(_mci_mesh.getBoundaryID(moose_object->getParam<BoundaryName>("primary_boundary"))),
     160        1414 :     _secondary_subdomain_id(
     161        2828 :         _mci_mesh.getSubdomainID(moose_object->getParam<SubdomainName>("secondary_subdomain"))),
     162        1414 :     _primary_subdomain_id(
     163        2828 :         _mci_mesh.getSubdomainID(moose_object->getParam<SubdomainName>("primary_subdomain"))),
     164        2828 :     _secondary_set({_secondary_id}),
     165        2828 :     _interpolate_normals(moose_object->getParam<bool>("interpolate_normals")),
     166        1414 :     _phys_points_secondary(_mci_assembly.qPointsFace()),
     167        1414 :     _phys_points_primary(_mci_assembly.qPointsFaceNeighbor()),
     168        1414 :     _qrule_msm(_mci_assembly.qRuleMortar()),
     169        1414 :     _qrule_face(_mci_assembly.qRuleFace()),
     170        1414 :     _lower_secondary_elem(_mci_assembly.lowerDElem()),
     171        1414 :     _lower_primary_elem(_mci_assembly.neighborLowerDElem()),
     172        1414 :     _JxW_msm(_mci_assembly.jxWMortar()),
     173        2828 :     _msm_elem(_mci_assembly.msmElem())
     174             : {
     175        2828 :   const bool displaced = moose_object->isParamValid("use_displaced_mesh")
     176        5656 :                              ? moose_object->getParam<bool>("use_displaced_mesh")
     177        1414 :                              : false;
     178             : 
     179             :   // Create the mortar interface if it hasn't already been created
     180        2828 :   _mci_fe_problem.createMortarInterface(
     181        1414 :       std::make_pair(_primary_id, _secondary_id),
     182           0 :       std::make_pair(_primary_subdomain_id, _secondary_subdomain_id),
     183             :       displaced,
     184        2828 :       moose_object->getParam<bool>("periodic"),
     185        2828 :       moose_object->getParam<bool>("debug_mesh"),
     186        2828 :       moose_object->getParam<bool>("correct_edge_dropping"),
     187        5656 :       moose_object->getParam<Real>("minimum_projection_angle"),
     188             :       moose_object->getParam<MooseEnum>("triangulation"),
     189        4242 :       moose_object->getParam<bool>("triangulate_triangles"));
     190             : 
     191        1414 :   _amg = &_mci_fe_problem.getMortarInterface(
     192        1414 :       std::make_pair(_primary_id, _secondary_id),
     193        1414 :       std::make_pair(_primary_subdomain_id, _secondary_subdomain_id),
     194             :       displaced);
     195             : 
     196        1414 :   const auto & secondary_set = _mortar_data.getHigherDimSubdomainIDs(_secondary_subdomain_id);
     197        1414 :   const auto & primary_set = _mortar_data.getHigherDimSubdomainIDs(_primary_subdomain_id);
     198             : 
     199        2828 :   std::set_union(secondary_set.begin(),
     200             :                  secondary_set.end(),
     201             :                  primary_set.begin(),
     202             :                  primary_set.end(),
     203        1414 :                  std::inserter(_higher_dim_subdomain_ids, _higher_dim_subdomain_ids.begin()));
     204        1414 :   _boundary_ids = {_secondary_id, _primary_id};
     205        1414 : }
     206             : 
     207             : void
     208      492178 : MortarConsumerInterface::setNormals()
     209             : {
     210      492178 :   if (interpolateNormals())
     211      490982 :     _normals = amg().getNormals(*_lower_secondary_elem, _qrule_face->get_points());
     212             :   else
     213        1196 :     _normals = amg().getNodalNormals(*_lower_secondary_elem);
     214      492178 : }
     215             : 
     216             : void
     217      196448 : MortarConsumerInterface::trimDerivative(const dof_id_type remove_derivative_index,
     218             :                                         ADReal & dual_number)
     219             : {
     220      196448 :   auto md_it = dual_number.derivatives().nude_data().begin();
     221      196448 :   auto mi_it = dual_number.derivatives().nude_indices().begin();
     222             : 
     223      196448 :   auto d_it = dual_number.derivatives().nude_data().begin();
     224             : 
     225      196448 :   for (auto i_it = dual_number.derivatives().nude_indices().begin();
     226      554252 :        i_it != dual_number.derivatives().nude_indices().end();
     227      357804 :        ++i_it, ++d_it)
     228      357804 :     if (*i_it != remove_derivative_index)
     229             :     {
     230      333806 :       *mi_it = *i_it;
     231      333806 :       *md_it = *d_it;
     232      333806 :       ++mi_it;
     233      333806 :       ++md_it;
     234             :     }
     235             : 
     236      196448 :   std::size_t n_indices = md_it - dual_number.derivatives().nude_data().begin();
     237      196448 :   dual_number.derivatives().nude_indices().resize(n_indices);
     238      196448 :   dual_number.derivatives().nude_data().resize(n_indices);
     239      196448 : }

Generated by: LCOV version 1.14