https://mooseframework.inl.gov
ADMortarLagrangeConstraint.C
Go to the documentation of this file.
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 
11 
12 // MOOSE includes
13 #include "MooseVariable.h"
14 #include "MoosePreconditioner.h"
16 #include "NonlinearSystemBase.h"
17 #include "Assembly.h"
18 #include "SystemBase.h"
19 #include "ADUtils.h"
20 #include "FEProblemBase.h"
22 
23 #include <algorithm>
24 #include <vector>
25 
28 {
30  params.addParam<Real>(
31  "derivative_threshold",
32  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  return params;
37 }
38 
40  : ADMortarConstraint(parameters),
41  _ad_derivative_threshold(getParam<Real>("derivative_threshold")),
42  _apply_derivative_threshold(true)
43 {
44 }
45 
46 void
48 {
50 
51  // Detect if preconditioner is VCP. If so, disable automatic derivative trimming.
52  auto const * mpc = feProblem().getNonlinearSystemBase(_sys.number()).getPreconditioner();
53 
54  if (dynamic_cast<const VariableCondensationPreconditioner *>(mpc))
56 }
57 
58 void
60 {
63 
65 
66  unsigned int test_space_size = 0;
67  switch (mortar_type)
68  {
71  test_space_size = _test_secondary.size();
72  break;
73 
76  test_space_size = _test_primary.size();
77  break;
78 
80  mooseAssert(_var, "LM variable is null");
82  test_space_size = _test.size();
83  break;
84  }
85 
86  std::vector<unsigned int> is_index_on_lower_dimension;
87  // Find out if nodes are on the surface
88  for (_i = 0; _i < test_space_size; _i++)
89  {
90  if (mortar_type == Moose::MortarType::Primary && !_primary_ip_lowerd_map.count(_i))
91  continue;
92 
93  if (mortar_type == Moose::MortarType::Secondary && !_secondary_ip_lowerd_map.count(_i))
94  continue;
95 
96  is_index_on_lower_dimension.push_back(_i);
97  }
98 
99  for (_qp = 0; _qp < _qrule_msm->n_points(); _qp++)
100  for (const auto index : is_index_on_lower_dimension)
101  {
102  _i = index;
103  _local_re(_i) += raw_value(_JxW_msm[_qp] * _coord[_qp] * computeQpResidual(mortar_type));
104  }
105 
107 }
108 
109 void
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 
122 
124 
125  switch (mortar_type)
126  {
127  case MType::Secondary:
128  dof_indices = _secondary_var.dofIndices();
129  jacobian_types = {JType::SecondarySecondary, JType::SecondaryPrimary, JType::SecondaryLower};
130  scaling_factor = _secondary_var.scalingFactor();
131  break;
132 
133  case MType::Primary:
134  dof_indices = _primary_var.dofIndicesNeighbor();
135  jacobian_types = {JType::PrimarySecondary, JType::PrimaryPrimary, JType::PrimaryLower};
136  scaling_factor = _primary_var.scalingFactor();
137  break;
138 
139  case MType::Lower:
140  mooseAssert(_var, "This should be non-null");
141  dof_indices = _var->dofIndicesLower();
142  jacobian_types = {JType::LowerSecondary, JType::LowerPrimary, JType::LowerLower};
143  scaling_factor = _var->scalingFactor();
144  break;
145  }
146  test_space_size = dof_indices.size();
147 
148  residuals.resize(test_space_size, 0);
149 
150  std::vector<unsigned int> is_index_on_lower_dimension;
151  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  for (_i = 0; _i < test_space_size; _i++)
157  {
158  if (mortar_type == Moose::MortarType::Primary && !_primary_ip_lowerd_map.count(_i))
159  continue;
160 
161  if (mortar_type == Moose::MortarType::Secondary && !_secondary_ip_lowerd_map.count(_i))
162  continue;
163 
164  is_index_on_lower_dimension.push_back(_i);
165  dof_indices_lower.push_back(dof_indices[_i]);
166  number_indices_on_lowerd++;
167  }
168 
169  std::vector<ADReal> residuals_lower;
170  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  for (_qp = 0; _qp < _qrule_msm->n_points(); _qp++)
178  {
179  unsigned int index_lower = 0;
180  for (const auto index : is_index_on_lower_dimension)
181  {
182  _i = index;
183  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  index_lower++;
191  }
192  }
193 
194  addJacobian(_assembly, residuals_lower, dof_indices_lower, scaling_factor);
195 }
MooseVariableField< Real > & _secondary_var
const VariableTestValue & _test_secondary
void accumulateTaggedLocalResidual()
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
unsigned int number() const
std::map< unsigned int, unsigned int > getPrimaryIpToLowerElementMap(const Elem &primary_elem, const Elem &primary_elem_ip, const Elem &lower_secondary_elem) const
const std::vector< dof_id_type > & dofIndicesLower() const final
auto raw_value(const Eigen::Map< T > &in)
Elem const *const & _lower_primary_elem
const std::vector< Real > & _JxW_msm
unsigned int _i
virtual ADReal computeQpResidual(Moose::MortarType mortar_type)=0
virtual void computeResidual() override
const libMesh::QBase *const & _qrule_msm
static InputParameters validParams()
const VariableTestValue & _test
SystemBase & _sys
void addJacobian(Assembly &assembly, const Residuals &residuals, const Indices &dof_indices, Real scaling_factor)
Elem const *const & _lower_secondary_elem
virtual const std::vector< dof_id_type > & dofIndicesNeighbor() const=0
const AutomaticMortarGeneration & amg() const
virtual const std::vector< dof_id_type > & dofIndices() const
unsigned int n_points() const
std::map< unsigned int, unsigned int > _primary_ip_lowerd_map
Nodal map from primary interior parent to lower dimensional domain.
std::map< unsigned int, unsigned int > getSecondaryIpToLowerElementMap(const Elem &lower_secondary_elem) const
NonlinearSystemBase & getNonlinearSystemBase(const unsigned int sys_num)
unsigned int number() const
const FEProblemBase & feProblem() const
Assembly & _assembly
virtual void initialSetup() override
std::map< unsigned int, unsigned int > _secondary_ip_lowerd_map
Nodal map from secondary interior parent to lower dimensional domain.
MooseVariable *const _var
void prepareVectorTagNeighbor(Assembly &assembly, unsigned int ivar)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
bool _apply_derivative_threshold
Whether to apply derivative trimming.
ConstraintJacobianType
DenseVector< Number > _local_re
virtual void computeJacobian() override
ADMortarLagrangeConstraint(const InputParameters &parameters)
static InputParameters validParams()
void prepareVectorTagLower(Assembly &assembly, unsigned int ivar)
void prepareVectorTag(Assembly &assembly, unsigned int ivar)
const MooseArray< Real > & _coord
virtual void initialSetup()
const VariableTestValue & _test_primary
unsigned int _qp
void scalingFactor(const std::vector< Real > &factor)
MooseVariableField< Real > & _primary_var