Loading [MathJax]/extensions/tex2jax.js
https://mooseframework.inl.gov
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends
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 
21 template <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 
35 template <typename T>
37  : InterfaceKernelBase(parameters),
39  false,
41  std::is_same<T, Real>::value
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"))
66  mooseError(
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  {
71  if (_save_in_strings.size() != _save_in_var_side.size())
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())
86  mooseError(
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())
96  mooseError(
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())
130  mooseError(
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())
140  mooseError(
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 
158 template <typename T>
159 void
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  {
187  Threads::spin_mutex::scoped_lock lock(_resid_vars_mutex);
188  for (const auto & var : _primary_save_in_residual_variables)
189  {
190  var->sys().solution().add_vector(_local_re, var->dofIndices());
191  }
192  }
193  else if (_has_secondary_residuals_saved_in && !is_elem)
194  {
195  Threads::spin_mutex::scoped_lock lock(_resid_vars_mutex);
196  for (const auto & var : _secondary_save_in_residual_variables)
197  var->sys().solution().add_vector(_local_re, var->dofIndicesNeighbor());
198  }
199 }
200 
201 template <typename T>
202 void
204 {
205  // in the gmsh mesh format (at least in the version 2 format) the "sideset" physical entities are
206  // associated only with the lower-dimensional geometric entity that is the boundary between two
207  // higher-dimensional element faces. It does not have a sidedness to it like the exodus format
208  // does. Consequently we may naively try to execute an interface kernel twice, one time where _var
209  // has dofs on _current_elem *AND* _neighbor_var has dofs on _neighbor_elem, and the other time
210  // where _var has dofs on _neighbor_elem and _neighbor_var has dofs on _current_elem. We only want
211  // to execute in the former case. In the future we should remove this and add some kind of "block"
212  // awareness to interface kernels to avoid all the unnecessary reinit that happens before we hit
213  // this return
214  if (!_var.activeOnSubdomain(_current_elem->subdomain_id()) ||
215  !_neighbor_var.activeOnSubdomain(_neighbor_elem->subdomain_id()))
216  return;
217 
218  precalculateResidual();
219 
220  // Compute the residual for this element
221  computeElemNeighResidual(Moose::Element);
222 
223  // Compute the residual for the neighbor
224  // This also prevents computing a residual if the neighbor variable is auxiliary
225  if (_same_system)
226  computeElemNeighResidual(Moose::Neighbor);
227 }
228 
229 template <typename T>
230 void
232 {
233  const TemplateVariableTestValue & test_space =
234  (type == Moose::ElementElement || type == Moose::ElementNeighbor) ? _test : _test_neighbor;
235  const TemplateVariableTestValue & loc_phi =
236  (type == Moose::ElementElement || type == Moose::NeighborElement) ? _phi : _phi_neighbor;
237 
238  unsigned int ivar, jvar;
239 
240  switch (type)
241  {
243  ivar = jvar = _var.number();
244  break;
246  ivar = _var.number(), jvar = _neighbor_var.number();
247  break;
249  ivar = _neighbor_var.number(), jvar = _var.number();
250  break;
252  ivar = _neighbor_var.number(), jvar = _neighbor_var.number();
253  break;
254  default:
255  mooseError("Unknown DGJacobianType ", type);
256  }
257 
258  if (type == Moose::ElementElement)
259  prepareMatrixTag(_assembly, ivar, jvar);
260  else
261  prepareMatrixTagNeighbor(_assembly, ivar, jvar, type);
262 
263  for (_qp = 0; _qp < _qrule->n_points(); _qp++)
264  {
265  initQpJacobian(type);
266  for (_i = 0; _i < test_space.size(); _i++)
267  for (_j = 0; _j < loc_phi.size(); _j++)
268  _local_ke(_i, _j) += _JxW[_qp] * _coord[_qp] * computeQpJacobian(type);
269  }
270 
271  accumulateTaggedLocalMatrix();
272 
273  // To save the diagonal of the Jacobian
274  if (_has_primary_jacobians_saved_in && type == Moose::ElementElement)
275  {
276  auto rows = _local_ke.m();
277  DenseVector<Number> diag(rows);
278  for (decltype(rows) i = 0; i < rows; i++)
279  diag(i) = _local_ke(i, i);
280 
281  Threads::spin_mutex::scoped_lock lock(_jacoby_vars_mutex);
282  for (const auto & var : _primary_save_in_jacobian_variables)
283  var->sys().solution().add_vector(diag, var->dofIndices());
284  }
285  else if (_has_secondary_jacobians_saved_in && type == Moose::NeighborNeighbor)
286  {
287  auto rows = _local_ke.m();
288  DenseVector<Number> diag(rows);
289  for (decltype(rows) i = 0; i < rows; i++)
290  diag(i) = _local_ke(i, i);
291 
292  Threads::spin_mutex::scoped_lock lock(_jacoby_vars_mutex);
293  for (const auto & var : _secondary_save_in_jacobian_variables)
294  var->sys().solution().add_vector(diag, var->dofIndicesNeighbor());
295  }
296 }
297 
298 template <typename T>
299 void
301 {
302  // in the gmsh mesh format (at least in the version 2 format) the "sideset" physical entities are
303  // associated only with the lower-dimensional geometric entity that is the boundary between two
304  // higher-dimensional element faces. It does not have a sidedness to it like the exodus format
305  // does. Consequently we may naively try to execute an interface kernel twice, one time where _var
306  // has dofs on _current_elem *AND* _neighbor_var has dofs on _neighbor_elem, and the other time
307  // where _var has dofs on _neighbor_elem and _neighbor_var has dofs on _current_elem. We only want
308  // to execute in the former case. In the future we should remove this and add some kind of "block"
309  // awareness to interface kernels to avoid all the unnecessary reinit that happens before we hit
310  // this return
311  if (!_var.activeOnSubdomain(_current_elem->subdomain_id()) ||
312  !_neighbor_var.activeOnSubdomain(_neighbor_elem->subdomain_id()))
313  return;
314 
315  precalculateJacobian();
316 
317  computeElemNeighJacobian(Moose::ElementElement);
318  if (_same_system)
319  computeElemNeighJacobian(Moose::NeighborNeighbor);
320 }
321 
322 template <typename T>
323 void
325  unsigned int jvar)
326 {
327  const TemplateVariableTestValue & test_space =
328  (type == Moose::ElementElement || type == Moose::ElementNeighbor) ? _test : _test_neighbor;
329  const TemplateVariableTestValue & loc_phi =
330  (type == Moose::ElementElement || type == Moose::NeighborElement) ? _phi : _phi_neighbor;
331 
332  unsigned int ivar;
333 
334  if (type == Moose::ElementElement || type == Moose::ElementNeighbor)
335  ivar = _var.number();
336  else
337  ivar = _neighbor_var.number();
338 
339  if (type == Moose::ElementElement)
340  prepareMatrixTag(_assembly, ivar, jvar);
341  else
342  prepareMatrixTagNeighbor(_assembly, ivar, jvar, type);
343 
344  // Prevent calling of Jacobian computation if jvar doesn't lie in the current block
345  if ((_local_ke.m() == test_space.size()) && (_local_ke.n() == loc_phi.size()))
346  for (_qp = 0; _qp < _qrule->n_points(); _qp++)
347  {
348  initQpOffDiagJacobian(type, jvar);
349  for (_i = 0; _i < test_space.size(); _i++)
350  for (_j = 0; _j < loc_phi.size(); _j++)
351  _local_ke(_i, _j) += _JxW[_qp] * _coord[_qp] * computeQpOffDiagJacobian(type, jvar);
352  }
353 
354  accumulateTaggedLocalMatrix();
355 }
356 
357 template <typename T>
358 void
360 {
361  // in the gmsh mesh format (at least in the version 2 format) the "sideset" physical entities are
362  // associated only with the lower-dimensional geometric entity that is the boundary between two
363  // higher-dimensional element faces. It does not have a sidedness to it like the exodus format
364  // does. Consequently we may naively try to execute an interface kernel twice, one time where _var
365  // has dofs on _current_elem *AND* _neighbor_var has dofs on _neighbor_elem, and the other time
366  // where _var has dofs on _neighbor_elem and _neighbor_var has dofs on _current_elem. We only want
367  // to execute in the former case. In the future we should remove this and add some kind of "block"
368  // awareness to interface kernels to avoid all the unnecessary reinit that happens before we hit
369  // this return
370  if (!_var.activeOnSubdomain(_current_elem->subdomain_id()) ||
371  !_neighbor_var.activeOnSubdomain(_neighbor_elem->subdomain_id()))
372  return;
373 
374  bool is_jvar_not_interface_var = true;
375  if (jvar == _var.number())
376  {
377  precalculateJacobian();
378  computeElemNeighJacobian(Moose::ElementElement);
379  is_jvar_not_interface_var = false;
380  }
381  if (jvar == _neighbor_var.number() && _same_system)
382  {
383  precalculateJacobian();
384  computeElemNeighJacobian(Moose::ElementNeighbor);
385  is_jvar_not_interface_var = false;
386  }
387 
388  if (is_jvar_not_interface_var)
389  {
390  precalculateOffDiagJacobian(jvar);
391  computeOffDiagElemNeighJacobian(Moose::ElementElement, jvar);
392  computeOffDiagElemNeighJacobian(Moose::ElementNeighbor, jvar);
393  }
394 }
395 
396 template <typename T>
397 void
399 {
400  // in the gmsh mesh format (at least in the version 2 format) the "sideset" physical entities are
401  // associated only with the lower-dimensional geometric entity that is the boundary between two
402  // higher-dimensional element faces. It does not have a sidedness to it like the exodus format
403  // does. Consequently we may naively try to execute an interface kernel twice, one time where _var
404  // has dofs on _current_elem *AND* _neighbor_var has dofs on _neighbor_elem, and the other time
405  // where _var has dofs on _neighbor_elem and _neighbor_var has dofs on _current_elem. We only want
406  // to execute in the former case. In the future we should remove this and add some kind of "block"
407  // awareness to interface kernels to avoid all the unnecessary reinit that happens before we hit
408  // this return
409  if (!_var.activeOnSubdomain(_current_elem->subdomain_id()) ||
410  !_neighbor_var.activeOnSubdomain(_neighbor_elem->subdomain_id()))
411  return;
412 
413  // We don't care about any contribution to the neighbor Jacobian rows if it's not in the system
414  // we are currently working with (the variable's system)
415  if (!_same_system)
416  return;
417 
418  bool is_jvar_not_interface_var = true;
419  if (jvar == _var.number())
420  {
421  precalculateJacobian();
422  computeElemNeighJacobian(Moose::NeighborElement);
423  is_jvar_not_interface_var = false;
424  }
425  if (jvar == _neighbor_var.number())
426  {
427  precalculateJacobian();
428  computeElemNeighJacobian(Moose::NeighborNeighbor);
429  is_jvar_not_interface_var = false;
430  }
431 
432  if (is_jvar_not_interface_var)
433  {
434  precalculateOffDiagJacobian(jvar);
435  computeOffDiagElemNeighJacobian(Moose::NeighborElement, jvar);
436  computeOffDiagElemNeighJacobian(Moose::NeighborNeighbor, jvar);
437  }
438 }
439 
440 template <typename T>
441 void
443 {
444  computeResidual();
445 
446  if (!isImplicit())
447  return;
448 
449  for (const auto & [ivariable, jvariable] : _fe_problem.couplingEntries(_tid, _sys.number()))
450  {
451  if (ivariable->isFV())
452  continue;
453 
454  const unsigned int ivar = ivariable->number();
455  const unsigned int jvar = jvariable->number();
456 
457  prepareShapes(jvar);
458  prepareNeighborShapes(jvar);
459 
460  if (_var.number() == ivar)
461  computeElementOffDiagJacobian(jvar);
462 
463  if (_same_system)
464  if (_neighbor_var.number() == ivar)
465  computeNeighborOffDiagJacobian(jvar);
466  }
467 }
468 
469 // Explicitly instantiates the two versions of the InterfaceKernelTempl class
470 template class InterfaceKernelTempl<Real>;
VarFieldType
Definition: MooseTypes.h:717
const libMesh::FEType & feType() const
Get the type of finite element object.
std::vector< MooseVariableFEBase * > _secondary_save_in_residual_variables
The aux variables to save the secondary contributions to.
static InputParameters validParams()
MultiMooseEnum _diag_save_in_var_side
MultiMooseEnum specifying whether jacobian save-in aux variables correspond to primary or secondary s...
Class for stuff related to variables.
Definition: Adaptivity.h:31
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:302
InterfaceKernel and VectorInterfaceKernel is responsible for interfacing physics across subdomains...
InterfaceKernelTempl(const InputParameters &parameters)
unsigned int size() const
Return the number of active items in the MultiMooseEnum.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
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...
DGResidualType
Definition: MooseTypes.h:739
THREAD_ID _tid
The thread ID for this kernel.
MultiMooseEnum _save_in_var_side
MultiMooseEnum specifying whether residual save-in aux variables correspond to primary or secondary s...
virtual const std::string & name() const
Get the name of the class.
Definition: MooseBase.h:57
bool _has_primary_jacobians_saved_in
Whether there are primary jacobian aux variables.
SystemBase & _sys
Reference to the EquationSystem object.
void registerBase(const std::string &value)
This method must be called from every base "Moose System" to create linkage with the Action System...
MooseVariableFE< T > * mooseVariable() const
Return the MooseVariableFE object that this interface acts on.
Enhances MooseVariableInterface interface provide values from neighbor elements.
const MooseVariableFE< T > & _neighbor_var
Coupled neighbor variable.
virtual void computeElementOffDiagJacobian(unsigned int jvar) override
Selects the correct Jacobian type and routine to call for the primary variable jacobian.
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
virtual void computeElemNeighResidual(Moose::DGResidualType type)
Using the passed DGResidual type, selects the correct test function space and residual block...
virtual void computeResidualAndJacobian() override
Computes the residual and Jacobian for the current side.
std::vector< MooseVariableFEBase * > _primary_save_in_jacobian_variables
The aux variables to save the diagonal Jacobian contributions of the primary variables to...
SubProblem & _subproblem
Reference to this kernel&#39;s SubProblem.
VarKindType
Framework-wide stuff.
Definition: MooseTypes.h:710
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 computeJacobian() override
Computes the jacobian for the current side.
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.
std::vector< MooseVariableFEBase * > _primary_save_in_residual_variables
The aux variables to save the primary residual contributions to.
virtual bool hasVariable(const std::string &var_name) const
Query a system for a variable.
Definition: SystemBase.C:805
DGJacobianType
Definition: MooseTypes.h:745
bool isParamSetByUser(const std::string &name) const
Method returns true if the parameter was by the user.
virtual void computeElemNeighJacobian(Moose::DGJacobianType type)
Using the passed DGJacobian type, selects the correct test function and trial function spaces and jac...
void addMooseVariableDependency(MooseVariableFieldBase *var)
Call this function to add the passed in MooseVariableFieldBase as a variable that this object depends...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
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:173
std::vector< MooseVariableFEBase * > _secondary_save_in_jacobian_variables
The aux variables to save the diagonal Jacobian contributions of the secondary variables to...
bool _has_secondary_residuals_saved_in
Whether there are secondary residual aux variables.
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_primary_residuals_saved_in
Whether there are primary residual aux variables.
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type.
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:179
const InputParameters & parameters() const
Get the parameters of the object.
InterfaceKernelBase is the base class for all InterfaceKernel type classes.
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
bool _has_secondary_jacobians_saved_in
Whether there are secondary jacobian aux variables.
MooseVariableFE< T > & _var
The primary side MooseVariable.
SystemBase & sys()
Get the system this variable is part of.
virtual void computeResidual() override
Computes the residual for the current side.
static InputParameters validParams()
virtual void computeNeighborOffDiagJacobian(unsigned int jvar) override
Selects the correct Jacobian type and routine to call for the secondary variable jacobian.
bool isParamValid(const std::string &name) const
This method returns parameters that have been initialized in one fashion or another, i.e.