https://mooseframework.inl.gov
MooseVariableData.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 "MooseVariableData.h"
11 #include "MooseVariableField.h"
12 #include "Assembly.h"
13 #include "MooseError.h"
14 #include "DisplacedSystem.h"
15 #include "TimeIntegrator.h"
16 #include "MooseVariableFE.h"
17 #include "MooseTypes.h"
18 
19 #include "libmesh/quadrature.h"
20 #include "libmesh/fe_base.h"
21 #include "libmesh/system.h"
22 #include "libmesh/type_n_tensor.h"
23 #include "libmesh/fe_interface.h"
24 
25 using namespace libMesh;
26 
27 template <typename OutputType>
29  SystemBase & sys,
30  THREAD_ID tid,
31  Moose::ElementType element_type,
32  const QBase * const & qrule_in,
33  const QBase * const & qrule_face_in,
34  const Node * const & node,
35  const Elem * const & elem)
36 
37  : MooseVariableDataBase<OutputType>(var, sys, tid),
38  _fe_type(var.feType()),
39  _var_num(var.number()),
40  _assembly(_subproblem.assembly(_tid, var.kind() == Moose::VAR_SOLVER ? sys.number() : 0)),
41  _element_type(element_type),
42  _ad_zero(0),
43  _need_ad_u_dot(false),
44  _need_ad_u_dotdot(false),
45  _need_second(false),
46  _need_second_old(false),
47  _need_second_older(false),
48  _need_second_previous_nl(false),
49  _need_curl(false),
50  _need_curl_old(false),
51  _need_curl_older(false),
52  _need_div(false),
53  _need_div_old(false),
54  _need_div_older(false),
55  _need_ad(false),
56  _need_ad_u(false),
57  _need_ad_grad_u(false),
58  _need_ad_grad_u_dot(false),
59  _need_ad_second_u(false),
60  _need_ad_curl_u(false),
61  _has_dof_indices(false),
62  _qrule(qrule_in),
63  _qrule_face(qrule_face_in),
64  _use_dual(var.useDual()),
65  _second_phi_assembly_method(nullptr),
66  _second_phi_face_assembly_method(nullptr),
67  _curl_phi_assembly_method(nullptr),
68  _curl_phi_face_assembly_method(nullptr),
69  _div_phi_assembly_method(nullptr),
70  _div_phi_face_assembly_method(nullptr),
71  _ad_grad_phi_assembly_method(nullptr),
72  _ad_grad_phi_face_assembly_method(nullptr),
73  _time_integrator(nullptr),
74  _node(node),
75  _elem(elem),
76  _displaced(dynamic_cast<const DisplacedSystem *>(&_sys) ? true : false),
77  _current_side(_assembly.side())
78 {
79  _continuity = FEInterface::get_continuity(_fe_type);
80 
82 
84 
85  // Initialize AD zero with zero derivatives
86  const auto old_do = ADReal::do_derivatives;
87  ADReal::do_derivatives = true;
88  _ad_zero = 0.;
89  ADReal::do_derivatives = old_do;
90 
91  switch (_element_type)
92  {
94  {
95  _phi_assembly_method = &Assembly::fePhi<OutputShape>;
96  _phi_face_assembly_method = &Assembly::fePhiFace<OutputShape>;
97  _grad_phi_assembly_method = &Assembly::feGradPhi<OutputShape>;
98  _grad_phi_face_assembly_method = &Assembly::feGradPhiFace<OutputShape>;
99  _second_phi_assembly_method = &Assembly::feSecondPhi<OutputShape>;
100  _second_phi_face_assembly_method = &Assembly::feSecondPhiFace<OutputShape>;
101  _curl_phi_assembly_method = &Assembly::feCurlPhi<OutputShape>;
102  _curl_phi_face_assembly_method = &Assembly::feCurlPhiFace<OutputShape>;
103  _div_phi_assembly_method = &Assembly::feDivPhi<OutputShape>;
104  _div_phi_face_assembly_method = &Assembly::feDivPhiFace<OutputShape>;
105  _ad_grad_phi_assembly_method = &Assembly::feADGradPhi<OutputShape>;
106  _ad_grad_phi_face_assembly_method = &Assembly::feADGradPhiFace<OutputShape>;
107 
110  break;
111  }
113  {
114  _phi_assembly_method = &Assembly::fePhiNeighbor<OutputShape>;
115  _phi_face_assembly_method = &Assembly::fePhiFaceNeighbor<OutputShape>;
116  _grad_phi_assembly_method = &Assembly::feGradPhiNeighbor<OutputShape>;
117  _grad_phi_face_assembly_method = &Assembly::feGradPhiFaceNeighbor<OutputShape>;
118  _second_phi_assembly_method = &Assembly::feSecondPhiNeighbor<OutputShape>;
119  _second_phi_face_assembly_method = &Assembly::feSecondPhiFaceNeighbor<OutputShape>;
120  _curl_phi_assembly_method = &Assembly::feCurlPhiNeighbor<OutputShape>;
121  _curl_phi_face_assembly_method = &Assembly::feCurlPhiFaceNeighbor<OutputShape>;
122  _div_phi_assembly_method = &Assembly::feDivPhiNeighbor<OutputShape>;
123  _div_phi_face_assembly_method = &Assembly::feDivPhiFaceNeighbor<OutputShape>;
124 
125  _ad_grad_phi = nullptr;
126  _ad_grad_phi_face = nullptr;
127  break;
128  }
130  {
131  if (_use_dual)
132  {
133  _phi_assembly_method = &Assembly::feDualPhiLower<OutputType>;
134  _phi_face_assembly_method = &Assembly::feDualPhiLower<OutputType>; // Place holder
135  _grad_phi_assembly_method = &Assembly::feGradDualPhiLower<OutputType>;
136  _grad_phi_face_assembly_method = &Assembly::feGradDualPhiLower<OutputType>; // Place holder
137  }
138  else
139  {
140  _phi_assembly_method = &Assembly::fePhiLower<OutputType>;
141  _phi_face_assembly_method = &Assembly::fePhiLower<OutputType>; // Place holder
142  _grad_phi_assembly_method = &Assembly::feGradPhiLower<OutputType>;
143  _grad_phi_face_assembly_method = &Assembly::feGradPhiLower<OutputType>; // Place holder
144  }
145 
146  _ad_grad_phi = nullptr;
147  _ad_grad_phi_face = nullptr;
148  break;
149  }
150  }
155 }
156 
157 template <typename OutputType>
158 void
160 {
161  switch (gm_type)
162  {
163  case Moose::Volume:
164  {
165  _current_qrule = _qrule;
166  _current_phi = _phi;
167  _current_grad_phi = _grad_phi;
168  _current_second_phi = _second_phi;
169  _current_curl_phi = _curl_phi;
170  _current_div_phi = _div_phi;
171  _current_ad_grad_phi = _ad_grad_phi;
172  break;
173  }
174  case Moose::Face:
175  {
176  _current_qrule = _qrule_face;
177  _current_phi = _phi_face;
178  _current_grad_phi = _grad_phi_face;
179  _current_second_phi = _second_phi_face;
180  _current_curl_phi = _curl_phi_face;
181  _current_div_phi = _div_phi_face;
182  _current_ad_grad_phi = _ad_grad_phi_face;
183  break;
184  }
185  }
186 }
187 
188 template <typename OutputType>
191 {
192  if (_sys.solutionUDot())
193  {
194  _need_u_dot = true;
195  return _u_dot;
196  }
197  else
198  mooseError("MooseVariableFE: Time derivative of solution (`u_dot`) is not stored. Please set "
199  "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
200 }
201 
202 template <typename OutputType>
205 {
206  if (_sys.solutionUDotDot())
207  {
208  _need_u_dotdot = true;
209  return _u_dotdot;
210  }
211  else
212  mooseError("MooseVariableFE: Second time derivative of solution (`u_dotdot`) is not stored. "
213  "Please set uDotDotRequested() to true in FEProblemBase before requesting "
214  "`u_dotdot`.");
215 }
216 
217 template <typename OutputType>
220 {
221  if (_sys.solutionUDotOld())
222  {
223  _need_u_dot_old = true;
224  return _u_dot_old;
225  }
226  else
227  mooseError("MooseVariableFE: Old time derivative of solution (`u_dot_old`) is not stored. "
228  "Please set uDotOldRequested() to true in FEProblemBase before requesting "
229  "`u_dot_old`.");
230 }
231 
232 template <typename OutputType>
235 {
236  if (_sys.solutionUDotDotOld())
237  {
238  _need_u_dotdot_old = true;
239  return _u_dotdot_old;
240  }
241  else
242  mooseError("MooseVariableFE: Old second time derivative of solution (`u_dotdot_old`) is not "
243  "stored. Please set uDotDotOldRequested() to true in FEProblemBase before "
244  "requesting `u_dotdot_old`");
245 }
246 
247 template <typename OutputType>
250 {
251  if (_sys.solutionUDot())
252  {
253  _need_grad_dot = true;
254  return _grad_u_dot;
255  }
256  else
257  mooseError("MooseVariableFE: Time derivative of solution (`u_dot`) is not stored. Please set "
258  "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
259 }
260 
261 template <typename OutputType>
264 {
265  if (_sys.solutionUDotDot())
266  {
267  _need_grad_dotdot = true;
268  return _grad_u_dotdot;
269  }
270  else
271  mooseError("MooseVariableFE: Second time derivative of solution (`u_dotdot`) is not stored. "
272  "Please set uDotDotRequested() to true in FEProblemBase before requesting "
273  "`u_dotdot`.");
274 }
275 
276 template <typename OutputType>
279 {
280  secondPhi();
281  secondPhiFace();
282  switch (state)
283  {
284  case Moose::Current:
285  {
286  _need_second = true;
287  return _second_u;
288  }
289 
290  case Moose::Old:
291  {
292  _need_second_old = true;
293  return _second_u_old;
294  }
295 
296  case Moose::Older:
297  {
298  _need_second_older = true;
299  return _second_u_older;
300  }
301 
302  case Moose::PreviousNL:
303  {
304  _need_second_previous_nl = true;
305  return _second_u_previous_nl;
306  }
307 
308  default:
309  // We should never get here but gcc requires that we have a default. See
310  // htpps://stackoverflow.com/questions/18680378/after-defining-case-for-all-enum-values-compiler-still-says-control-reaches-e
311  mooseError("Unknown SolutionState!");
312  }
313 }
314 
315 template <typename OutputType>
318 {
319  curlPhi();
320  curlPhiFace();
321  switch (state)
322  {
323  case Moose::Current:
324  {
325  _need_curl = true;
326  return _curl_u;
327  }
328 
329  case Moose::Old:
330  {
331  _need_curl_old = true;
332  return _curl_u_old;
333  }
334 
335  case Moose::Older:
336  {
337  _need_curl_older = true;
338  return _curl_u_older;
339  }
340 
341  default:
342  mooseError("We don't currently support curl from the previous non-linear iteration");
343  }
344 }
345 
346 template <typename OutputType>
349 {
350  divPhi();
351  divPhiFace();
352  switch (state)
353  {
354  case Moose::Current:
355  {
356  _need_div = true;
357  return _div_u;
358  }
359 
360  case Moose::Old:
361  {
362  _need_div_old = true;
363  return _div_u_old;
364  }
365 
366  case Moose::Older:
367  {
368  _need_div_older = true;
369  return _div_u_older;
370  }
371 
372  default:
373  mooseError("We don't currently support divergence from the previous non-linear iteration");
374  }
375 }
376 
377 template <typename OutputType>
380 {
381  _second_phi = &_second_phi_assembly_method(_assembly, _fe_type);
382  return *_second_phi;
383 }
384 
385 template <typename OutputType>
388 {
389  _second_phi_face = &_second_phi_face_assembly_method(_assembly, _fe_type);
390  return *_second_phi_face;
391 }
392 
393 template <typename OutputType>
396 {
397  _curl_phi = &_curl_phi_assembly_method(_assembly, _fe_type);
398  return *_curl_phi;
399 }
400 
401 template <typename OutputType>
404 {
405  _curl_phi_face = &_curl_phi_face_assembly_method(_assembly, _fe_type);
406  return *_curl_phi_face;
407 }
408 
409 template <typename OutputType>
412 {
413  _div_phi = &_div_phi_assembly_method(_assembly, _fe_type);
414  return *_div_phi;
415 }
416 
417 template <typename OutputType>
420 {
421  _div_phi_face = &_div_phi_face_assembly_method(_assembly, _fe_type);
422  return *_div_phi_face;
423 }
424 
425 template <typename OutputType>
426 template <bool monomial>
427 void
429 {
430  const auto num_dofs = _dof_indices.size();
431  if (num_dofs > 0)
432  fetchDoFValues();
433 
434  const bool is_transient = _subproblem.isTransient();
435  const auto nqp = _current_qrule->n_points();
436  auto && active_coupleable_matrix_tags = _subproblem.getActiveFEVariableCoupleableMatrixTags(_tid);
437 
438  // Map grad_phi using Eigen so that we can perform array operations easier
439  if constexpr (std::is_same_v<OutputType, RealEigenVector>)
440  {
441  if (_qrule == _current_qrule)
442  {
443  _mapped_grad_phi.resize(num_dofs);
444  for (const auto i : make_range(num_dofs))
445  {
446  _mapped_grad_phi[i].resize(nqp, Eigen::Map<RealDIMValue>(nullptr));
447  for (const auto qp : make_range(nqp))
448  // Note: this does NOT do any allocation. It is "reconstructing" the object in place
449  new (&_mapped_grad_phi[i][qp])
450  Eigen::Map<RealDIMValue>(const_cast<Real *>(&(*_current_grad_phi)[i][qp](0)));
451  }
452  }
453  else
454  {
455  _mapped_grad_phi_face.resize(num_dofs);
456  for (const auto i : make_range(num_dofs))
457  {
458  _mapped_grad_phi_face[i].resize(nqp, Eigen::Map<RealDIMValue>(nullptr));
459  for (const auto qp : make_range(nqp))
460  // Note: this does NOT do any allocation. It is "reconstructing" the object in place
461  new (&_mapped_grad_phi_face[i][qp])
462  Eigen::Map<RealDIMValue>(const_cast<Real *>(&(*_current_grad_phi)[i][qp](0)));
463  }
464  }
465  }
466 
467  mooseAssert(
468  !(_need_second || _need_second_old || _need_second_older || _need_second_previous_nl) ||
469  _current_second_phi,
470  "We're requiring a second calculation but have not set a second shape function!");
471  mooseAssert(!(_need_curl || _need_curl_old) || _current_curl_phi,
472  "We're requiring a curl calculation but have not set a curl shape function!");
473  mooseAssert(!(_need_div || _need_div_old) || _current_div_phi,
474  "We're requiring a divergence calculation but have not set a div shape function!");
475 
476  // Helper for filling values
477  const auto fill = [this, nqp, num_dofs](auto & dest, const auto & phi, const auto & dof_values)
478  {
479  if constexpr (monomial)
480  libmesh_ignore(num_dofs);
481 
482  // Deduce OutputType
483  constexpr bool is_real = std::is_same_v<OutputType, Real>;
484  constexpr bool is_real_vector = std::is_same_v<OutputType, RealVectorValue>;
485  constexpr bool is_eigen = std::is_same_v<OutputType, RealEigenVector>;
486  static_assert(is_real || is_real_vector || is_eigen, "Unsupported type");
487 
488  // this is only used in the RealEigenVector case to get this->_count
489  if constexpr (!is_eigen)
490  libmesh_ignore(this);
491 
492  // Deduce type of value within dest MooseArray
493  using dest_array_type = typename std::remove_reference_t<decltype(dest)>::value_type;
494  constexpr bool is_value = std::is_same_v<dest_array_type, OutputType>;
495  constexpr bool is_gradient = std::is_same_v<dest_array_type, OutputGradient>;
496  constexpr bool is_second = std::is_same_v<dest_array_type, OutputSecond>;
497  constexpr bool is_divergence = std::is_same_v<dest_array_type, OutputDivergence>;
498  static_assert(is_value || is_gradient || is_second || is_divergence,
499  "Unsupported destination array type");
500 
501  // Sets a value to zero at a quadrature point
502  const auto set_zero = [this, &dest](const auto qp)
503  {
504  if constexpr (!is_eigen)
505  libmesh_ignore(this);
506 
507  if constexpr (is_real || is_real_vector)
508  dest[qp] = 0;
509  else if constexpr (is_eigen)
510  {
511  if constexpr (is_value)
512  dest[qp].setZero(this->_count);
513  else if constexpr (is_gradient)
514  dest[qp].setZero(this->_count, LIBMESH_DIM);
515  else if constexpr (is_second)
516  dest[qp].setZero(this->_count, LIBMESH_DIM * LIBMESH_DIM);
517  else
518  static_assert(Moose::always_false<OutputType, dest_array_type>, "Unsupported type");
519  }
520  else
521  static_assert(Moose::always_false<OutputType, dest_array_type>, "Unsupported type");
522  };
523 
524  // Accumulates a value
525  const auto accumulate = [&dest, &phi, &dof_values](const auto i, const auto qp)
526  {
527  if constexpr (is_real || is_real_vector || (is_eigen && is_value))
528  {
529  if constexpr (is_value || is_divergence)
530  dest[qp] += phi[i][qp] * dof_values[i];
531  else if constexpr (is_gradient || is_second)
532  dest[qp].add_scaled(phi[i][qp], dof_values[i]);
533  else
534  static_assert(Moose::always_false<OutputType, dest_array_type>, "Unsupported type");
535  }
536  else if constexpr (is_eigen)
537  {
538  if constexpr (is_gradient)
539  {
540  for (const auto d : make_range(Moose::dim))
541  dest[qp].col(d) += phi[i][qp](d) * dof_values[i];
542  }
543  else if constexpr (is_second)
544  {
545  for (unsigned int d = 0, d1 = 0; d1 < LIBMESH_DIM; ++d1)
546  for (const auto d2 : make_range(Moose::dim))
547  dest[qp].col(d++) += phi[i][qp](d1, d2) * dof_values[i];
548  }
549  else
550  static_assert(Moose::always_false<OutputType, dest_array_type>, "Unsupported type");
551  }
552  else
553  static_assert(Moose::always_false<OutputType, dest_array_type>, "Unsupported type");
554  };
555 
556  dest.resize(nqp);
557 
558  // Monomial case, accumulate dest[0] and set dest[>0] to dest[0]
559  if constexpr (monomial)
560  {
561  mooseAssert(num_dofs == 1, "Should have only one dof");
562  set_zero(0);
563  accumulate(0, 0);
564  for (unsigned int qp = 1; qp < nqp; ++qp)
565  dest[qp] = dest[0];
566  }
567  // Non monomial case
568  else
569  {
570  for (const auto qp : make_range(nqp))
571  set_zero(qp);
572  for (const auto i : make_range(num_dofs))
573  for (const auto qp : make_range(nqp))
574  accumulate(i, qp);
575  }
576  };
577 
578  // Curl
579  if (_need_curl)
580  fill(_curl_u, *_current_curl_phi, _vector_tags_dof_u[_solution_tag]);
581  if (_need_curl_old)
582  fill(_curl_u_old, *_current_curl_phi, _vector_tags_dof_u[_old_solution_tag]);
583 
584  // Div
585  if (_need_div)
586  fill(_div_u, *_current_div_phi, _vector_tags_dof_u[_solution_tag]);
587  if (is_transient && _need_div_old)
588  fill(_div_u_old, *_current_div_phi, _vector_tags_dof_u[_old_solution_tag]);
589 
590  // Second
591  if (_need_second)
592  fill(_second_u, *_current_second_phi, _vector_tags_dof_u[_solution_tag]);
593  if (_need_second_previous_nl)
594  fill(
595  _second_u_previous_nl, *_current_second_phi, _vector_tags_dof_u[_previous_nl_solution_tag]);
596 
597  // Vector tags
598  for (auto tag : _required_vector_tags)
599  {
600  if (_need_vector_tag_u[tag] && _sys.hasVector(tag) && _sys.getVector(tag).closed())
601  fill(_vector_tag_u[tag], *_current_phi, _vector_tags_dof_u[tag]);
602  if (_need_vector_tag_grad[tag] && _sys.hasVector(tag) && _sys.getVector(tag).closed())
603  fill(_vector_tag_grad[tag], *_current_grad_phi, _vector_tags_dof_u[tag]);
604  }
605 
606  // Matrix tags
607  for (auto tag : active_coupleable_matrix_tags)
608  if (_need_matrix_tag_u[tag])
609  fill(_matrix_tag_u[tag], *_current_phi, _matrix_tags_dof_u[tag]);
610 
611  // Derivatives and old values
612  if (is_transient)
613  {
614  if (_need_second_old)
615  fill(_second_u_old, *_current_second_phi, _vector_tags_dof_u[_old_solution_tag]);
616  if (_need_second_older)
617  fill(_second_u_older, *_current_second_phi, _vector_tags_dof_u[_older_solution_tag]);
618  if (_need_u_dot)
619  fill(_u_dot, *_current_phi, _dof_values_dot);
620  if (_need_u_dotdot)
621  fill(_u_dotdot, *_current_phi, _dof_values_dotdot);
622  if (_need_u_dot_old)
623  fill(_u_dot_old, *_current_phi, _dof_values_dot_old);
624  if (_need_u_dotdot_old)
625  fill(_u_dotdot_old, *_current_phi, _dof_values_dotdot_old);
626 
627  if (_need_du_dot_du)
628  {
629  _du_dot_du.resize(nqp);
630  for (const auto qp : make_range(nqp))
631  _du_dot_du[qp] = 0.;
632  for (const auto i : make_range(num_dofs))
633  for (const auto qp : make_range(nqp))
634  _du_dot_du[qp] = _dof_du_dot_du[i];
635  }
636  if (_need_du_dotdot_du)
637  {
638  _du_dotdot_du.resize(nqp);
639  for (const auto qp : make_range(nqp))
640  _du_dotdot_du[qp] = 0.;
641  for (const auto i : make_range(num_dofs))
642  for (const auto qp : make_range(nqp))
643  _du_dotdot_du[qp] = _dof_du_dotdot_du[i];
644  }
645 
646  if (_need_grad_dot)
647  fill(_grad_u_dot, *_current_grad_phi, _dof_values_dot);
648  if (_need_grad_dotdot)
649  fill(_grad_u_dotdot, *_current_grad_phi, _dof_values_dotdot);
650  }
651 
652  // Automatic differentiation, not for eigen
653  if constexpr (!std::is_same_v<OutputType, RealEigenVector>)
654  if (_need_ad)
655  computeAD(num_dofs, nqp);
656 }
657 
658 template <typename OutputType>
659 void
661 {
662  computeValuesInternal</* monomial = */ false>();
663 }
664 
665 template <typename OutputType>
666 void
668 {
669  if (_dof_indices.size() == 0)
670  return;
671 
672  // Monomial optimizations are not appropriate after p-refinement
673  if (_elem->p_level())
674  computeValues();
675  else
676  computeValuesInternal</* monomial = */ true>();
677 }
678 
679 template <typename OutputType>
680 void
681 MooseVariableData<OutputType>::computeAD(const unsigned int num_dofs, const unsigned int nqp)
682 {
683  const bool do_derivatives = Moose::doDerivatives(_subproblem, _sys);
684 
685  _ad_dof_values.resize(num_dofs);
686  for (const auto i : make_range(num_dofs))
687  _ad_dof_values[i] = (*_sys.currentSolution())(_dof_indices[i]);
688  // NOTE! You have to do this AFTER setting the value!
689  if (do_derivatives)
690  for (const auto i : make_range(num_dofs))
691  Moose::derivInsert(_ad_dof_values[i].derivatives(), _dof_indices[i], 1.);
692 
693  if (_need_ad_u)
694  {
695  _ad_u.resize(nqp);
696  for (const auto qp : make_range(nqp))
697  _ad_u[qp] = _ad_zero;
698 
699  for (const auto i : make_range(num_dofs))
700  for (const auto qp : make_range(nqp))
701  _ad_u[qp] += _ad_dof_values[i] * (*_current_phi)[i][qp];
702  }
703 
704  if (_need_ad_grad_u)
705  {
706  _ad_grad_u.resize(nqp);
707  for (const auto qp : make_range(nqp))
708  _ad_grad_u[qp] = _ad_zero;
709 
710  // The latter check here is for handling the fact that we have not yet implemented
711  // calculation of ad_grad_phi for neighbor and neighbor-face, so if we are in that
712  // situation we need to default to using the non-ad grad_phi
713  if (_displaced && _current_ad_grad_phi)
714  for (const auto i : make_range(num_dofs))
715  for (const auto qp : make_range(nqp))
716  _ad_grad_u[qp] += _ad_dof_values[i] * (*_current_ad_grad_phi)[i][qp];
717  else
718  for (const auto i : make_range(num_dofs))
719  for (const auto qp : make_range(nqp))
720  _ad_grad_u[qp] += _ad_dof_values[i] * (*_current_grad_phi)[i][qp];
721  }
722 
723  if (_need_ad_second_u)
724  {
725  _ad_second_u.resize(nqp);
726  for (const auto qp : make_range(nqp))
727  _ad_second_u[qp] = _ad_zero;
728 
729  for (const auto i : make_range(num_dofs))
730  for (const auto qp : make_range(nqp))
731  // Note that this will not carry any derivatives with respect to displacements because
732  // those calculations have not yet been implemented in Assembly
733  _ad_second_u[qp] += _ad_dof_values[i] * (*_current_second_phi)[i][qp];
734  }
735 
736  if (_need_ad_curl_u)
737  {
738  _ad_curl_u.resize(nqp);
739  for (const auto qp : make_range(nqp))
740  _ad_curl_u[qp] = _ad_zero;
741 
742  for (const auto i : make_range(num_dofs))
743  for (const auto qp : make_range(nqp))
744  {
745  mooseAssert(_current_curl_phi,
746  "We're requiring a curl calculation but have not set a curl shape function!");
747 
748  // Note that the current version of _ad_curl_u is not yet implemented for mesh displacement
749  _ad_curl_u[qp] += _ad_dof_values[i] * (*_current_curl_phi)[i][qp];
750  }
751  }
752 
753  bool is_transient = _subproblem.isTransient();
754  if (is_transient)
755  {
756  if (_need_ad_u_dot)
757  {
758  _ad_dofs_dot.resize(num_dofs);
759  if (_need_ad_u_dotdot)
760  _ad_dofs_dotdot.resize(num_dofs);
761  _ad_u_dot.resize(nqp);
762  for (const auto qp : make_range(nqp))
763  _ad_u_dot[qp] = _ad_zero;
764 
765  if (_time_integrator && _time_integrator->dt())
766  {
767  for (const auto i : make_range(num_dofs))
768  _ad_dofs_dot[i] = _ad_dof_values[i];
769  for (const auto i : make_range(num_dofs))
770  _time_integrator->computeADTimeDerivatives(_ad_dofs_dot[i],
771  _dof_indices[i],
772  _need_ad_u_dotdot ? _ad_dofs_dotdot[i]
773  : _ad_real_dummy);
774 
775  for (const auto i : make_range(num_dofs))
776  for (const auto qp : make_range(nqp))
777  _ad_u_dot[qp] += (*_current_phi)[i][qp] * _ad_dofs_dot[i];
778  }
779  else if (!_time_integrator)
780  {
781  for (const auto i : make_range(num_dofs))
782  _ad_dofs_dot[i] = _dof_values_dot[i];
783  for (const auto qp : make_range(nqp))
784  _ad_u_dot[qp] = _u_dot[qp];
785  }
786  }
787 
788  if (_need_ad_u_dotdot)
789  {
790  _ad_u_dotdot.resize(nqp);
791  for (const auto qp : make_range(nqp))
792  _ad_u_dotdot[qp] = _ad_zero;
793 
794  if (_time_integrator && _time_integrator->dt())
795  for (const auto i : make_range(num_dofs))
796  for (const auto qp : make_range(nqp))
797  _ad_u_dotdot[qp] += (*_current_phi)[i][qp] * _ad_dofs_dotdot[i];
798  else if (!_time_integrator)
799  for (const auto qp : make_range(nqp))
800  _ad_u_dotdot[qp] = _u_dotdot[qp];
801  }
802 
803  if (_need_ad_grad_u_dot)
804  {
805  _ad_grad_u_dot.resize(nqp);
806  for (const auto qp : make_range(nqp))
807  _ad_grad_u_dot[qp] = _ad_zero;
808 
809  if (_time_integrator && _time_integrator->dt())
810  {
811  // The latter check here is for handling the fact that we have not yet implemented
812  // calculation of ad_grad_phi for neighbor and neighbor-face, so if we are in that
813  // situation we need to default to using the non-ad grad_phi
814  if (_displaced && _current_ad_grad_phi)
815  for (const auto i : make_range(num_dofs))
816  for (const auto qp : make_range(nqp))
817  _ad_grad_u_dot[qp] += _ad_dofs_dot[i] * (*_current_ad_grad_phi)[i][qp];
818  else
819  for (const auto i : make_range(num_dofs))
820  for (const auto qp : make_range(nqp))
821  _ad_grad_u_dot[qp] += _ad_dofs_dot[i] * (*_current_grad_phi)[i][qp];
822  }
823  else if (!_time_integrator)
824  for (const auto qp : make_range(nqp))
825  _ad_grad_u_dot[qp] = _grad_u_dot[qp];
826  }
827  }
828 }
829 
830 template <>
831 void
832 MooseVariableData<RealEigenVector>::computeAD(const unsigned int /*num_dofs*/,
833  const unsigned int /*nqp*/)
834 {
835  mooseError("AD for array variable has not been implemented");
836 }
837 
838 template <typename OutputType>
839 void
840 MooseVariableData<OutputType>::setDofValue(const OutputData & value, unsigned int index)
841 {
842  auto & dof_values = _vector_tags_dof_u[_solution_tag];
843  dof_values[index] = value;
844  _has_dof_values = true;
845 
846  auto & u = _vector_tag_u[_solution_tag];
847  const auto nqps = u.size();
848  const auto ndofs = dof_values.size();
849  for (const auto qp : make_range(nqps))
850  u[qp] *= 0.;
851  for (const auto qp : make_range(nqps))
852  for (const auto i : make_range(ndofs))
853  u[qp] += (*_phi)[i][qp] * dof_values[i];
854 }
855 
856 template <typename OutputType>
857 void
859 {
860  auto & dof_values = _vector_tags_dof_u[_solution_tag];
861  for (unsigned int i = 0; i < values.size(); i++)
862  dof_values[i] = values(i);
863 
864  _has_dof_values = true;
865 
866  auto & u = _vector_tag_u[_solution_tag];
867  const auto nqps = u.size();
868  const auto ndofs = dof_values.size();
869  for (const auto qp : make_range(nqps))
870  u[qp] *= 0.;
871  for (const auto qp : make_range(nqps))
872  for (const auto i : make_range(ndofs))
873  u[qp] += (*_phi)[i][qp] * dof_values[i];
874 }
875 
876 template <typename OutputType>
877 void
879  const OutputData & v)
880 {
881  residual.set(_nodal_dof_index, v);
882 }
883 
884 template <>
885 void
887  const RealEigenVector & v)
888 {
889  for (const auto j : make_range(_count))
890  residual.set(_nodal_dof_index + j, v(j));
891 }
892 
893 template <typename OutputType>
896 {
897  mooseAssert(_subproblem.mesh().isSemiLocal(const_cast<Node *>(&node)), "Node is not Semilocal");
898 
899  // Make sure that the node has DOFs
900  /* Note, this is a reproduction of an assert within libMesh::Node::dof_number, this is done to
901  * produce a better error (see misc/check_error.node_value_off_block) */
902  mooseAssert(node.n_dofs(_sys.number(), _var_num) > 0,
903  "Node " << node.id() << " does not contain any dofs for the "
904  << _sys.system().variable_name(_var_num) << " variable");
905 
906  dof_id_type dof = node.dof_number(_sys.number(), _var_num, 0);
907 
908  switch (state)
909  {
910  case Moose::Current:
911  return (*_sys.currentSolution())(dof);
912 
913  case Moose::Old:
914  return _sys.solutionOld()(dof);
915 
916  case Moose::Older:
917  return _sys.solutionOlder()(dof);
918 
919  default:
920  mooseError("PreviousNL not currently supported for getNodalValue");
921  }
922 }
923 
924 template <>
927  Moose::SolutionState state) const
928 {
929  mooseAssert(_subproblem.mesh().isSemiLocal(const_cast<Node *>(&node)), "Node is not Semilocal");
930 
931  // Make sure that the node has DOFs
932  /* Note, this is a reproduction of an assert within libMesh::Node::dof_number, this is done to
933  * produce a better error (see misc/check_error.node_value_off_block) */
934  mooseAssert(node.n_dofs(_sys.number(), _var_num) > 0,
935  "Node " << node.id() << " does not contain any dofs for the "
936  << _sys.system().variable_name(_var_num) << " variable");
937 
938  dof_id_type dof = node.dof_number(_sys.number(), _var_num, 0);
939 
940  RealEigenVector v(_count);
941  switch (state)
942  {
943  case Moose::Current:
944  for (unsigned int i = 0; i < _count; ++i)
945  v(i) = (*_sys.currentSolution())(dof++);
946  break;
947 
948  case Moose::Old:
949  for (unsigned int i = 0; i < _count; ++i)
950  v(i) = _sys.solutionOld()(dof++);
951  break;
952 
953  case Moose::Older:
954  for (unsigned int i = 0; i < _count; ++i)
955  v(i) = _sys.solutionOlder()(dof++);
956  break;
957 
958  default:
959  mooseError("PreviousNL not currently supported for getNodalValue");
960  }
961  return v;
962 }
963 
964 template <typename OutputType>
967  Moose::SolutionState state,
968  unsigned int idx) const
969 {
970  std::vector<dof_id_type> dof_indices;
971  _dof_map.dof_indices(elem, dof_indices, _var_num);
972 
973  switch (state)
974  {
975  case Moose::Current:
976  return (*_sys.currentSolution())(dof_indices[idx]);
977 
978  case Moose::Old:
979  return _sys.solutionOld()(dof_indices[idx]);
980 
981  case Moose::Older:
982  return _sys.solutionOlder()(dof_indices[idx]);
983 
984  default:
985  mooseError("PreviousNL not currently supported for getElementalValue");
986  }
987 }
988 
989 template <>
992  Moose::SolutionState state,
993  unsigned int idx) const
994 {
995  std::vector<dof_id_type> dof_indices;
996  _dof_map.dof_indices(elem, dof_indices, _var_num);
997 
998  dof_id_type dof = dof_indices[idx];
999 
1000  RealEigenVector v(_count);
1001 
1002  switch (state)
1003  {
1004  case Moose::Current:
1005  for (unsigned int i = 0; i < _count; ++i)
1006  v(i) = (*_sys.currentSolution())(dof++);
1007  break;
1008 
1009  case Moose::Old:
1010  for (unsigned int i = 0; i < _count; ++i)
1011  v(i) = _sys.solutionOld()(dof++);
1012  break;
1013 
1014  case Moose::Older:
1015  for (unsigned int i = 0; i < _count; ++i)
1016  v(i) = _sys.solutionOlder()(dof++);
1017  break;
1018 
1019  default:
1020  mooseError("PreviousNL not currently supported for getElementalValue");
1021  }
1022  return v;
1023 }
1024 
1025 template <typename OutputType>
1026 void
1028  std::vector<dof_id_type> & dof_indices) const
1029 {
1030  _dof_map.dof_indices(elem, dof_indices, _var_num);
1031 }
1032 
1033 template <typename OutputType>
1034 void
1036  const DenseVector<Number> & v) const
1037 {
1038  sol.add_vector(v, _dof_indices);
1039 }
1040 
1041 template <>
1042 void
1044  const DenseVector<Number> & v) const
1045 {
1046  unsigned int p = 0;
1047  const auto num_dofs = _dof_indices.size();
1048  for (const auto j : make_range(_count))
1049  {
1050  unsigned int inc = (isNodal() ? j : j * num_dofs);
1051  for (const auto i : make_range(num_dofs))
1052  sol.add(_dof_indices[i] + inc, v(p++));
1053  }
1054 }
1055 
1056 template <typename OutputType>
1059 {
1060  if (_sys.solutionUDot())
1061  {
1062  _need_dof_values_dot = true;
1063  return _dof_values_dot;
1064  }
1065  else
1066  mooseError("MooseVariableData: Time derivative of solution (`u_dot`) is not stored. Please set "
1067  "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
1068 }
1069 
1070 template <typename OutputType>
1073 {
1074  if (_sys.solutionUDotDot())
1075  {
1076  _need_dof_values_dotdot = true;
1077  return _dof_values_dotdot;
1078  }
1079  else
1080  mooseError("MooseVariableData: Second time derivative of solution (`u_dotdot`) is not stored. "
1081  "Please set uDotDotRequested() to true in FEProblemBase before requesting "
1082  "`u_dotdot`.");
1083 }
1084 
1085 template <typename OutputType>
1088 {
1089  if (_sys.solutionUDotOld())
1090  {
1091  _need_dof_values_dot_old = true;
1092  return _dof_values_dot_old;
1093  }
1094  else
1095  mooseError("MooseVariableData: Old time derivative of solution (`u_dot_old`) is not stored. "
1096  "Please set uDotOldRequested() to true in FEProblemBase before requesting "
1097  "`u_dot_old`.");
1098 }
1099 
1100 template <typename OutputType>
1103 {
1104  if (_sys.solutionUDotDotOld())
1105  {
1106  _need_dof_values_dotdot_old = true;
1107  return _dof_values_dotdot_old;
1108  }
1109  else
1110  mooseError("MooseVariableData: Old second time derivative of solution (`u_dotdot_old`) is not "
1111  "stored. Please set uDotDotOldRequested() to true in FEProblemBase before "
1112  "requesting `u_dotdot_old`.");
1113 }
1114 
1115 template <typename OutputType>
1116 const MooseArray<Number> &
1118 {
1119  _need_dof_du_dot_du = true;
1120  return _dof_du_dot_du;
1121 }
1122 
1123 template <typename OutputType>
1124 const MooseArray<Number> &
1126 {
1127  _need_dof_du_dotdot_du = true;
1128  return _dof_du_dotdot_du;
1129 }
1130 
1131 template <typename OutputType>
1132 void
1134 {
1135  unsigned int nqp = _qrule->n_points();
1136 
1137  _increment.resize(nqp);
1138  // Compute the increment at each quadrature point
1139  unsigned int num_dofs = _dof_indices.size();
1140  for (const auto qp : make_range(nqp))
1141  {
1142  _increment[qp] = 0.;
1143  for (const auto i : make_range(num_dofs))
1144  _increment[qp] += (*_phi)[i][qp] * increment_vec(_dof_indices[i]);
1145  }
1146 }
1147 
1148 template <>
1149 void
1151  const NumericVector<Number> & increment_vec)
1152 {
1153  unsigned int nqp = _qrule->n_points();
1154 
1155  _increment.resize(nqp);
1156  // Compute the increment at each quadrature point
1157  unsigned int num_dofs = _dof_indices.size();
1158  if (isNodal())
1159  {
1160  for (const auto qp : make_range(nqp))
1161  {
1162  for (const auto i : make_range(num_dofs))
1163  for (const auto j : make_range(_count))
1164  _increment[qp](j) += (*_phi)[i][qp] * increment_vec(_dof_indices[i] + j);
1165  }
1166  }
1167  else
1168  {
1169  for (const auto qp : make_range(nqp))
1170  {
1171  unsigned int n = 0;
1172  for (const auto j : make_range(_count))
1173  for (const auto i : make_range(num_dofs))
1174  {
1175  _increment[qp](j) += (*_phi)[i][qp] * increment_vec(_dof_indices[i] + n);
1176  n += num_dofs;
1177  }
1178  }
1179  }
1180 }
1181 
1182 template <typename OutputType>
1183 void
1185 {
1186  if (!isNodal())
1187  mooseError("computeIncrementAtNode can only be called for nodal variables");
1188 
1189  _increment.resize(1);
1190 
1191  // Compute the increment for the current DOF
1192  _increment[0] = increment_vec(_dof_indices[0]);
1193 }
1194 
1195 template <>
1196 void
1198  const NumericVector<Number> & increment_vec)
1199 {
1200  if (!isNodal())
1201  mooseError("computeIncrementAtNode can only be called for nodal variables");
1202 
1203  _increment.resize(1);
1204 
1205  // Compute the increment for the current DOF
1206  if (isNodal())
1207  for (unsigned int j = 0; j < _count; j++)
1208  _increment[0](j) = increment_vec(_dof_indices[0] + j);
1209  else
1210  {
1211  unsigned int n = 0;
1212  const auto n_dof_indices = _dof_indices.size();
1213  for (const auto j : make_range(_count))
1214  {
1215  _increment[0](j) = increment_vec(_dof_indices[0] + n);
1216  n += n_dof_indices;
1217  }
1218  }
1219 }
1220 
1221 template <typename OutputType>
1222 const OutputType &
1224 {
1225  if (isNodal())
1226  {
1227  if (_sys.solutionUDot())
1228  {
1229  _need_dof_values_dot = true;
1230  return _nodal_value_dot;
1231  }
1232  else
1233  mooseError(
1234  "MooseVariableData: Time derivative of solution (`u_dot`) is not stored. Please set "
1235  "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
1236  }
1237  else
1238  mooseError("Nodal values can be requested only on nodal variables, variable '",
1239  var().name(),
1240  "' is not nodal.");
1241 }
1242 
1243 template <typename OutputType>
1244 const OutputType &
1246 {
1247  if (isNodal())
1248  {
1249  if (_sys.solutionUDotDot())
1250  {
1251  _need_dof_values_dotdot = true;
1252  return _nodal_value_dotdot;
1253  }
1254  else
1255  mooseError(
1256  "MooseVariableData: Second time derivative of solution (`u_dotdot`) is not stored. "
1257  "Please set uDotDotRequested() to true in FEProblemBase before requesting "
1258  "`u_dotdot`.");
1259  }
1260  else
1261  mooseError("Nodal values can be requested only on nodal variables, variable '",
1262  var().name(),
1263  "' is not nodal.");
1264 }
1265 
1266 template <typename OutputType>
1267 const OutputType &
1269 {
1270  if (isNodal())
1271  {
1272  if (_sys.solutionUDotOld())
1273  {
1274  _need_dof_values_dot_old = true;
1275  return _nodal_value_dot_old;
1276  }
1277  else
1278  mooseError("MooseVariableData: Old time derivative of solution (`u_dot_old`) is not stored. "
1279  "Please set uDotOldRequested() to true in FEProblemBase before requesting "
1280  "`u_dot_old`.");
1281  }
1282  else
1283  mooseError("Nodal values can be requested only on nodal variables, variable '",
1284  var().name(),
1285  "' is not nodal.");
1286 }
1287 
1288 template <typename OutputType>
1289 const OutputType &
1291 {
1292  if (isNodal())
1293  {
1294  if (_sys.solutionUDotDotOld())
1295  {
1296  _need_dof_values_dotdot_old = true;
1297  return _nodal_value_dotdot_old;
1298  }
1299  else
1300  mooseError(
1301  "MooseVariableData: Old second time derivative of solution (`u_dotdot_old`) is not "
1302  "stored. Please set uDotDotOldRequested() to true in FEProblemBase before "
1303  "requesting `u_dotdot_old`.");
1304  }
1305  else
1306  mooseError("Nodal values can be requested only on nodal variables, variable '",
1307  var().name(),
1308  "' is not nodal.");
1309 }
1310 
1311 template <typename OutputType>
1312 void
1314 {
1315  if (_has_dof_indices)
1316  {
1317  fetchDoFValues();
1318  assignNodalValue();
1319 
1320  if (_need_ad)
1321  fetchADNodalValues();
1322  }
1323  else
1324  zeroSizeDofValues();
1325 }
1326 
1327 template <typename OutputType>
1328 void
1330 {
1331  auto n = _dof_indices.size();
1332  libmesh_assert(n);
1333  _ad_dof_values.resize(n);
1334 
1335  if (_need_ad_u_dot)
1336  _ad_dofs_dot.resize(n);
1337  if (_need_ad_u_dotdot)
1338  _ad_dofs_dotdot.resize(n);
1339 
1340  const bool do_derivatives =
1341  ADReal::do_derivatives && _sys.number() == _subproblem.currentNlSysNum();
1342 
1343  for (decltype(n) i = 0; i < n; ++i)
1344  {
1345  _ad_dof_values[i] = _vector_tags_dof_u[_solution_tag][i];
1346  if (do_derivatives)
1347  Moose::derivInsert(_ad_dof_values[i].derivatives(), _dof_indices[i], 1.);
1348  assignADNodalValue(_ad_dof_values[i], i);
1349 
1350  if (_need_ad_u_dot)
1351  {
1352  if (_time_integrator && _time_integrator->dt())
1353  {
1354  _ad_dofs_dot[i] = _ad_dof_values[i];
1355  _time_integrator->computeADTimeDerivatives(_ad_dofs_dot[i],
1356  _dof_indices[i],
1357  _need_ad_u_dotdot ? _ad_dofs_dotdot[i]
1358  : _ad_real_dummy);
1359  }
1360  // Executing something with a time derivative at initial should not put a NaN
1361  else if (_time_integrator && !_time_integrator->dt())
1362  _ad_dofs_dot[i] = 0.;
1363  else
1364  mooseError("AD nodal time derivatives not implemented for variables without a time "
1365  "integrator (auxiliary variables)");
1366  }
1367  }
1368 }
1369 
1370 template <>
1371 void
1373 {
1374  mooseError("I do not know how to support AD with array variables");
1375 }
1376 
1377 template <>
1378 void
1379 MooseVariableData<Real>::assignADNodalValue(const ADReal & value, const unsigned int &)
1380 {
1381  _ad_nodal_value = value;
1382 }
1383 
1384 template <>
1385 void
1387  const unsigned int & component)
1388 {
1389  _ad_nodal_value(component) = value;
1390 }
1391 
1392 template <typename OutputType>
1393 void
1395 {
1396  _dof_map.dof_indices(_elem, _dof_indices, _var_num);
1397  _vector_tags_dof_u[_solution_tag].resize(_dof_indices.size());
1398 
1399  unsigned int nqp = _qrule->n_points();
1400  _vector_tag_u[_solution_tag].resize(nqp);
1401 }
1402 
1403 template <typename OutputType>
1404 void
1406 {
1407  _dof_map.dof_indices(_elem, _dof_indices, _var_num);
1408  _has_dof_values = false;
1409 
1410  // FIXME: remove this when the Richard's module is migrated to use the new NodalCoupleable
1411  // interface.
1412  _has_dof_indices = _dof_indices.size();
1413 }
1414 
1415 template <typename OutputType>
1416 void
1418 {
1419  if (std::size_t n_dofs = _node->n_dofs(_sys.number(), _var_num))
1420  {
1421  _dof_indices.resize(n_dofs);
1422  for (std::size_t i = 0; i < n_dofs; ++i)
1423  _dof_indices[i] = _node->dof_number(_sys.number(), _var_num, i);
1424  // For standard variables. _nodal_dof_index is retrieved by nodalDofIndex() which is used in
1425  // NodalBC for example
1426  _nodal_dof_index = _dof_indices[0];
1427  _has_dof_indices = true;
1428  }
1429  else
1430  {
1431  _dof_indices.clear(); // Clear these so Assembly doesn't think there's dofs here
1432  _has_dof_indices = false;
1433  }
1434 }
1435 
1436 template <typename OutputType>
1437 void
1439 {
1440  /* FIXME: this method is only for elemental auxiliary variables, so
1441  * we may want to rename it */
1442  if (_elem)
1443  {
1444  _dof_map.dof_indices(_elem, _dof_indices, _var_num);
1445  if (_elem->n_dofs(_sys.number(), _var_num) > 0)
1446  {
1447  // FIXME: check if the following is equivalent with '_nodal_dof_index = _dof_indices[0];'?
1448  _nodal_dof_index = _elem->dof_number(_sys.number(), _var_num, 0);
1449 
1450  fetchDoFValues();
1451 
1452  const auto num_dofs = _dof_indices.size();
1453  for (auto & dof_u : _vector_tags_dof_u)
1454  dof_u.resize(num_dofs);
1455 
1456  for (auto & dof_u : _matrix_tags_dof_u)
1457  dof_u.resize(num_dofs);
1458 
1459  _has_dof_indices = true;
1460  }
1461  else
1462  _has_dof_indices = false;
1463  }
1464  else
1465  _has_dof_indices = false;
1466 }
1467 
1468 template <typename OutputType>
1469 void
1470 MooseVariableData<OutputType>::reinitNodes(const std::vector<dof_id_type> & nodes)
1471 {
1472  _dof_indices.clear();
1473  for (const auto & node_id : nodes)
1474  {
1475  auto && nd = _subproblem.mesh().getMesh().query_node_ptr(node_id);
1476  if (nd && (_subproblem.mesh().isSemiLocal(const_cast<Node *>(nd))))
1477  {
1478  if (nd->n_dofs(_sys.number(), _var_num) > 0)
1479  {
1480  dof_id_type dof = nd->dof_number(_sys.number(), _var_num, 0);
1481  _dof_indices.push_back(dof);
1482  }
1483  }
1484  }
1485 
1486  if (!_dof_indices.empty())
1487  _has_dof_indices = true;
1488  else
1489  _has_dof_indices = false;
1490 }
1491 
1492 template class MooseVariableData<Real>;
1493 template class MooseVariableData<RealVectorValue>;
1494 template class MooseVariableData<RealEigenVector>;
const FieldVariableDivergence & divSln(Moose::SolutionState state) const
Local solution divergence getter.
std::string name(const ElemQuality q)
const Assembly & _assembly
OutputData getNodalValue(const Node &node, Moose::SolutionState state) const
const FieldVariableValue & uDotDotOld() const
dof_id_type dof_number(const unsigned int s, const unsigned int var, const unsigned int comp) const
void computeAD(const unsigned int num_dofs, const unsigned int nqp)
compute AD things
const FieldVariablePhiCurl & curlPhi() const
curl_phi getter
void reinitNodes(const std::vector< dof_id_type > &nodes)
Set _dof_indices to the degrees of freedom existing on the passed-in nodes.
void prepare()
Get the dof indices corresponding to the current element.
Class for stuff related to variables.
void setDofValue(const OutputData &value, unsigned int index)
dof value setters
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:302
void computeValues()
compute the variable values
virtual void add_vector(const T *v, const std::vector< numeric_index_type > &dof_indices)
const FieldVariableValue & uDotDot() const
void getDofIndices(const Elem *elem, std::vector< dof_id_type > &dof_indices) const
std::function< const typename OutputTools< OutputShape >::VariablePhiCurl &(const Assembly &, libMesh::FEType)> _curl_phi_assembly_method
Moose::DOFType< OutputType >::type OutputData
const OutputType & nodalValueDotOld() const
std::function< const typename OutputTools< OutputShape >::VariablePhiCurl &(const Assembly &, libMesh::FEType)> _curl_phi_face_assembly_method
void computeIncrementAtNode(const libMesh::NumericVector< libMesh::Number > &increment_vec)
Compute and store incremental change at the current node based on increment_vec.
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
Definition: Moose.h:154
const FieldVariableValue & uDot() const
void computeMonomialValues()
compute the values for const monomial variables
MooseVariableData(const MooseVariableField< OutputType > &var, SystemBase &sys, THREAD_ID tid, Moose::ElementType element_type, const QBase *const &qrule_in, const QBase *const &qrule_face_in, const Node *const &node, const Elem *const &elem)
void computeNodalValues()
compute nodal things
const MooseArray< libMesh::Number > & dofValuesDuDotDotDu() const
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
ElementType
Definition: MooseTypes.h:763
std::function< const ADTemplateVariablePhiGradient< OutputShape > &(const Assembly &, libMesh::FEType)> _ad_grad_phi_assembly_method
Base class for a system (of equations)
Definition: SystemBase.h:84
DualNumber< Real, DNDerivativeType, true > ADReal
Definition: ADRealForward.h:46
const unsigned int _var_num
void prepareIC()
prepare the initial condition
void assignADNodalValue(const ADReal &value, const unsigned int &component)
Helper methods for assigning nodal values from their corresponding solution values (dof values as the...
const FieldVariableGradient & gradSlnDot() const
Local time derivative of solution gradient getter.
bool doDerivatives(const SubProblem &subproblem, const SystemBase &sys)
Definition: ADUtils.C:83
void setDofValues(const DenseVector< OutputData > &values)
Set local DOF values and evaluate the values on quadrature points.
unsigned int n_dofs(const unsigned int s, const unsigned int var=libMesh::invalid_uint) const
std::function< const typename OutputTools< OutputShape >::VariablePhiValue &(const Assembly &, libMesh::FEType)> _phi_face_assembly_method
OutputData getElementalValue(const Elem *elem, Moose::SolutionState state, unsigned int idx=0) const
void insertNodalValue(libMesh::NumericVector< libMesh::Number > &residual, const OutputData &v)
Write a nodal value to the passed-in solution vector.
std::function< const typename OutputTools< OutputShape >::VariablePhiSecond &(const Assembly &, libMesh::FEType)> _second_phi_face_assembly_method
void libmesh_ignore(const Args &...)
const DoFValue & dofValuesDotDotOld() const
const MooseArray< libMesh::Number > & dofValuesDuDotDu() const
const DoFValue & dofValuesDot() const
const FieldVariablePhiDivergence & divPhi() const
divergence_phi getter
dof_id_type id() const
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
void computeValuesInternal()
Internal method for computeValues() and computeMonomialValues()
const OutputType & nodalValueDot() const
const FieldVariablePhiSecond & secondPhiFace() const
second_phi_face getter
void computeIncrementAtQps(const libMesh::NumericVector< libMesh::Number > &increment_vec)
Compute and store incremental change in solution at QPs based on increment_vec.
C_ZERO
const FieldVariableGradient & gradSlnDotDot() const
Local second time derivative of solution gradient getter.
std::function< const typename OutputTools< OutputShape >::VariablePhiDivergence &(const Assembly &, libMesh::FEType)> _div_phi_face_assembly_method
libmesh_assert(ctx)
void reinitNode()
Prepare degrees of freedom for the current node.
std::function< const ADTemplateVariablePhiGradient< OutputShape > &(const Assembly &, libMesh::FEType)> _ad_grad_phi_face_assembly_method
const TimeIntegrator * _time_integrator
Pointer to time integrator.
const DoFValue & dofValuesDotDot() const
libMesh::FEContinuity _continuity
Continuity type of the variable.
Moose::ElementType _element_type
The element type this object is storing data for. This is either Element, Neighbor, or Lower.
ADReal _ad_zero
A zero AD variable.
std::function< const typename OutputTools< OutputShape >::VariablePhiGradient &(const Assembly &, libMesh::FEType)> _grad_phi_assembly_method
const ADTemplateVariablePhiGradient< OutputShape > * _ad_grad_phi
const OutputType & nodalValueDotDotOld() const
std::function< const typename OutputTools< OutputShape >::VariablePhiGradient &(const Assembly &, libMesh::FEType)> _grad_phi_face_assembly_method
const FieldVariablePhiValue * _phi_face
std::function< const typename OutputTools< OutputShape >::VariablePhiSecond &(const Assembly &, libMesh::FEType)> _second_phi_assembly_method
GeometryType
Definition: MooseTypes.h:248
const FieldVariableCurl & curlSln(Moose::SolutionState state) const
Local solution curl getter.
C_ONE
const FieldVariableValue & uDotOld() const
SolutionState
Definition: MooseTypes.h:233
const libMesh::FEType & _fe_type
const ADTemplateVariablePhiGradient< OutputShape > * _ad_grad_phi_face
const FieldVariablePhiSecond & secondPhi() const
second_phi getter
const OutputType & nodalValueDotDot() const
SystemBase & _sys
The MOOSE system which ultimately holds the vectors and matrices relevant to this variable data...
IntRange< T > make_range(T beg, T end)
virtual unsigned int size() const override final
const TimeIntegrator * queryTimeIntegrator(const unsigned int var_num) const
Retrieve the time integrator that integrates the given variable&#39;s equation.
Definition: SystemBase.C:1640
const FieldVariablePhiGradient * _grad_phi_face
void addSolution(libMesh::NumericVector< libMesh::Number > &sol, const DenseVector< libMesh::Number > &v) const
Add passed in local DOF values to a solution vector.
void derivInsert(SemiDynamicSparseNumberArray< Real, libMesh::dof_id_type, NWrapper< N >> &derivs, libMesh::dof_id_type index, Real value)
Definition: ADReal.h:21
const FieldVariablePhiCurl & curlPhiFace() const
curl_phi_face getter
Eigen::Matrix< Real, Eigen::Dynamic, 1 > RealEigenVector
Definition: MooseTypes.h:146
virtual void set(const numeric_index_type i, const T value)=0
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
const DoFValue & dofValuesDotOld() const
void setGeometry(Moose::GeometryType gm_type)
Set the geometry type before calculating variables values.
void reinitAux()
Prepare dof indices and solution values for elemental auxiliary variables.
virtual void add(const numeric_index_type i, const T value)=0
std::function< const typename OutputTools< OutputType >::VariablePhiValue &(const Assembly &, libMesh::FEType)> _phi_assembly_method
const FieldVariablePhiDivergence & divPhiFace() const
divergence_phi_face getter
const FieldVariableSecond & secondSln(Moose::SolutionState state) const
Local solution second spatial derivative getter.
bool _is_nodal
if variable is nodal
const FieldVariablePhiGradient * _grad_phi
std::function< const typename OutputTools< OutputShape >::VariablePhiDivergence &(const Assembly &, libMesh::FEType)> _div_phi_assembly_method
const FieldVariablePhiValue * _phi
unsigned int THREAD_ID
Definition: MooseTypes.h:209
unsigned int idx(const ElemType type, const unsigned int nx, const unsigned int i, const unsigned int j)
uint8_t dof_id_type