LCOV - code coverage report
Current view: top level - src/userobjects - WeightedGapUserObject.C (source / functions) Hit Total Coverage
Test: idaholab/moose contact: #32971 (54bef8) with base c6cf66 Lines: 82 83 98.8 %
Date: 2026-05-29 20:36:03 Functions: 9 9 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 "WeightedGapUserObject.h"
      11             : #include "MooseVariableField.h"
      12             : #include "SubProblem.h"
      13             : #include "MortarUtils.h"
      14             : #include "MooseUtils.h"
      15             : #include "MortarContactUtils.h"
      16             : #include "AutomaticMortarGeneration.h"
      17             : 
      18             : #include "libmesh/quadrature.h"
      19             : 
      20             : #include <limits>
      21             : 
      22             : InputParameters
      23        1782 : WeightedGapUserObject::validParams()
      24             : {
      25        1782 :   InputParameters params = MortarUserObject::validParams();
      26        1782 :   params += MortarConsumerInterface::validParams();
      27        1782 :   params += TwoMaterialPropertyInterface::validParams();
      28        3564 :   params.addRequiredCoupledVar("disp_x", "The x displacement variable");
      29        3564 :   params.addRequiredCoupledVar("disp_y", "The y displacement variable");
      30        3564 :   params.addCoupledVar("disp_z", "The z displacement variable");
      31        1782 :   params.set<bool>("use_displaced_mesh") = true;
      32        1782 :   params.set<bool>("interpolate_normals") = false;
      33        7128 :   params.set<ExecFlagEnum>("execute_on") = {EXEC_LINEAR, EXEC_NONLINEAR};
      34        1782 :   params.suppressParameter<ExecFlagEnum>("execute_on");
      35        1782 :   return params;
      36        1782 : }
      37             : 
      38         774 : WeightedGapUserObject::WeightedGapUserObject(const InputParameters & parameters)
      39             :   : MortarUserObject(parameters),
      40        1548 :     _fe_problem(*getCheckedPointerParam<FEProblemBase *>("_fe_problem_base")),
      41         774 :     _nodal(getVar("disp_x", 0)->feType().family == LAGRANGE),
      42         774 :     _disp_x_var(getVar("disp_x", 0)),
      43         774 :     _disp_y_var(getVar("disp_y", 0)),
      44         774 :     _has_disp_z(isCoupled("disp_z")),
      45         774 :     _disp_z_var(_has_disp_z ? getVar("disp_z", 0) : nullptr),
      46         774 :     _secondary_disp_x(_disp_x_var->adSln()),
      47         774 :     _primary_disp_x(_disp_x_var->adSlnNeighbor()),
      48         774 :     _secondary_disp_y(_disp_y_var->adSln()),
      49         774 :     _primary_disp_y(_disp_y_var->adSlnNeighbor()),
      50         774 :     _secondary_disp_z(_has_disp_z ? &_disp_z_var->adSln() : nullptr),
      51         774 :     _primary_disp_z(_has_disp_z ? &_disp_z_var->adSlnNeighbor() : nullptr),
      52        1548 :     _coord(_assembly.mortarCoordTransformation())
      53             : {
      54        1548 :   if (!getParam<bool>("use_displaced_mesh"))
      55           0 :     paramError("use_displaced_mesh",
      56             :                "'use_displaced_mesh' must be true for the WeightedGapUserObject object");
      57         774 : }
      58             : 
      59             : void
      60         764 : WeightedGapUserObject::initialSetup()
      61             : {
      62         764 :   MortarUserObject::initialSetup();
      63         764 :   _test = &test();
      64         764 : }
      65             : 
      66             : void
      67     8239845 : WeightedGapUserObject::computeQpProperties()
      68             : {
      69             :   // Trim interior node variable derivatives
      70             :   const auto & primary_ip_lowerd_map = amg().getPrimaryIpToLowerElementMap(
      71     8239845 :       *_lower_primary_elem, *_lower_primary_elem->interior_parent(), *_lower_secondary_elem);
      72             :   const auto & secondary_ip_lowerd_map =
      73     8239845 :       amg().getSecondaryIpToLowerElementMap(*_lower_secondary_elem);
      74             : 
      75     8239845 :   std::array<const MooseVariable *, 3> var_array{{_disp_x_var, _disp_y_var, _disp_z_var}};
      76             :   std::array<ADReal, 3> primary_disp{
      77     8239845 :       {_primary_disp_x[_qp], _primary_disp_y[_qp], _has_disp_z ? (*_primary_disp_z)[_qp] : 0}};
      78     8239845 :   std::array<ADReal, 3> secondary_disp{{_secondary_disp_x[_qp],
      79     8239845 :                                         _secondary_disp_y[_qp],
      80     8239845 :                                         _has_disp_z ? (*_secondary_disp_z)[_qp] : 0}};
      81             : 
      82     8239845 :   trimInteriorNodeDerivatives(primary_ip_lowerd_map, var_array, primary_disp, false);
      83     8239845 :   trimInteriorNodeDerivatives(secondary_ip_lowerd_map, var_array, secondary_disp, true);
      84             : 
      85             :   const ADReal & prim_x = primary_disp[0];
      86             :   const ADReal & prim_y = primary_disp[1];
      87             :   const ADReal * prim_z = nullptr;
      88     8239845 :   if (_has_disp_z)
      89             :     prim_z = &primary_disp[2];
      90             : 
      91             :   const ADReal & sec_x = secondary_disp[0];
      92             :   const ADReal & sec_y = secondary_disp[1];
      93             :   const ADReal * sec_z = nullptr;
      94     8239845 :   if (_has_disp_z)
      95             :     sec_z = &secondary_disp[2];
      96             : 
      97             :   // Compute gap vector
      98     8239845 :   ADRealVectorValue gap_vec = _phys_points_primary[_qp] - _phys_points_secondary[_qp];
      99             : 
     100             :   // Generic displacement for interface problems
     101     8239845 :   _qp_displacement_nodal(0) = prim_x - sec_x;
     102     8239845 :   _qp_displacement_nodal(1) = prim_y - sec_y;
     103     8239845 :   if (_has_disp_z)
     104     7134272 :     _qp_displacement_nodal(2) = *prim_z - *sec_z;
     105             : 
     106     8239845 :   _qp_displacement_nodal *= _JxW_msm[_qp] * _coord[_qp];
     107             : 
     108     8239845 :   gap_vec(0).derivatives() = prim_x.derivatives() - sec_x.derivatives();
     109     8239845 :   gap_vec(1).derivatives() = prim_y.derivatives() - sec_y.derivatives();
     110     8239845 :   if (_has_disp_z)
     111     7134272 :     gap_vec(2).derivatives() = prim_z->derivatives() - sec_z->derivatives();
     112             : 
     113             :   // Compute integration point quantities: Normals (geometry) is averaged at the node, but not
     114             :   // interpolated within the weak integration.
     115     8239845 :   _qp_gap_nodal = gap_vec * (_JxW_msm[_qp] * _coord[_qp]);
     116             : 
     117             :   // To do normalization of constraint coefficient (c_n)
     118     8239845 :   _qp_factor = _JxW_msm[_qp] * _coord[_qp];
     119     8239845 : }
     120             : 
     121             : void
     122    30748234 : WeightedGapUserObject::computeQpIProperties()
     123             : {
     124             :   mooseAssert(_normals.size() == _lower_secondary_elem->n_nodes(),
     125             :               "Making sure that _normals is the expected size");
     126             : 
     127             :   // Get the _dof_to_weighted_gap map
     128    30748234 :   const auto * const dof = static_cast<const DofObject *>(_lower_secondary_elem->node_ptr(_i));
     129             : 
     130             :   auto & [weighted_gap, normalization] = _dof_to_weighted_gap[dof];
     131             : 
     132    30748234 :   weighted_gap += (*_test)[_i][_qp] * _qp_gap_nodal * _normals[_i];
     133    30748234 :   normalization += (*_test)[_i][_qp] * _qp_factor;
     134             : 
     135    61496468 :   _dof_to_weighted_displacements[dof] += (*_test)[_i][_qp] * _qp_displacement_nodal;
     136    30748234 : }
     137             : 
     138             : void
     139      119631 : WeightedGapUserObject::initialize()
     140             : {
     141             :   _dof_to_weighted_gap.clear();
     142             :   _dof_to_weighted_displacements.clear();
     143      119631 : }
     144             : 
     145             : void
     146      119631 : WeightedGapUserObject::finalize()
     147             : {
     148             :   // If the constraint is performed by the owner, then we don't need any data sent back; the owner
     149             :   // will take care of it. But if the constraint is not performed by the owner and we might have to
     150             :   // do some of the constraining ourselves, then we need data sent back to us
     151      119631 :   const bool send_data_back = !constrainedByOwner();
     152      119631 :   Moose::Mortar::Contact::communicateGaps(_dof_to_weighted_gap,
     153      119631 :                                           _subproblem.mesh(),
     154      119631 :                                           _nodal,
     155             :                                           /*normalize_c*/ true,
     156             :                                           _communicator,
     157             :                                           send_data_back);
     158      119631 : }
     159             : 
     160             : void
     161     2242932 : WeightedGapUserObject::execute()
     162             : {
     163    10482777 :   for (_qp = 0; _qp < _qrule_msm->n_points(); _qp++)
     164             :   {
     165     8239845 :     computeQpProperties();
     166    38988079 :     for (_i = 0; _i < _test->size(); ++_i)
     167    30748234 :       computeQpIProperties();
     168             :   }
     169     2242932 : }
     170             : 
     171             : Real
     172      142332 : WeightedGapUserObject::getNormalGap(const Node * const node) const
     173             : {
     174      142332 :   const auto it = _dof_to_weighted_gap.find(_subproblem.mesh().nodePtr(node->id()));
     175             : 
     176             :   // We are returning the physical weighted gap for analysis purposes
     177      142332 :   if (it != _dof_to_weighted_gap.end())
     178       17321 :     return physicalGap(it->second);
     179             :   else
     180             :     return 0.0;
     181             : }

Generated by: LCOV version 1.14