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 1914 : WeightedGapUserObject::validParams() 24 : { 25 1914 : InputParameters params = MortarUserObject::validParams(); 26 1914 : params += MortarConsumerInterface::validParams(); 27 1914 : params += TwoMaterialPropertyInterface::validParams(); 28 3828 : params.addRequiredCoupledVar("disp_x", "The x displacement variable"); 29 3828 : params.addRequiredCoupledVar("disp_y", "The y displacement variable"); 30 3828 : params.addCoupledVar("disp_z", "The z displacement variable"); 31 1914 : params.set<bool>("use_displaced_mesh") = true; 32 1914 : params.set<bool>("interpolate_normals") = false; 33 7656 : params.set<ExecFlagEnum>("execute_on") = {EXEC_LINEAR, EXEC_NONLINEAR}; 34 1914 : params.suppressParameter<ExecFlagEnum>("execute_on"); 35 1914 : return params; 36 1914 : } 37 : 38 840 : WeightedGapUserObject::WeightedGapUserObject(const InputParameters & parameters) 39 : : MortarUserObject(parameters), 40 1680 : _fe_problem(*getCheckedPointerParam<FEProblemBase *>("_fe_problem_base")), 41 840 : _nodal(getVar("disp_x", 0)->feType().family == LAGRANGE), 42 840 : _disp_x_var(getVar("disp_x", 0)), 43 840 : _disp_y_var(getVar("disp_y", 0)), 44 840 : _has_disp_z(isCoupled("disp_z")), 45 840 : _disp_z_var(_has_disp_z ? getVar("disp_z", 0) : nullptr), 46 840 : _secondary_disp_x(_disp_x_var->adSln()), 47 840 : _primary_disp_x(_disp_x_var->adSlnNeighbor()), 48 840 : _secondary_disp_y(_disp_y_var->adSln()), 49 840 : _primary_disp_y(_disp_y_var->adSlnNeighbor()), 50 840 : _secondary_disp_z(_has_disp_z ? &_disp_z_var->adSln() : nullptr), 51 840 : _primary_disp_z(_has_disp_z ? &_disp_z_var->adSlnNeighbor() : nullptr), 52 1680 : _coord(_assembly.mortarCoordTransformation()) 53 : { 54 1680 : if (!getParam<bool>("use_displaced_mesh")) 55 0 : paramError("use_displaced_mesh", 56 : "'use_displaced_mesh' must be true for the WeightedGapUserObject object"); 57 840 : } 58 : 59 : void 60 822 : WeightedGapUserObject::initialSetup() 61 : { 62 822 : MortarUserObject::initialSetup(); 63 822 : _test = &test(); 64 822 : } 65 : 66 : void 67 9212726 : WeightedGapUserObject::computeQpProperties() 68 : { 69 : // Trim interior node variable derivatives 70 : const auto & primary_ip_lowerd_map = amg().getPrimaryIpToLowerElementMap( 71 9212726 : *_lower_primary_elem, *_lower_primary_elem->interior_parent(), *_lower_secondary_elem); 72 : const auto & secondary_ip_lowerd_map = 73 9212726 : amg().getSecondaryIpToLowerElementMap(*_lower_secondary_elem); 74 : 75 9212726 : std::array<const MooseVariable *, 3> var_array{{_disp_x_var, _disp_y_var, _disp_z_var}}; 76 : std::array<ADReal, 3> primary_disp{ 77 9212726 : {_primary_disp_x[_qp], _primary_disp_y[_qp], _has_disp_z ? (*_primary_disp_z)[_qp] : 0}}; 78 9212726 : std::array<ADReal, 3> secondary_disp{{_secondary_disp_x[_qp], 79 9212726 : _secondary_disp_y[_qp], 80 9212726 : _has_disp_z ? (*_secondary_disp_z)[_qp] : 0}}; 81 : 82 9212726 : trimInteriorNodeDerivatives(primary_ip_lowerd_map, var_array, primary_disp, false); 83 9212726 : 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 9212726 : 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 9212726 : if (_has_disp_z) 95 : sec_z = &secondary_disp[2]; 96 : 97 : // Compute gap vector 98 9212726 : ADRealVectorValue gap_vec = _phys_points_primary[_qp] - _phys_points_secondary[_qp]; 99 : 100 : // Generic displacement for interface problems 101 9212726 : _qp_displacement_nodal(0) = prim_x - sec_x; 102 9212726 : _qp_displacement_nodal(1) = prim_y - sec_y; 103 9212726 : if (_has_disp_z) 104 8109504 : _qp_displacement_nodal(2) = *prim_z - *sec_z; 105 : 106 9212726 : _qp_displacement_nodal *= _JxW_msm[_qp] * _coord[_qp]; 107 : 108 9212726 : gap_vec(0).derivatives() = prim_x.derivatives() - sec_x.derivatives(); 109 9212726 : gap_vec(1).derivatives() = prim_y.derivatives() - sec_y.derivatives(); 110 9212726 : if (_has_disp_z) 111 8109504 : 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 9212726 : _qp_gap_nodal = gap_vec * (_JxW_msm[_qp] * _coord[_qp]); 116 : 117 : // To do normalization of constraint coefficient (c_n) 118 9212726 : _qp_factor = _JxW_msm[_qp] * _coord[_qp]; 119 9212726 : } 120 : 121 : void 122 34644460 : 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 34644460 : 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 34644460 : weighted_gap += (*_test)[_i][_qp] * _qp_gap_nodal * _normals[_i]; 133 34644460 : normalization += (*_test)[_i][_qp] * _qp_factor; 134 : 135 69288920 : _dof_to_weighted_displacements[dof] += (*_test)[_i][_qp] * _qp_displacement_nodal; 136 34644460 : } 137 : 138 : void 139 121566 : WeightedGapUserObject::initialize() 140 : { 141 : _dof_to_weighted_gap.clear(); 142 : _dof_to_weighted_displacements.clear(); 143 121566 : } 144 : 145 : void 146 121566 : 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 121566 : const bool send_data_back = !constrainedByOwner(); 152 121566 : Moose::Mortar::Contact::communicateGaps(_dof_to_weighted_gap, 153 121566 : _subproblem.mesh(), 154 121566 : _nodal, 155 : /*normalize_c*/ true, 156 : _communicator, 157 : send_data_back); 158 121566 : } 159 : 160 : void 161 2494147 : WeightedGapUserObject::execute() 162 : { 163 11706873 : for (_qp = 0; _qp < _qrule_msm->n_points(); _qp++) 164 : { 165 9212726 : computeQpProperties(); 166 43857186 : for (_i = 0; _i < _test->size(); ++_i) 167 34644460 : computeQpIProperties(); 168 : } 169 2494147 : } 170 : 171 : Real 172 142572 : WeightedGapUserObject::getNormalGap(const Node * const node) const 173 : { 174 142572 : 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 142572 : if (it != _dof_to_weighted_gap.end()) 178 17561 : return physicalGap(it->second); 179 : else 180 : return 0.0; 181 : }