LCOV - code coverage report
Current view: top level - src/constraints - ADMortarLagrangeConstraint.C (source / functions) Hit Total Coverage
Test: idaholab/moose contact: #31405 (292dce) with base fef103 Lines: 85 86 98.8 %
Date: 2025-09-04 07:52:48 Functions: 5 5 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             : #include "ADMortarLagrangeConstraint.h"
      11             : 
      12             : // MOOSE includes
      13             : #include "MooseVariable.h"
      14             : #include "MoosePreconditioner.h"
      15             : #include "VariableCondensationPreconditioner.h"
      16             : #include "NonlinearSystemBase.h"
      17             : #include "Assembly.h"
      18             : #include "SystemBase.h"
      19             : #include "ADUtils.h"
      20             : #include "FEProblemBase.h"
      21             : #include "AutomaticMortarGeneration.h"
      22             : 
      23             : #include <algorithm>
      24             : #include <vector>
      25             : 
      26             : InputParameters
      27        7878 : ADMortarLagrangeConstraint::validParams()
      28             : {
      29        7878 :   InputParameters params = ADMortarConstraint::validParams();
      30       15756 :   params.addParam<Real>(
      31             :       "derivative_threshold",
      32       15756 :       1.0e-17,
      33             :       "Threshold to discard automatic differentiation derivatives. This number is chosen on the "
      34             :       "order of the machine epsilon based on current experience.");
      35             : 
      36        7878 :   return params;
      37           0 : }
      38             : 
      39        4345 : ADMortarLagrangeConstraint::ADMortarLagrangeConstraint(const InputParameters & parameters)
      40             :   : ADMortarConstraint(parameters),
      41        8690 :     _ad_derivative_threshold(getParam<Real>("derivative_threshold")),
      42        4345 :     _apply_derivative_threshold(true)
      43             : {
      44        4345 : }
      45             : 
      46             : void
      47        4299 : ADMortarLagrangeConstraint::initialSetup()
      48             : {
      49        4299 :   SetupInterface::initialSetup();
      50             : 
      51             :   // Detect if preconditioner is VCP. If so, disable automatic derivative trimming.
      52        4299 :   auto const * mpc = feProblem().getNonlinearSystemBase(_sys.number()).getPreconditioner();
      53             : 
      54        4299 :   if (dynamic_cast<const VariableCondensationPreconditioner *>(mpc))
      55         134 :     _apply_derivative_threshold = false;
      56        4299 : }
      57             : 
      58             : void
      59    21252138 : ADMortarLagrangeConstraint::computeResidual(Moose::MortarType mortar_type)
      60             : {
      61    21252138 :   _primary_ip_lowerd_map = amg().getPrimaryIpToLowerElementMap(
      62    21252138 :       *_lower_primary_elem, *_lower_primary_elem->interior_parent(), *_lower_secondary_elem);
      63             : 
      64    21252138 :   _secondary_ip_lowerd_map = amg().getSecondaryIpToLowerElementMap(*_lower_secondary_elem);
      65             : 
      66             :   unsigned int test_space_size = 0;
      67    21252138 :   switch (mortar_type)
      68             :   {
      69    10622049 :     case Moose::MortarType::Secondary:
      70    10622049 :       prepareVectorTag(_assembly, _secondary_var.number());
      71    10622049 :       test_space_size = _test_secondary.size();
      72    10622049 :       break;
      73             : 
      74    10622049 :     case Moose::MortarType::Primary:
      75    10622049 :       prepareVectorTagNeighbor(_assembly, _primary_var.number());
      76    10622049 :       test_space_size = _test_primary.size();
      77    10622049 :       break;
      78             : 
      79        8040 :     case Moose::MortarType::Lower:
      80             :       mooseAssert(_var, "LM variable is null");
      81        8040 :       prepareVectorTagLower(_assembly, _var->number());
      82        8040 :       test_space_size = _test.size();
      83        8040 :       break;
      84             :   }
      85             : 
      86    21252138 :   std::vector<unsigned int> is_index_on_lower_dimension;
      87             :   // Find out if nodes are on the surface
      88   174204186 :   for (_i = 0; _i < test_space_size; _i++)
      89             :   {
      90   152952048 :     if (mortar_type == Moose::MortarType::Primary && !_primary_ip_lowerd_map.count(_i))
      91    38277336 :       continue;
      92             : 
      93   114674712 :     if (mortar_type == Moose::MortarType::Secondary && !_secondary_ip_lowerd_map.count(_i))
      94    38277336 :       continue;
      95             : 
      96    76397376 :     is_index_on_lower_dimension.push_back(_i);
      97             :   }
      98             : 
      99    97649514 :   for (_qp = 0; _qp < _qrule_msm->n_points(); _qp++)
     100   364706736 :     for (const auto index : is_index_on_lower_dimension)
     101             :     {
     102   288309360 :       _i = index;
     103   576618720 :       _local_re(_i) += raw_value(_JxW_msm[_qp] * _coord[_qp] * computeQpResidual(mortar_type));
     104             :     }
     105             : 
     106    21252138 :   accumulateTaggedLocalResidual();
     107    21252138 : }
     108             : 
     109             : void
     110     6748142 : ADMortarLagrangeConstraint::computeJacobian(Moose::MortarType mortar_type)
     111             : {
     112             :   std::vector<ADReal> residuals;
     113             :   size_t test_space_size = 0;
     114             :   typedef Moose::ConstraintJacobianType JType;
     115             :   typedef Moose::MortarType MType;
     116             :   std::vector<JType> jacobian_types;
     117             :   std::vector<dof_id_type> dof_indices;
     118             :   Real scaling_factor = 1;
     119             : 
     120     6748142 :   _primary_ip_lowerd_map = amg().getPrimaryIpToLowerElementMap(
     121     6748142 :       *_lower_primary_elem, *_lower_primary_elem->interior_parent(), *_lower_secondary_elem);
     122             : 
     123     6748142 :   _secondary_ip_lowerd_map = amg().getSecondaryIpToLowerElementMap(*_lower_secondary_elem);
     124             : 
     125     6748142 :   switch (mortar_type)
     126             :   {
     127     3370801 :     case MType::Secondary:
     128     3370801 :       dof_indices = _secondary_var.dofIndices();
     129     3370801 :       jacobian_types = {JType::SecondarySecondary, JType::SecondaryPrimary, JType::SecondaryLower};
     130     3370801 :       scaling_factor = _secondary_var.scalingFactor();
     131     3370801 :       break;
     132             : 
     133     3370801 :     case MType::Primary:
     134     3370801 :       dof_indices = _primary_var.dofIndicesNeighbor();
     135     3370801 :       jacobian_types = {JType::PrimarySecondary, JType::PrimaryPrimary, JType::PrimaryLower};
     136     3370801 :       scaling_factor = _primary_var.scalingFactor();
     137     3370801 :       break;
     138             : 
     139        6540 :     case MType::Lower:
     140             :       mooseAssert(_var, "This should be non-null");
     141        6540 :       dof_indices = _var->dofIndicesLower();
     142        6540 :       jacobian_types = {JType::LowerSecondary, JType::LowerPrimary, JType::LowerLower};
     143        6540 :       scaling_factor = _var->scalingFactor();
     144        6540 :       break;
     145             :   }
     146             :   test_space_size = dof_indices.size();
     147             : 
     148     6748142 :   residuals.resize(test_space_size, 0);
     149             : 
     150     6748142 :   std::vector<unsigned int> is_index_on_lower_dimension;
     151     6748142 :   std::vector<dof_id_type> dof_indices_lower;
     152             : 
     153             :   // Find out if nodes are on the surface
     154             :   unsigned int number_indices_on_lowerd = 0;
     155             : 
     156    54335474 :   for (_i = 0; _i < test_space_size; _i++)
     157             :   {
     158    47587332 :     if (mortar_type == Moose::MortarType::Primary && !_primary_ip_lowerd_map.count(_i))
     159    11903676 :       continue;
     160             : 
     161    35683656 :     if (mortar_type == Moose::MortarType::Secondary && !_secondary_ip_lowerd_map.count(_i))
     162    11903676 :       continue;
     163             : 
     164    23779980 :     is_index_on_lower_dimension.push_back(_i);
     165    23779980 :     dof_indices_lower.push_back(dof_indices[_i]);
     166    23779980 :     number_indices_on_lowerd++;
     167             :   }
     168             : 
     169     6748142 :   std::vector<ADReal> residuals_lower;
     170     6748142 :   residuals_lower.resize(number_indices_on_lowerd, 0);
     171             : 
     172             :   // Only populate nodal residuals on the primary/secondary surfaces
     173             :   // We do this regardless of whether we are interpolating normals. Use of this class
     174             :   // implies we have Lagrange elements, so internal (high-dimensional) normals have no meaning
     175             :   // and should be zero. As such, we decide to omit them and avoid possible spurious population of
     176             :   // automatic differentiation-generated derivatives.
     177    30528122 :   for (_qp = 0; _qp < _qrule_msm->n_points(); _qp++)
     178             :   {
     179             :     unsigned int index_lower = 0;
     180   112461240 :     for (const auto index : is_index_on_lower_dimension)
     181             :     {
     182    88681260 :       _i = index;
     183   177362520 :       residuals_lower[index_lower] += _JxW_msm[_qp] * _coord[_qp] * computeQpResidual(mortar_type);
     184             : 
     185             :       // Get rid of derivatives that we assume won't count (tolerance prescribed by user)
     186             :       // This can cause zero diagonal terms with the variable condensation preconditioner when the
     187             :       // no adaptivity option is used (dofs are not checked).
     188             :       // Uncomment when https://github.com/libMesh/MetaPhysicL/pull/18 makes it to MOOSE
     189             : 
     190    88681260 :       index_lower++;
     191             :     }
     192             :   }
     193             : 
     194     6748142 :   addJacobian(_assembly, residuals_lower, dof_indices_lower, scaling_factor);
     195     6748142 : }

Generated by: LCOV version 1.14