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 // Explicitly instantiates the three versions of the AuxKernelTempl class
356 template class AuxKernelTempl<Real>;
357 template class AuxKernelTempl<RealVectorValue>;
358 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 void compute() override
Computes the value and stores it in the solution vector.
Definition: AuxKernel.C:143
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...
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:153
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:166
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:108
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:111
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