https://mooseframework.inl.gov
AuxKernel.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 "AuxKernel.h"
11 
12 // local includes
13 #include "FEProblem.h"
14 #include "SubProblem.h"
15 #include "AuxiliarySystem.h"
16 #include "MooseTypes.h"
17 #include "Assembly.h"
18 #include "MortarNodalAuxKernel.h"
19 
20 #include "libmesh/numeric_vector.h"
21 #include "libmesh/dof_map.h"
22 #include "libmesh/quadrature.h"
23 #include "libmesh/boundary_info.h"
24 
25 template <typename ComputeValueType>
28 {
30 
31  if (typeid(AuxKernelTempl<ComputeValueType>).name() == typeid(VectorAuxKernel).name())
32  params.registerBase("VectorAuxKernel");
33  if (typeid(AuxKernelTempl<ComputeValueType>).name() == typeid(ArrayAuxKernel).name())
34  params.registerBase("ArrayAuxKernel");
35 
36  params.registerSystemAttributeName("AuxKernel");
37 
38  return params;
39 }
40 
41 template <typename ComputeValueType>
43  : AuxKernelBase(parameters),
44  MooseVariableInterface<ComputeValueType>(
45  this,
46  parameters.getCheckedPointerParam<SystemBase *>("_sys")
47  ->getVariable(parameters.get<THREAD_ID>("_tid"),
48  parameters.get<AuxVariableName>("variable"))
49  .isNodal(),
50  "variable",
52  std::is_same<Real, ComputeValueType>::value
54  : (std::is_same<RealVectorValue, ComputeValueType>::value
57 
58  _var(_aux_sys.getActualFieldVariable<ComputeValueType>(
59  _tid, parameters.get<AuxVariableName>("variable"))),
60  _nodal(_var.isNodal()),
61  _u(_nodal ? _var.nodalValueArray() : _var.sln()),
62 
63  _test(_bnd ? _var.phiFace() : _var.phi()),
64  _q_point(_bnd ? _assembly.qPointsFace() : _assembly.qPoints()),
65  _qrule(_bnd ? _assembly.qRuleFace() : _assembly.qRule()),
66  _JxW(_bnd ? _assembly.JxWFace() : _assembly.JxW()),
67  _coord(_assembly.coordTransformation()),
68 
69  _current_elem(_assembly.elem()),
70  _current_side(_assembly.side()),
71  _current_elem_volume(_assembly.elemVolume()),
72  _current_side_volume(_assembly.sideElemVolume()),
73 
74  _current_node(_assembly.node()),
75  _current_boundary_id(_assembly.currentBoundaryID()),
76  _solution(_aux_sys.solution()),
77 
78  _current_lower_d_elem(_assembly.lowerDElem())
79 {
80 
81  if (!_bnd || _nodal)
82  // If we're not boundary restricted then we cannot be a coincident lower-d calculation
84 }
85 
86 template <typename ComputeValueType>
87 const VariableValue &
88 AuxKernelTempl<ComputeValueType>::coupledDot(const std::string & var_name, unsigned int comp) const
89 {
90  auto var = getVar(var_name, comp);
91  if (var->kind() == Moose::VAR_AUXILIARY)
92  mooseError(
93  name(),
94  ": Unable to couple time derivative of an auxiliary variable into the auxiliary system.");
95 
96  return Coupleable::coupledDot(var_name, comp);
97 }
98 
99 template <typename ComputeValueType>
100 const VariableValue &
102  unsigned int comp) const
103 {
104  auto var = getVar(var_name, comp);
105  if (var->kind() == Moose::VAR_AUXILIARY)
106  mooseError(
107  name(),
108  ": Unable to couple time derivative of an auxiliary variable into the auxiliary system.");
109 
110  return Coupleable::coupledDotDu(var_name, comp);
111 }
112 
113 template <>
114 void
115 AuxKernelTempl<Real>::setDofValueHelper(const Real & value)
116 {
117  mooseAssert(_n_shapes == 1,
118  "Should only be calling setDofValue if there is one dof for the aux var");
119  _var.setDofValue(value, 0);
120 }
121 
122 template <>
123 void
125 {
126  mooseError("Not implemented");
127 }
128 
129 template <typename ComputeValueType>
130 void
132 {
133  mooseAssert(_coincident_lower_d_calc.has_value(),
134  "We should have set _coincident_lower_d_calc by now");
135  if (_coincident_lower_d_calc.value())
136  _var.insertLower(_aux_sys.solution());
137  else
138  _var.insert(_aux_sys.solution());
139 }
140 
141 template <typename ComputeValueType>
142 void
144 {
145  precalculateValue();
146 
147  if (isNodal()) /* nodal variables */
148  {
149  if (_var.isNodalDefined())
150  {
151  _qp = 0;
152  ComputeValueType value = computeValue();
153  // update variable data, which is referenced by other kernels, so the value is up-to-date
154  _var.setNodalValue(value);
155  }
156  }
157  else /* elemental variables */
158  {
159  _n_shapes =
160  _coincident_lower_d_calc.value() ? _var.dofIndicesLower().size() : _var.numberOfDofs();
161 
162  if (_n_shapes == 1) /* p0 */
163  {
164  ComputeValueType value = 0;
165  for (_qp = 0; _qp < _qrule->n_points(); _qp++)
166  value += _JxW[_qp] * _coord[_qp] * computeValue();
167  value /= (_bnd ? _current_side_volume : _current_elem_volume);
168  if (_var.isFV())
169  setDofValueHelper(value);
170  else
171  {
172  // update the variable data referenced by other kernels.
173  // Note that this will update the values at the quadrature points too
174  // (because this is an Elemental variable)
175  if (_coincident_lower_d_calc.value())
176  {
177  _local_sol.resize(1);
178  if constexpr (std::is_same<Real, ComputeValueType>::value)
179  _local_sol(0) = value;
180  else
181  mooseAssert(false, "We should not enter the single dof branch with a vector variable");
182  _var.setLowerDofValues(_local_sol);
183  }
184  else
185  _var.setNodalValue(value);
186  }
187  }
188  else /* high-order */
189  {
190  _local_re.resize(_n_shapes);
191  _local_re.zero();
192  _local_ke.resize(_n_shapes, _n_shapes);
193  _local_ke.zero();
194 
195  const auto & test = _coincident_lower_d_calc.value() ? _var.phiLower() : _test;
196 
197  // assemble the local mass matrix and the load
198  for (unsigned int i = 0; i < test.size(); i++)
199  for (_qp = 0; _qp < _qrule->n_points(); _qp++)
200  {
201  ComputeValueType t = _JxW[_qp] * _coord[_qp] * test[i][_qp];
202  _local_re(i) += t * computeValue();
203  for (unsigned int j = 0; j < test.size(); j++)
204  _local_ke(i, j) += t * test[j][_qp];
205  }
206  // mass matrix is always SPD but in case of boundary restricted, it will be rank deficient
207  _local_sol.resize(_n_shapes);
208  if (_bnd)
209  _local_ke.svd_solve(_local_re, _local_sol);
210  else
211  _local_ke.cholesky_solve(_local_re, _local_sol);
212 
213  _coincident_lower_d_calc.value() ? _var.setLowerDofValues(_local_sol)
214  : _var.setDofValues(_local_sol);
215  }
216  }
217 }
218 
219 template <>
220 void
222 {
223  precalculateValue();
224 
225  if (isNodal()) /* nodal variables */
226  {
227  if (_var.isNodalDefined())
228  {
229  _qp = 0;
230  RealEigenVector value = computeValue();
231  // update variable data, which is referenced by other kernels, so the value is up-to-date
232  _var.setNodalValue(value);
233  }
234  }
235  else /* elemental variables */
236  {
237  mooseAssert(
238  _var.numberOfDofs() % _var.count() == 0,
239  "The number of degrees of freedom should be cleanly divisible by the variable count");
240  _n_shapes = _var.numberOfDofs() / _var.count();
241  if (_n_shapes == 1) /* p0 */
242  {
243  RealEigenVector value = RealEigenVector::Zero(_var.count());
244  for (_qp = 0; _qp < _qrule->n_points(); _qp++)
245  value += _JxW[_qp] * _coord[_qp] * computeValue();
246  value /= (_bnd ? _current_side_volume : _current_elem_volume);
247  // update the variable data referenced by other kernels.
248  // Note that this will update the values at the quadrature points too
249  // (because this is an Elemental variable)
250  _var.setNodalValue(value);
251  }
252  else /* high-order */
253  {
254  _local_re.resize(_n_shapes);
255  for (unsigned int i = 0; i < _local_re.size(); ++i)
256  _local_re(i) = RealEigenVector::Zero(_var.count());
257  _local_ke.resize(_n_shapes, _n_shapes);
258  _local_ke.zero();
259 
260  // assemble the local mass matrix and the load
261  for (unsigned int i = 0; i < _test.size(); i++)
262  for (_qp = 0; _qp < _qrule->n_points(); _qp++)
263  {
264  Real t = _JxW[_qp] * _coord[_qp] * _test[i][_qp];
265  _local_re(i) += t * computeValue();
266  for (unsigned int j = 0; j < _test.size(); j++)
267  _local_ke(i, j) += t * _test[j][_qp];
268  }
269 
270  // mass matrix is always SPD
271  _local_sol.resize(_n_shapes);
272  for (unsigned int i = 0; i < _local_re.size(); ++i)
273  _local_sol(i) = RealEigenVector::Zero(_var.count());
274  DenseVector<Number> re(_n_shapes);
275  DenseVector<Number> sol(_n_shapes);
276  for (unsigned int i = 0; i < _var.count(); ++i)
277  {
278  for (unsigned int j = 0; j < _n_shapes; ++j)
279  re(j) = _local_re(j)(i);
280 
281  if (_bnd)
282  _local_ke.svd_solve(re, sol);
283  else
284  _local_ke.cholesky_solve(re, sol);
285 
286  for (unsigned int j = 0; j < _n_shapes; ++j)
287  _local_sol(j)(i) = sol(j);
288  }
289 
290  _var.setDofValues(_local_sol);
291  }
292  }
293 }
294 
295 template <typename ComputeValueType>
298 {
299  if (_sys.solutionStatesInitialized())
300  mooseError("The solution states have already been initialized when calling ",
301  type(),
302  "::uOld().\n\n",
303  "Make sure to call uOld() within the object constructor.");
304 
305  return _nodal ? _var.nodalValueOldArray() : _var.slnOld();
306 }
307 
308 template <typename ComputeValueType>
311 {
312  if (_sys.solutionStatesInitialized())
313  mooseError("The solution states have already been initialized when calling ",
314  type(),
315  "::uOlder().\n\n",
316  "Make sure to call uOlder() within the object constructor.");
317 
318  return _nodal ? _var.nodalValueOlderArray() : _var.slnOlder();
319 }
320 
321 template <typename ComputeValueType>
322 bool
324 {
325  return dynamic_cast<MortarNodalAuxKernelTempl<ComputeValueType> *>(this) != nullptr;
326 }
327 
328 template <typename ComputeValueType>
329 void
331 {
332  mooseAssert(_bnd && !isNodal(),
333  "We can never be a lower-dimensional calculation if we are not boundary restricted "
334  "or if we are a nodal auxiliary kernel");
335 
336  // MOOSE maintains three copies of finite element data. One is for the current canonical element,
337  // one is for the element neighbor, and one is for a lower-d element. These three copies have
338  // supported all of MOOSE's finite element use cases to date, including mortar. For AuxKernel, we
339  // do not use the neighbor data copy, but we do use the other two copies. The numberOfDofs() API
340  // returns the number of degrees of freedom for the canonical element. If there are none, then
341  // there must be degrees of freedom associated with the lower-d element
342  _coincident_lower_d_calc = !_var.numberOfDofs();
343 
344  if (_coincident_lower_d_calc.value())
345  {
346  static const std::string lower_error = "Make sure that the lower-d variable lives on a "
347  "lower-d block that is a superset of the boundary";
348  if (!_current_lower_d_elem)
349  mooseError("No lower-dimensional element. ", lower_error);
350  if (!_var.dofIndicesLower().size())
351  mooseError("No degrees of freedom. ", lower_error);
352  }
353 }
354 
355 template <typename ComputeValueType>
356 std::set<MooseVariableFieldBase *>
358  const libMesh::Node & node, const std::set<MooseVariableFieldBase *> & vars_to_check)
359 {
360  if (node.n_dofs(_var.sys().number(), _var.number()))
361  return MooseVariableDependencyInterface::checkVariables(node, vars_to_check);
362  else
363  // the aux kernel early returns if _var has no dofs
364  return {};
365 }
366 
367 // Explicitly instantiates the three versions of the AuxKernelTempl class
368 template class AuxKernelTempl<Real>;
369 template class AuxKernelTempl<RealVectorValue>;
370 template class AuxKernelTempl<RealEigenVector>;
std::string name(const ElemQuality q)
VarFieldType
Definition: MooseTypes.h:770
Base class for auxiliary kernels.
Definition: AuxKernelBase.h:42
const OutputTools< ComputeValueType >::VariableValue & uOlder() const
Retrieves the older value of the variable that this AuxKernel operates on.
Definition: AuxKernel.C:310
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311
virtual std::set< MooseVariableFieldBase * > checkVariables(const libMesh::Node &node, const std::set< MooseVariableFieldBase *> &vars_to_check)
Check whether all of the supplied variables have degree of freedom indices on the supplied node...
virtual void compute() override
Computes the value and stores it in the solution vector.
Definition: AuxKernel.C:143
virtual std::set< MooseVariableFieldBase * > checkVariables(const libMesh::Node &node, const std::set< MooseVariableFieldBase *> &vars_to_check) override
Check whether all of the supplied variables have degree of freedom indices on the supplied node...
Definition: AuxKernel.C:357
virtual const VariableValue & coupledDot(const std::string &var_name, unsigned int comp=0) const
Time derivative of a coupled variable.
Definition: Coupleable.C:1176
void registerSystemAttributeName(const std::string &value)
This method is used to define the MOOSE system name that is used by the TheWarehouse object for stori...
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
Base class for a system (of equations)
Definition: SystemBase.h:85
const bool _bnd
true if the kernel is boundary kernel, false if it is interior kernels
Definition: AuxKernelBase.h:90
void registerBase(const std::string &value)
This method must be called from every base "Moose System" to create linkage with the Action System...
unsigned int n_dofs(const unsigned int s, const unsigned int var=libMesh::invalid_uint) const
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
unsigned int _n_shapes
number of shape functions for the finite element type and current DofObject
Definition: AuxKernel.h:158
VarKindType
Framework-wide stuff.
Definition: MooseTypes.h:763
bool isMortar()
Definition: AuxKernel.C:323
AuxKernelTempl(const InputParameters &parameters)
Definition: AuxKernel.C:42
virtual const OutputTools< ComputeValueType >::VariableValue & value()
The value of the variable this object is operating on.
Base class for creating new nodally-based mortar auxiliary kernels.
std::optional< bool > _coincident_lower_d_calc
Whether we are computing for a lower dimensional variable using boundary restriction, e.g.
Definition: AuxKernel.h:171
virtual const VariableValue & coupledDot(const std::string &var_name, unsigned int comp=0) const override
Time derivative of a coupled variable.
Definition: AuxKernel.C:88
static InputParameters validParams()
Definition: AuxKernelBase.C:20
OutputTools< Real >::VariableValue VariableValue
Definition: MooseTypes.h:343
virtual const VariableValue & coupledDotDu(const std::string &var_name, unsigned int comp=0) const
Time derivative of a coupled variable with respect to the coefficients.
Definition: Coupleable.C:1474
const OutputTools< ComputeValueType >::VariableValue & uOld() const
Retrieves the old value of the variable that this AuxKernel operates on.
Definition: AuxKernel.C:297
void insert()
Insert the just computed values into the auxiliary solution vector.
Definition: AuxKernel.C:131
MooseVariableField< ComputeValueType > & _var
This is a regular kernel so we cast to a regular MooseVariable, hides base _var.
Definition: AuxKernel.h:113
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual void setDofValue(const DofValue &value, unsigned int index)=0
Degree of freedom value setters.
const bool _nodal
Flag indicating if the AuxKernel is nodal.
Definition: AuxKernel.h:116
void determineWhetherCoincidentLowerDCalc()
Determines whether we&#39;re a coincident lower-d calculation.
Definition: AuxKernel.C:330
Interface for objects that need to get values of MooseVariables.
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
Definition: MooseBase.h:281
static InputParameters validParams()
Definition: AuxKernel.C:27
Eigen::Matrix< Real, Eigen::Dynamic, 1 > RealEigenVector
Definition: MooseTypes.h:147
Base class for creating new auxiliary kernels and auxiliary boundary conditions.
Definition: AuxKernel.h:17
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
virtual const VariableValue & coupledDotDu(const std::string &var_name, unsigned int comp=0) const override
Time derivative of a coupled variable with respect to the coefficients.
Definition: AuxKernel.C:101
void setDofValueHelper(const ComputeValueType &dof_value)
Currently only used when the auxiliary variable is a finite volume variable, this helps call through ...
const Elem & get(const ElemType type_in)
unsigned int THREAD_ID
Definition: MooseTypes.h:237