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

Generated by: LCOV version 1.14