https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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
46void
48{
50
51 // Detect if preconditioner is VCP. If so, disable automatic derivative trimming.
53
54 if (dynamic_cast<const VariableCondensationPreconditioner *>(mpc))
56}
57
58void
60{
63
65
66 unsigned int test_space_size = 0;
67 switch (mortar_type)
68 {
69 case Moose::MortarType::Secondary:
71 test_space_size = _test_secondary.size();
72 break;
73
74 case Moose::MortarType::Primary:
76 test_space_size = _test_primary.size();
77 break;
78
79 case Moose::MortarType::Lower:
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
109void
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}
static InputParameters validParams()
virtual ADReal computeQpResidual(Moose::MortarType mortar_type)=0
ADMortarLagrangeConstraint(const InputParameters &parameters)
bool _apply_derivative_threshold
Whether to apply derivative trimming.
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 > _secondary_ip_lowerd_map
Nodal map from secondary interior parent to lower dimensional domain.
virtual void computeJacobian() override
static InputParameters validParams()
virtual void computeResidual() override
std::map< unsigned int, unsigned int > getSecondaryIpToLowerElementMap(const Elem &lower_secondary_elem) const
std::map< unsigned int, unsigned int > getPrimaryIpToLowerElementMap(const Elem &primary_elem, const Elem &primary_elem_ip, const Elem &lower_secondary_elem) const
unsigned int _qp
unsigned int _i
NonlinearSystemBase & getNonlinearSystemBase(const unsigned int sys_num)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
virtual const std::vector< dof_id_type > & dofIndices() const
void scalingFactor(const std::vector< Real > &factor)
unsigned int number() const
const std::vector< dof_id_type > & dofIndicesLower() const final
virtual const std::vector< dof_id_type > & dofIndicesNeighbor() const=0
MooseVariableField< Real > & _primary_var
MooseVariable *const _var
const VariableTestValue & _test_secondary
const MooseArray< Real > & _coord
MooseVariableField< Real > & _secondary_var
const FEProblemBase & feProblem() const
const VariableTestValue & _test
const VariableTestValue & _test_primary
Elem const *const & _lower_secondary_elem
const libMesh::QBase *const & _qrule_msm
const AutomaticMortarGeneration & amg() const
Elem const *const & _lower_primary_elem
const std::vector< Real > & _JxW_msm
MoosePreconditioner const * getPreconditioner() const
Assembly & _assembly
SystemBase & _sys
virtual void initialSetup()
unsigned int number() const
void prepareVectorTagLower(Assembly &assembly, unsigned int ivar)
void addJacobian(Assembly &assembly, const Residuals &residuals, const Indices &dof_indices, Real scaling_factor)
void accumulateTaggedLocalResidual()
void prepareVectorTagNeighbor(Assembly &assembly, unsigned int ivar)
void prepareVectorTag(Assembly &assembly, unsigned int ivar)
DenseVector< Number > _local_re
unsigned int n_points() const
ConstraintJacobianType