https://mooseframework.inl.gov
Loading...
Searching...
No Matches
ADInterfaceKernel.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
10#include "ADInterfaceKernel.h"
11
12// MOOSE includes
13#include "Assembly.h"
14#include "MooseVariableFE.h"
15#include "SystemBase.h"
16#include "ADUtils.h"
17
18// libmesh includes
19#include "libmesh/quadrature.h"
20
21template <typename T>
24{
26 if (std::is_same<T, Real>::value)
27 params.registerBase("InterfaceKernel");
28 else if (std::is_same<T, RealVectorValue>::value)
29 params.registerBase("VectorInterfaceKernel");
30 else
31 ::mooseError("unsupported ADInterfaceKernelTempl specialization");
32 return params;
33}
34
35template <typename T>
37 : InterfaceKernelBase(parameters),
39 false,
40 Moose::VarKindType::VAR_SOLVER,
41 std::is_same<T, Real>::value
42 ? Moose::VarFieldType::VAR_FIELD_STANDARD
43 : Moose::VarFieldType::VAR_FIELD_VECTOR),
44 _var(*this->mooseVariable()),
45 _normals(_assembly.normals()),
46 _u(_var.adSln()),
47 _grad_u(_var.adGradSln()),
48 _ad_JxW(_assembly.adJxWFace()),
49 _ad_coord(_assembly.adCoordTransformation()),
50 _ad_q_point(_assembly.adQPoints()),
51 _phi(_assembly.phiFace(_var)),
52 _test(_var.phiFace()),
53 _grad_test(_var.adGradPhiFace()),
54 _neighbor_var(*getVarHelper<MooseVariableFE<T>>("neighbor_var", 0)),
55 _neighbor_value(_neighbor_var.adSlnNeighbor()),
56 _grad_neighbor_value(_neighbor_var.adGradSlnNeighbor()),
57 _phi_neighbor(_assembly.phiFaceNeighbor(_neighbor_var)),
58 _test_neighbor(_neighbor_var.phiFaceNeighbor()),
59 _grad_test_neighbor(_neighbor_var.gradPhiFaceNeighbor())
60
61{
63
65
66 if (!parameters.isParamValid("boundary"))
68 "In order to use an interface kernel, you must specify a boundary where it will live.");
69}
70
71template <typename T>
72void
74{
75 bool is_elem;
76 if (type == Moose::Element)
77 is_elem = true;
78 else
79 is_elem = false;
80
81 const ADTemplateVariableTestValue<T> & test_space = is_elem ? _test : _test_neighbor;
82
83 if (is_elem)
84 prepareVectorTag(_assembly, _var.number());
85 else
86 prepareVectorTagNeighbor(_assembly, _neighbor_var.number());
87
88 for (_qp = 0; _qp < _qrule->n_points(); _qp++)
89 {
90 initQpResidual(type);
91 const auto jxw_p = _JxW[_qp] * _coord[_qp];
92 for (_i = 0; _i < test_space.size(); _i++)
93 _local_re(_i) += jxw_p * raw_value(computeQpResidual(type));
94 }
95
96 accumulateTaggedLocalResidual();
97}
98
99template <typename T>
100void
102{
103 // in the gmsh mesh format (at least in the version 2 format) the "sideset" physical entities are
104 // associated only with the lower-dimensional geometric entity that is the boundary between two
105 // higher-dimensional element faces. It does not have a sidedness to it like the exodus format
106 // does. Consequently we may naively try to execute an interface kernel twice, one time where _var
107 // has dofs on _current_elem *AND* _neighbor_var has dofs on _neighbor_elem, and the other time
108 // where _var has dofs on _neighbor_elem and _neighbor_var has dofs on _current_elem. We only want
109 // to execute in the former case. In the future we should remove this and add some kind of "block"
110 // awareness to interface kernels to avoid all the unnecessary reinit that happens before we hit
111 // this return
112 if (!_var.activeOnSubdomain(_current_elem->subdomain_id()) ||
113 !_neighbor_var.activeOnSubdomain(_neighbor_elem->subdomain_id()))
114 return;
115
116 precalculateResidual();
117
118 // Compute the residual for this element
119 computeElemNeighResidual(Moose::Element);
120
121 // Compute the residual for the neighbor
122 computeElemNeighResidual(Moose::Neighbor);
123}
124
125template <typename T>
126void
128{
129 mooseAssert(type == Moose::ElementElement || type == Moose::NeighborNeighbor,
130 "With AD you should need one call per side");
131
132 const ADTemplateVariableTestValue<T> & test_space =
133 (type == Moose::ElementElement || type == Moose::ElementNeighbor) ? _test : _test_neighbor;
134
135 std::vector<ADReal> residuals(test_space.size(), 0);
136
137 switch (type)
138 {
140 resid_type = Moose::Element;
141 break;
143 resid_type = Moose::Element;
144 break;
146 resid_type = Moose::Neighbor;
147 break;
149 resid_type = Moose::Neighbor;
150 break;
151 default:
152 mooseError("Unknown DGJacobianType ", type);
153 }
154
155 for (_qp = 0; _qp < _qrule->n_points(); _qp++)
156 {
157 initQpResidual(resid_type);
158 const auto jxw_c = _ad_JxW[_qp] * _ad_coord[_qp];
159 for (_i = 0; _i < test_space.size(); _i++)
160 residuals[_i] += jxw_c * computeQpResidual(resid_type);
161 }
162
163 const bool element_var_is_var = (type == Moose::ElementElement || type == Moose::ElementNeighbor);
164 addJacobian(_assembly,
165 residuals,
166 element_var_is_var ? _var.dofIndices() : _neighbor_var.dofIndicesNeighbor(),
167 element_var_is_var ? _var.scalingFactor() : _neighbor_var.scalingFactor());
168}
169
170template <typename T>
171void
173{
174 // in the gmsh mesh format (at least in the version 2 format) the "sideset" physical entities are
175 // associated only with the lower-dimensional geometric entity that is the boundary between two
176 // higher-dimensional element faces. It does not have a sidedness to it like the exodus format
177 // does. Consequently we may naively try to execute an interface kernel twice, one time where _var
178 // has dofs on _current_elem *AND* _neighbor_var has dofs on _neighbor_elem, and the other time
179 // where _var has dofs on _neighbor_elem and _neighbor_var has dofs on _current_elem. We only want
180 // to execute in the former case. In the future we should remove this and add some kind of "block"
181 // awareness to interface kernels to avoid all the unnecessary reinit that happens before we hit
182 // this return
183 if (!_var.activeOnSubdomain(_current_elem->subdomain_id()) ||
184 !_neighbor_var.activeOnSubdomain(_neighbor_elem->subdomain_id()))
185 return;
186
187 precalculateJacobian();
188
189 computeElemNeighJacobian(Moose::ElementElement);
190 computeElemNeighJacobian(Moose::NeighborNeighbor);
191}
192
193template <typename T>
194void
196{
197 mooseAssert(type == Moose::ElementElement || type == Moose::NeighborNeighbor,
198 "With AD you should need one call per side");
199
200 const ADTemplateVariableTestValue<T> & test_space =
201 type == Moose::ElementElement ? _test : _test_neighbor;
202
203 if (type == Moose::ElementElement)
204 resid_type = Moose::Element;
205 else
206 resid_type = Moose::Neighbor;
207
208 std::vector<ADReal> residuals(test_space.size(), 0);
209
210 for (_qp = 0; _qp < _qrule->n_points(); _qp++)
211 {
212 initQpResidual(resid_type);
213 const auto jxw_c = _ad_JxW[_qp] * _ad_coord[_qp];
214 for (_i = 0; _i < test_space.size(); _i++)
215 residuals[_i] += jxw_c * computeQpResidual(resid_type);
216 }
217
218 // We assert earlier that the type cannot be Moose::ElementNeighbor (nor Moose::NeighborElement)
219 addJacobian(_assembly,
220 residuals,
221 type == Moose::ElementElement ? _var.dofIndices()
222 : _neighbor_var.dofIndicesNeighbor(),
223 type == Moose::ElementElement ? _var.scalingFactor() : _neighbor_var.scalingFactor());
224}
225
226template <typename T>
227void
229{
230 // in the gmsh mesh format (at least in the version 2 format) the "sideset" physical entities are
231 // associated only with the lower-dimensional geometric entity that is the boundary between two
232 // higher-dimensional element faces. It does not have a sidedness to it like the exodus format
233 // does. Consequently we may naively try to execute an interface kernel twice, one time where _var
234 // has dofs on _current_elem *AND* _neighbor_var has dofs on _neighbor_elem, and the other time
235 // where _var has dofs on _neighbor_elem and _neighbor_var has dofs on _current_elem. We only want
236 // to execute in the former case. In the future we should remove this and add some kind of "block"
237 // awareness to interface kernels to avoid all the unnecessary reinit that happens before we hit
238 // this return
239 if (!_var.activeOnSubdomain(_current_elem->subdomain_id()) ||
240 !_neighbor_var.activeOnSubdomain(_neighbor_elem->subdomain_id()))
241 return;
242
243 if (jvar != _var.number())
244 // We only need to do these computations a single time because AD computes all the derivatives
245 // at once
246 return;
247
248 precalculateOffDiagJacobian(jvar);
249
250 // Again AD does Jacobians all at once so we only need to call with ElementElement
251 computeOffDiagElemNeighJacobian(Moose::ElementElement, jvar);
252}
253
254template <typename T>
255void
257{
258 // in the gmsh mesh format (at least in the version 2 format) the "sideset" physical entities are
259 // associated only with the lower-dimensional geometric entity that is the boundary between two
260 // higher-dimensional element faces. It does not have a sidedness to it like the exodus format
261 // does. Consequently we may naively try to execute an interface kernel twice, one time where _var
262 // has dofs on _current_elem *AND* _neighbor_var has dofs on _neighbor_elem, and the other time
263 // where _var has dofs on _neighbor_elem and _neighbor_var has dofs on _current_elem. We only want
264 // to execute in the former case. In the future we should remove this and add some kind of "block"
265 // awareness to interface kernels to avoid all the unnecessary reinit that happens before we hit
266 // this return
267 if (!_var.activeOnSubdomain(_current_elem->subdomain_id()) ||
268 !_neighbor_var.activeOnSubdomain(_neighbor_elem->subdomain_id()))
269 return;
270
271 if (jvar != _neighbor_var.number())
272 // We only need to do these computations a single time because AD computes all the derivatives
273 // at once
274 return;
275
276 precalculateOffDiagJacobian(jvar);
277
278 // Again AD does Jacobians all at once so we only need to call with NeighborNeighbor
279 computeOffDiagElemNeighJacobian(Moose::NeighborNeighbor, jvar);
280}
281
282// Explicitly instantiates the two versions of the ADInterfaceKernelTempl class
283template class ADInterfaceKernelTempl<Real>;
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
typename OutputTools< T >::VariableTestValue ADTemplateVariableTestValue
Definition MooseTypes.h:673
ADInterfaceKernel and ADVectorInterfaceKernel is responsible for interfacing physics across subdomain...
void computeOffDiagElemNeighJacobian(Moose::DGJacobianType type, unsigned int jvar)
Using the passed DGJacobian type, selects the correct test function and trial function spaces and jac...
void computeElemNeighResidual(Moose::DGResidualType type)
Using the passed DGResidual type, selects the correct test function space and residual block,...
virtual void computeNeighborOffDiagJacobian(unsigned int jvar) override final
Selects the correct Jacobian type and routine to call for the secondary variable jacobian.
void computeJacobian() override final
Computes the jacobian for the current side.
void computeResidual() override final
Computes the residual for the current side.
void computeElemNeighJacobian(Moose::DGJacobianType type)
Using the passed DGJacobian type, selects the correct test function and trial function spaces and jac...
ADInterfaceKernelTempl(const InputParameters &parameters)
static InputParameters validParams()
virtual void computeElementOffDiagJacobian(unsigned int jvar) override final
Selects the correct Jacobian type and routine to call for the primary variable jacobian.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
void registerBase(const std::string &value)
This method must be called from every base "Moose System" to create linkage with the Action System.
bool isParamValid(const std::string &name) const
This method returns parameters that have been initialized in one fashion or another,...
InterfaceKernelBase is the base class for all InterfaceKernel type classes.
static InputParameters validParams()
void addMooseVariableDependency(MooseVariableFieldBase *var)
Call this function to add the passed in MooseVariableFieldBase as a variable that this object depends...
Class for stuff related to variables.
MooseVariableFE< T > * mooseVariable() const
Return the MooseVariableFE object that this interface acts on.
Enhances MooseVariableInterface interface provide values from neighbor elements.
SubProblem & _subproblem
Reference to this kernel's SubProblem.
virtual void haveADObjects(bool have_ad_objects)
Method for setting whether we have any ad objects.
Definition SubProblem.h:775
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
DGResidualType
Definition MooseTypes.h:798
@ Element
Definition MooseTypes.h:799
@ Neighbor
Definition MooseTypes.h:800
DGJacobianType
Definition MooseTypes.h:804
@ NeighborNeighbor
Definition MooseTypes.h:808
@ ElementElement
Definition MooseTypes.h:805
@ NeighborElement
Definition MooseTypes.h:807
@ ElementNeighbor
Definition MooseTypes.h:806