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 : #pragma once 11 : 12 : #include "MooseTypes.h" 13 : 14 : #include <set> 15 : 16 : class InputParameters; 17 : class MooseObject; 18 : class MooseMesh; 19 : class MortarInterfaceWarehouse; 20 : class AutomaticMortarGeneration; 21 : class SubProblem; 22 : class Assembly; 23 : 24 : namespace libMesh 25 : { 26 : class QBase; 27 : } 28 : 29 : /** 30 : * An interface for accessing mortar mesh data 31 : * 32 : * \note mci is shorthand for mortar consumer interface, so \p _mci_problem indicates 33 : * the mortar consumer interface's problem 34 : */ 35 : class MortarConsumerInterface 36 : { 37 : public: 38 : MortarConsumerInterface(const MooseObject * moose_object); 39 : 40 : static InputParameters validParams(); 41 : 42 : /** 43 : * @return An InputParameters object containing just the parameters that control 3D mortar 44 : * polygon triangulation (\p triangulation, \p triangulate_triangles). Provided so that 45 : * downstream actions / objects which need to expose the same controls (e.g. ContactAction) 46 : * can pull these definitions in via \p params += rather than duplicating them. 47 : */ 48 : static InputParameters triangulationParams(); 49 : 50 : /** 51 : * @return The primary lower dimensional subdomain id 52 : */ 53 500 : SubdomainID primarySubdomain() const { return _primary_subdomain_id; } 54 : 55 : /** 56 : * @return The secondary lower dimensional subdomain id 57 : */ 58 500 : SubdomainID secondarySubdomain() const { return _secondary_subdomain_id; } 59 : 60 : /** 61 : * @return Whether this object lies on the given primary-secondary boundary pair 62 : */ 63 : bool onInterface(BoundaryID primary_boundary_id, BoundaryID secondary_boundary_id) const; 64 : 65 : protected: 66 : const std::set<SubdomainID> & getHigherDimSubdomainIDs() const 67 : { 68 : return _higher_dim_subdomain_ids; 69 : } 70 1312 : const std::set<BoundaryID> & getBoundaryIDs() const { return _boundary_ids; } 71 : 72 : /** 73 : * Retrieve the automatic mortar generation object associated with this constraint 74 : */ 75 : const AutomaticMortarGeneration & amg() const; 76 : 77 : /** 78 : * Whether to interpolate the nodal normals (e.g. classic idea of evaluating field at quadrature 79 : * points). If this is set to false, then non-interpolated nodal normals will be used, and then 80 : * the _normals member should be indexed with _i instead of _qp 81 : */ 82 492178 : bool interpolateNormals() const { return _interpolate_normals; } 83 : 84 : /** 85 : * Get rid of AD derivative entries by dof index 86 : */ 87 : static void trimDerivative(dof_id_type remove_derivative_index, ADReal & dual_number); 88 : 89 : /** 90 : * Get rid of interior node variable's derivatives 91 : */ 92 : template <typename Variables, typename DualNumbers> 93 : static void 94 : trimInteriorNodeDerivatives(const std::map<unsigned int, unsigned int> & primary_ip_lowerd_map, 95 : const Variables & moose_var, 96 : DualNumbers & ad_vars, 97 : const bool is_secondary); 98 : 99 : FEProblemBase & _mci_fe_problem; 100 : SubProblem & _mci_subproblem; 101 : const THREAD_ID _mci_tid; 102 : 103 : /// Mesh to query for boundary and subdomain ID information 104 : MooseMesh & _mci_mesh; 105 : 106 : Assembly & _mci_assembly; 107 : 108 : /// A reference to the mortar data object that holds all the mortar 109 : /// mesh information 110 : const MortarInterfaceWarehouse & _mortar_data; 111 : 112 : /// Boundary ID for the secondary surface 113 : const BoundaryID _secondary_id; 114 : 115 : /// Boundary ID for the primary surface 116 : const BoundaryID _primary_id; 117 : 118 : /// Subdomain ID for the secondary surface 119 : const SubdomainID _secondary_subdomain_id; 120 : 121 : /// Subdomain ID for the primary surface 122 : const SubdomainID _primary_subdomain_id; 123 : 124 : /// the secondaryid set 125 : std::set<BoundaryID> _secondary_set; 126 : 127 : /// the union of the secondary and primary boundary ids 128 : std::set<BoundaryID> _boundary_ids; 129 : 130 : /// the higher dimensional subdomain ids corresponding to the interior parents 131 : std::set<SubdomainID> _higher_dim_subdomain_ids; 132 : 133 : /// Whether to interpolate the nodal normals 134 : const bool _interpolate_normals; 135 : 136 : /// The locations of the quadrature points on the interior secondary elements 137 : const MooseArray<Point> & _phys_points_secondary; 138 : 139 : /// The locations of the quadrature points on the interior primary elements 140 : const MooseArray<Point> & _phys_points_primary; 141 : 142 : /// The quadrature rule on the mortar segment element 143 : const libMesh::QBase * const & _qrule_msm; 144 : 145 : /// The arbitrary quadrature rule on the lower dimensional secondary face 146 : const libMesh::QBase * const & _qrule_face; 147 : 148 : /// The secondary face lower dimensional element (not the mortar element!). The mortar element 149 : /// lives on the secondary side of the mortar interface and *may* correspond to \p 150 : /// _lower_secondary_elem under the very specific circumstance that the nodes on the primary side 151 : /// of the mortar interface exactly project onto the secondary side of the mortar interface. In 152 : /// general projection of primary nodes will split the face elements on the secondary side of the 153 : /// interface. It is these split elements that are the mortar segment mesh elements 154 : Elem const * const & _lower_secondary_elem; 155 : 156 : /// The primary face lower dimensional element (not the mortar element!). The mortar element 157 : /// lives on the secondary side of the mortar interface and *may* correspond to \p 158 : /// _lower_secondary_elem under the very specific circumstance that the nodes on the primary side 159 : /// of the mortar interface exactly project onto the secondary side of the mortar interface. In 160 : /// general projection of primary nodes will split the face elements on the secondary side of the 161 : /// interface. It is these split elements that are the mortar segment mesh elements 162 : Elem const * const & _lower_primary_elem; 163 : 164 : /// The element Jacobian times weights 165 : const std::vector<Real> & _JxW_msm; 166 : 167 : /// The current mortar segment element 168 : const Elem * const & _msm_elem; 169 : 170 : /// the normals 171 : std::vector<Point> _normals; 172 : 173 : private: 174 : /** 175 : * Set the normals vector 176 : */ 177 : void setNormals(); 178 : 179 : // Pointer to automatic mortar generation object to give constraints access to mortar geometry 180 : const AutomaticMortarGeneration * _amg; 181 : 182 : friend class ComputeMortarFunctor; 183 : friend class FEProblemBase; 184 : 185 : template <typename> 186 : friend class MortarNodalAuxKernelTempl; 187 : friend class MortarUserObjectThread; 188 : 189 : /** 190 : * Calls the reinitialization of mortar user objects 191 : * @see FEProblemBase::reinitMortarUserObjects 192 : */ 193 : friend void reinitMortarUserObjects(BoundaryID, BoundaryID, bool); 194 : }; 195 : 196 : inline const AutomaticMortarGeneration & 197 541698 : MortarConsumerInterface::amg() const 198 : { 199 : mooseAssert(_amg, "this should have been set in the constructor"); 200 541698 : return *_amg; 201 : } 202 : 203 : template <typename Variables, typename DualNumbers> 204 : void 205 39252 : MortarConsumerInterface::trimInteriorNodeDerivatives( 206 : const std::map<unsigned int, unsigned int> & domain_ip_lowerd_map, 207 : const Variables & moose_vars, 208 : DualNumbers & dual_numbers, 209 : const bool is_secondary) 210 : { 211 : // 212 : // Remove interior node variable's derivatives from AD objects. 213 : // 214 : 215 : mooseAssert(moose_vars.size(), "Should have passed at least one variable"); 216 39252 : const auto num_indices = is_secondary ? moose_vars[0]->dofIndices().size() 217 19626 : : moose_vars[0]->dofIndicesNeighbor().size(); 218 : #ifdef DEBUG 219 : for (const auto i : make_range(std::size_t(1), moose_vars.size())) 220 : if (auto * moose_var = moose_vars[i]) 221 : mooseAssert(is_secondary ? moose_var->dofIndices().size() 222 : : moose_var->dofIndicesNeighbor().size() == num_indices, 223 : "These must be the same for all passed in variables"); 224 : #endif 225 : 226 186198 : for (const auto dof_index : make_range(num_indices)) 227 146946 : if (!domain_ip_lowerd_map.count(dof_index)) 228 : { 229 205326 : for (const auto * const moose_var : moose_vars) 230 : { 231 : // It's valid for a user to pass a container that represents a LIBMESH_DIM vector of 232 : // component variables for which one or two of the variables may be null depending on the 233 : // mesh dimension in the simulation 234 136884 : if (!moose_var) 235 68442 : continue; 236 : 237 : mooseAssert(moose_var->isNodal(), 238 : "Trimming of interior node's derivatives is only supported for Lagrange " 239 : "elements in mortar objects"); 240 : 241 68442 : const auto remove_derivative_index = is_secondary 242 107694 : ? moose_var->dofIndices()[dof_index] 243 39252 : : moose_var->dofIndicesNeighbor()[dof_index]; 244 264890 : for (auto & dual_number : dual_numbers) 245 196448 : trimDerivative(remove_derivative_index, dual_number); 246 : } 247 : } 248 39252 : } 249 : 250 : inline bool 251 22 : MortarConsumerInterface::onInterface(const BoundaryID primary_boundary_id, 252 : const BoundaryID secondary_boundary_id) const 253 : { 254 22 : return (primary_boundary_id == _primary_id) && (secondary_boundary_id == _secondary_id); 255 : }