https://mooseframework.inl.gov
Loading...
Searching...
No Matches
InterfaceKernel.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 "InterfaceKernel.h"
11
12// MOOSE includes
13#include "Assembly.h"
14#include "MooseVariableFE.h"
15#include "SystemBase.h"
16#include "AuxiliarySystem.h"
17#include "FEProblemBase.h"
18
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 InterfaceKernelTempl 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(_is_implicit ? _var.sln() : _var.slnOld()),
47 _grad_u(_is_implicit ? _var.gradSln() : _var.gradSlnOld()),
48 _phi(_assembly.phiFace(_var)),
49 _grad_phi(_assembly.gradPhiFace(_var)),
50 _test(_var.phiFace()),
51 _grad_test(_var.gradPhiFace()),
52 _neighbor_var(*getVarHelper<MooseVariableFE<T>>("neighbor_var", 0)),
53 _neighbor_value(_is_implicit ? _neighbor_var.slnNeighbor() : _neighbor_var.slnOldNeighbor()),
54 _grad_neighbor_value(_neighbor_var.gradSlnNeighbor()),
55 _phi_neighbor(_assembly.phiFaceNeighbor(_neighbor_var)),
56 _grad_phi_neighbor(_assembly.gradPhiFaceNeighbor(_neighbor_var)),
57 _test_neighbor(_neighbor_var.phiFaceNeighbor()),
58 _grad_test_neighbor(_neighbor_var.gradPhiFaceNeighbor()),
59 _same_system(_var.sys().number() == _neighbor_var.sys().number())
60{
61 // Neighbor variable dependency is added by
62 // NeighborCoupleableMooseVariableDependencyIntermediateInterface
64
65 if (!parameters.isParamValid("boundary"))
67 "In order to use an interface kernel, you must specify a boundary where it will live.");
68
69 if (parameters.isParamSetByUser("save_in"))
70 {
72 mooseError("save_in and save_in_var_side must be the same length");
73 else
74 {
75 for (unsigned i = 0; i < _save_in_strings.size(); ++i)
76 {
78
80 mooseError("Trying to use solution variable " + _save_in_strings[i] +
81 " as a save_in variable in " + name());
82
83 if (_save_in_var_side[i] == "m")
84 {
85 if (var->feType() != _var.feType())
87 "Error in " + name() +
88 ". There is a mismatch between the fe_type of the save-in Auxiliary variable "
89 "and the fe_type of the the primary side nonlinear "
90 "variable this interface kernel object is acting on.");
92 }
93 else
94 {
95 if (var->feType() != _neighbor_var.feType())
97 "Error in " + name() +
98 ". There is a mismatch between the fe_type of the save-in Auxiliary variable "
99 "and the fe_type of the the secondary side nonlinear "
100 "variable this interface kernel object is acting on.");
102 }
103
106 }
107 }
108 }
109
112
113 if (parameters.isParamSetByUser("diag_save_in"))
114 {
116 mooseError("diag_save_in and diag_save_in_var_side must be the same length");
117 else
118 {
119 for (unsigned i = 0; i < _diag_save_in_strings.size(); ++i)
120 {
122
124 mooseError("Trying to use solution variable " + _diag_save_in_strings[i] +
125 " as a save_in variable in " + name());
126
127 if (_diag_save_in_var_side[i] == "m")
128 {
129 if (var->feType() != _var.feType())
131 "Error in " + name() +
132 ". There is a mismatch between the fe_type of the save-in Auxiliary variable "
133 "and the fe_type of the the primary side nonlinear "
134 "variable this interface kernel object is acting on.");
136 }
137 else
138 {
139 if (var->feType() != _neighbor_var.feType())
141 "Error in " + name() +
142 ". There is a mismatch between the fe_type of the save-in Auxiliary variable "
143 "and the fe_type of the the secondary side nonlinear "
144 "variable this interface kernel object is acting on.");
146 }
147
150 }
151 }
152 }
153
156}
157
158template <typename T>
159void
161{
162 bool is_elem;
163 if (type == Moose::Element)
164 is_elem = true;
165 else
166 is_elem = false;
167
168 const TemplateVariableTestValue & test_space = is_elem ? _test : _test_neighbor;
169
170 if (is_elem)
171 prepareVectorTag(_assembly, _var.number());
172 else
173 prepareVectorTagNeighbor(_assembly, _neighbor_var.number());
174
175 for (_qp = 0; _qp < _qrule->n_points(); _qp++)
176 {
177 initQpResidual(type);
178 for (_i = 0; _i < test_space.size(); _i++)
179 _local_re(_i) += _JxW[_qp] * _coord[_qp] * computeQpResidual(type);
180 }
181
182 accumulateTaggedLocalResidual();
183
184 // To save the diagonal of the Jacobian
185 if (_has_primary_residuals_saved_in && is_elem)
186 for (const auto & var : _primary_save_in_residual_variables)
187 var->sys().solution().add_vector(_local_re, var->dofIndices());
188 else if (_has_secondary_residuals_saved_in && !is_elem)
189 for (const auto & var : _secondary_save_in_residual_variables)
190 var->sys().solution().add_vector(_local_re, var->dofIndicesNeighbor());
191}
192
193template <typename T>
194void
196{
197 // in the gmsh mesh format (at least in the version 2 format) the "sideset" physical entities are
198 // associated only with the lower-dimensional geometric entity that is the boundary between two
199 // higher-dimensional element faces. It does not have a sidedness to it like the exodus format
200 // does. Consequently we may naively try to execute an interface kernel twice, one time where _var
201 // has dofs on _current_elem *AND* _neighbor_var has dofs on _neighbor_elem, and the other time
202 // where _var has dofs on _neighbor_elem and _neighbor_var has dofs on _current_elem. We only want
203 // to execute in the former case. In the future we should remove this and add some kind of "block"
204 // awareness to interface kernels to avoid all the unnecessary reinit that happens before we hit
205 // this return
206 if (!_var.activeOnSubdomain(_current_elem->subdomain_id()) ||
207 !_neighbor_var.activeOnSubdomain(_neighbor_elem->subdomain_id()))
208 return;
209
210 precalculateResidual();
211
212 // Compute the residual for this element
213 computeElemNeighResidual(Moose::Element);
214
215 // Compute the residual for the neighbor
216 // This also prevents computing a residual if the neighbor variable is auxiliary
217 if (_same_system)
218 computeElemNeighResidual(Moose::Neighbor);
219}
220
221template <typename T>
222void
224{
225 const TemplateVariableTestValue & test_space =
226 (type == Moose::ElementElement || type == Moose::ElementNeighbor) ? _test : _test_neighbor;
227 const TemplateVariableTestValue & loc_phi =
228 (type == Moose::ElementElement || type == Moose::NeighborElement) ? _phi : _phi_neighbor;
229
230 unsigned int ivar, jvar;
231
232 switch (type)
233 {
235 ivar = jvar = _var.number();
236 break;
238 ivar = _var.number(), jvar = _neighbor_var.number();
239 break;
241 ivar = _neighbor_var.number(), jvar = _var.number();
242 break;
244 ivar = _neighbor_var.number(), jvar = _neighbor_var.number();
245 break;
246 default:
247 mooseError("Unknown DGJacobianType ", type);
248 }
249
250 if (type == Moose::ElementElement)
251 prepareMatrixTag(_assembly, ivar, jvar);
252 else
253 prepareMatrixTagNeighbor(_assembly, ivar, jvar, type);
254
255 for (_qp = 0; _qp < _qrule->n_points(); _qp++)
256 {
257 initQpJacobian(type);
258 for (_i = 0; _i < test_space.size(); _i++)
259 for (_j = 0; _j < loc_phi.size(); _j++)
260 _local_ke(_i, _j) += _JxW[_qp] * _coord[_qp] * computeQpJacobian(type);
261 }
262
263 accumulateTaggedLocalMatrix();
264
265 // To save the diagonal of the Jacobian
266 if (_has_primary_jacobians_saved_in && type == Moose::ElementElement)
267 {
268 auto rows = _local_ke.m();
269 DenseVector<Number> diag(rows);
270 for (decltype(rows) i = 0; i < rows; i++)
271 diag(i) = _local_ke(i, i);
272
273 for (const auto & var : _primary_save_in_jacobian_variables)
274 var->sys().solution().add_vector(diag, var->dofIndices());
275 }
276 else if (_has_secondary_jacobians_saved_in && type == Moose::NeighborNeighbor)
277 {
278 auto rows = _local_ke.m();
279 DenseVector<Number> diag(rows);
280 for (decltype(rows) i = 0; i < rows; i++)
281 diag(i) = _local_ke(i, i);
282
283 for (const auto & var : _secondary_save_in_jacobian_variables)
284 var->sys().solution().add_vector(diag, var->dofIndicesNeighbor());
285 }
286}
287
288template <typename T>
289void
291{
292 // in the gmsh mesh format (at least in the version 2 format) the "sideset" physical entities are
293 // associated only with the lower-dimensional geometric entity that is the boundary between two
294 // higher-dimensional element faces. It does not have a sidedness to it like the exodus format
295 // does. Consequently we may naively try to execute an interface kernel twice, one time where _var
296 // has dofs on _current_elem *AND* _neighbor_var has dofs on _neighbor_elem, and the other time
297 // where _var has dofs on _neighbor_elem and _neighbor_var has dofs on _current_elem. We only want
298 // to execute in the former case. In the future we should remove this and add some kind of "block"
299 // awareness to interface kernels to avoid all the unnecessary reinit that happens before we hit
300 // this return
301 if (!_var.activeOnSubdomain(_current_elem->subdomain_id()) ||
302 !_neighbor_var.activeOnSubdomain(_neighbor_elem->subdomain_id()))
303 return;
304
305 precalculateJacobian();
306
307 computeElemNeighJacobian(Moose::ElementElement);
308 if (_same_system)
309 computeElemNeighJacobian(Moose::NeighborNeighbor);
310}
311
312template <typename T>
313void
315 unsigned int jvar)
316{
317 const TemplateVariableTestValue & test_space =
318 (type == Moose::ElementElement || type == Moose::ElementNeighbor) ? _test : _test_neighbor;
319 const TemplateVariableTestValue & loc_phi =
320 (type == Moose::ElementElement || type == Moose::NeighborElement) ? _phi : _phi_neighbor;
321
322 unsigned int ivar;
323
324 if (type == Moose::ElementElement || type == Moose::ElementNeighbor)
325 ivar = _var.number();
326 else
327 ivar = _neighbor_var.number();
328
329 if (type == Moose::ElementElement)
330 prepareMatrixTag(_assembly, ivar, jvar);
331 else
332 prepareMatrixTagNeighbor(_assembly, ivar, jvar, type);
333
334 // Prevent calling of Jacobian computation if jvar doesn't lie in the current block
335 if ((_local_ke.m() == test_space.size()) && (_local_ke.n() == loc_phi.size()))
336 for (_qp = 0; _qp < _qrule->n_points(); _qp++)
337 {
338 initQpOffDiagJacobian(type, jvar);
339 for (_i = 0; _i < test_space.size(); _i++)
340 for (_j = 0; _j < loc_phi.size(); _j++)
341 _local_ke(_i, _j) += _JxW[_qp] * _coord[_qp] * computeQpOffDiagJacobian(type, jvar);
342 }
343
344 accumulateTaggedLocalMatrix();
345}
346
347template <typename T>
348void
350{
351 // in the gmsh mesh format (at least in the version 2 format) the "sideset" physical entities are
352 // associated only with the lower-dimensional geometric entity that is the boundary between two
353 // higher-dimensional element faces. It does not have a sidedness to it like the exodus format
354 // does. Consequently we may naively try to execute an interface kernel twice, one time where _var
355 // has dofs on _current_elem *AND* _neighbor_var has dofs on _neighbor_elem, and the other time
356 // where _var has dofs on _neighbor_elem and _neighbor_var has dofs on _current_elem. We only want
357 // to execute in the former case. In the future we should remove this and add some kind of "block"
358 // awareness to interface kernels to avoid all the unnecessary reinit that happens before we hit
359 // this return
360 if (!_var.activeOnSubdomain(_current_elem->subdomain_id()) ||
361 !_neighbor_var.activeOnSubdomain(_neighbor_elem->subdomain_id()))
362 return;
363
364 bool is_jvar_not_interface_var = true;
365 if (jvar == _var.number())
366 {
367 precalculateJacobian();
368 computeElemNeighJacobian(Moose::ElementElement);
369 is_jvar_not_interface_var = false;
370 }
371 if (jvar == _neighbor_var.number() && _same_system)
372 {
373 precalculateJacobian();
374 computeElemNeighJacobian(Moose::ElementNeighbor);
375 is_jvar_not_interface_var = false;
376 }
377
378 if (is_jvar_not_interface_var)
379 {
380 precalculateOffDiagJacobian(jvar);
381 computeOffDiagElemNeighJacobian(Moose::ElementElement, jvar);
382 computeOffDiagElemNeighJacobian(Moose::ElementNeighbor, jvar);
383 }
384}
385
386template <typename T>
387void
389{
390 // in the gmsh mesh format (at least in the version 2 format) the "sideset" physical entities are
391 // associated only with the lower-dimensional geometric entity that is the boundary between two
392 // higher-dimensional element faces. It does not have a sidedness to it like the exodus format
393 // does. Consequently we may naively try to execute an interface kernel twice, one time where _var
394 // has dofs on _current_elem *AND* _neighbor_var has dofs on _neighbor_elem, and the other time
395 // where _var has dofs on _neighbor_elem and _neighbor_var has dofs on _current_elem. We only want
396 // to execute in the former case. In the future we should remove this and add some kind of "block"
397 // awareness to interface kernels to avoid all the unnecessary reinit that happens before we hit
398 // this return
399 if (!_var.activeOnSubdomain(_current_elem->subdomain_id()) ||
400 !_neighbor_var.activeOnSubdomain(_neighbor_elem->subdomain_id()))
401 return;
402
403 // We don't care about any contribution to the neighbor Jacobian rows if it's not in the system
404 // we are currently working with (the variable's system)
405 if (!_same_system)
406 return;
407
408 bool is_jvar_not_interface_var = true;
409 if (jvar == _var.number())
410 {
411 precalculateJacobian();
412 computeElemNeighJacobian(Moose::NeighborElement);
413 is_jvar_not_interface_var = false;
414 }
415 if (jvar == _neighbor_var.number())
416 {
417 precalculateJacobian();
418 computeElemNeighJacobian(Moose::NeighborNeighbor);
419 is_jvar_not_interface_var = false;
420 }
421
422 if (is_jvar_not_interface_var)
423 {
424 precalculateOffDiagJacobian(jvar);
425 computeOffDiagElemNeighJacobian(Moose::NeighborElement, jvar);
426 computeOffDiagElemNeighJacobian(Moose::NeighborNeighbor, jvar);
427 }
428}
429
430template <typename T>
431void
433{
434 computeResidual();
435
436 if (!isImplicit())
437 return;
438
439 for (const auto & [ivariable, jvariable] : _fe_problem.couplingEntries(_tid, _sys.number()))
440 {
441 if (ivariable->isFV())
442 continue;
443
444 const unsigned int ivar = ivariable->number();
445 const unsigned int jvar = jvariable->number();
446
447 prepareShapes(jvar);
448 prepareNeighborShapes(jvar);
449
450 if (_var.number() == ivar)
451 computeElementOffDiagJacobian(jvar);
452
453 if (_same_system)
454 if (_neighbor_var.number() == ivar)
455 computeNeighborOffDiagJacobian(jvar);
456 }
457}
458
459// Explicitly instantiates the two versions of the InterfaceKernelTempl class
460template class InterfaceKernelTempl<Real>;
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
bool isParamSetByUser(const std::string &name) const
Method returns true if the parameter was set by the user.
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.
std::vector< MooseVariableFEBase * > _secondary_save_in_jacobian_variables
The aux variables to save the diagonal Jacobian contributions of the secondary variables to.
static InputParameters validParams()
std::vector< AuxVariableName > _save_in_strings
The names of the aux variables that will be used to save-in residuals (includes both primary and seco...
bool _has_secondary_jacobians_saved_in
Whether there are secondary jacobian aux variables.
bool _has_primary_residuals_saved_in
Whether there are primary residual aux variables.
bool _has_secondary_residuals_saved_in
Whether there are secondary residual aux variables.
std::vector< MooseVariableFEBase * > _secondary_save_in_residual_variables
The aux variables to save the secondary contributions to.
MultiMooseEnum _diag_save_in_var_side
MultiMooseEnum specifying whether jacobian save-in aux variables correspond to primary or secondary s...
std::vector< AuxVariableName > _diag_save_in_strings
The names of the aux variables that will be used to save-in jacobians (includes both primary and seco...
MultiMooseEnum _save_in_var_side
MultiMooseEnum specifying whether residual save-in aux variables correspond to primary or secondary s...
std::vector< MooseVariableFEBase * > _primary_save_in_jacobian_variables
The aux variables to save the diagonal Jacobian contributions of the primary variables to.
std::vector< MooseVariableFEBase * > _primary_save_in_residual_variables
The aux variables to save the primary residual contributions to.
bool _has_primary_jacobians_saved_in
Whether there are primary jacobian aux variables.
InterfaceKernel and VectorInterfaceKernel is responsible for interfacing physics across subdomains.
virtual void computeElementOffDiagJacobian(unsigned int jvar) override
Selects the correct Jacobian type and routine to call for the primary variable jacobian.
virtual void computeResidualAndJacobian() override
Computes the residual and Jacobian for the current side.
virtual void computeOffDiagElemNeighJacobian(Moose::DGJacobianType type, unsigned int jvar)
Using the passed DGJacobian type, selects the correct test function and trial function spaces and jac...
virtual void computeElemNeighResidual(Moose::DGResidualType type)
Using the passed DGResidual type, selects the correct test function space and residual block,...
virtual void computeResidual() override
Computes the residual for the current side.
static InputParameters validParams()
InterfaceKernelTempl(const InputParameters &parameters)
MooseVariableFE< T > & _var
The primary side MooseVariable.
virtual void computeNeighborOffDiagJacobian(unsigned int jvar) override
Selects the correct Jacobian type and routine to call for the secondary variable jacobian.
const MooseVariableFE< T > & _neighbor_var
Coupled neighbor variable.
virtual void computeElemNeighJacobian(Moose::DGJacobianType type)
Using the passed DGJacobian type, selects the correct test function and trial function spaces and jac...
virtual void computeJacobian() override
Computes the jacobian for the current side.
const InputParameters & parameters() const
Get the parameters of the object.
Definition MooseBase.h:131
const std::string & name() const
Get the name of the class.
Definition MooseBase.h:103
const libMesh::FEType & feType() const
Get the type of finite element object.
SystemBase & sys()
Get the system this variable is part of.
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.
unsigned int size() const
Return the number of active items in the MultiMooseEnum.
Enhances MooseVariableInterface interface provide values from neighbor elements.
THREAD_ID _tid
The thread ID for this kernel.
SubProblem & _subproblem
Reference to this kernel's SubProblem.
SystemBase & _sys
Reference to the EquationSystem object.
virtual MooseVariable & getStandardVariable(const THREAD_ID tid, const std::string &var_name)=0
Returns the variable reference for requested MooseVariable which may be in any system.
virtual void addVariableToZeroOnJacobian(std::string var_name)
Adds this variable to the list of variables to be zeroed during each Jacobian evaluation.
Definition SystemBase.C:181
virtual void addVariableToZeroOnResidual(std::string var_name)
Adds this variable to the list of variables to be zeroed during each residual evaluation.
Definition SystemBase.C:175
virtual bool hasVariable(const std::string &var_name) const
Query a system for a variable.
Definition SystemBase.C:850
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