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"
25template <
typename OutputType>
30 const QBase *
const & qrule_in,
31 const QBase *
const & qrule_face_in,
32 const Node *
const & node,
33 const Elem *
const & elem)
37 _fe_type(var.feType()),
38 _var_num(var.number()),
39 _assembly(_subproblem.assembly(_tid, var.kind() ==
Moose::VAR_SOLVER ? sys.number() : 0)),
40 _element_type(element_type),
42 _has_dof_indices(false),
44 _qrule_face(qrule_face_in),
45 _use_dual(var.useDual()),
46 _second_phi_assembly_method(nullptr),
47 _second_phi_face_assembly_method(nullptr),
48 _curl_phi_assembly_method(nullptr),
49 _curl_phi_face_assembly_method(nullptr),
50 _div_phi_assembly_method(nullptr),
51 _div_phi_face_assembly_method(nullptr),
52 _ad_grad_phi_assembly_method(nullptr),
53 _ad_grad_phi_face_assembly_method(nullptr),
54 _time_integrator(nullptr),
57 _displaced(dynamic_cast<const
DisplacedSystem *>(&_sys) ? true : false),
58 _current_side(_assembly.side())
67 const auto old_do = ADReal::do_derivatives;
68 ADReal::do_derivatives =
true;
70 ADReal::do_derivatives = old_do;
138template <
typename OutputType>
146 _current_qrule = _qrule;
148 _current_grad_phi = _grad_phi;
149 _current_second_phi = _second_phi;
150 _current_curl_phi = _curl_phi;
151 _current_div_phi = _div_phi;
152 _current_ad_grad_phi = _ad_grad_phi;
157 _current_qrule = _qrule_face;
158 _current_phi = _phi_face;
159 _current_grad_phi = _grad_phi_face;
160 _current_second_phi = _second_phi_face;
161 _current_curl_phi = _curl_phi_face;
162 _current_div_phi = _div_phi_face;
163 _current_ad_grad_phi = _ad_grad_phi_face;
169template <
typename OutputType>
173 if (_sys.solutionUDot())
179 mooseError(
"MooseVariableFE: Time derivative of solution (`u_dot`) is not stored. Please set "
180 "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
183template <
typename OutputType>
187 if (_sys.solutionUDotDot())
189 _need_u_dotdot =
true;
193 mooseError(
"MooseVariableFE: Second time derivative of solution (`u_dotdot`) is not stored. "
194 "Please set uDotDotRequested() to true in FEProblemBase before requesting "
198template <
typename OutputType>
202 if (_sys.solutionUDotOld())
204 _need_u_dot_old =
true;
208 mooseError(
"MooseVariableFE: Old time derivative of solution (`u_dot_old`) is not stored. "
209 "Please set uDotOldRequested() to true in FEProblemBase before requesting "
213template <
typename OutputType>
217 if (_sys.solutionUDotDotOld())
219 _need_u_dotdot_old =
true;
220 return _u_dotdot_old;
223 mooseError(
"MooseVariableFE: Old second time derivative of solution (`u_dotdot_old`) is not "
224 "stored. Please set uDotDotOldRequested() to true in FEProblemBase before "
225 "requesting `u_dotdot_old`");
228template <
typename OutputType>
232 if (_sys.solutionUDot())
234 _need_grad_dot =
true;
238 mooseError(
"MooseVariableFE: Time derivative of solution (`u_dot`) is not stored. Please set "
239 "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
242template <
typename OutputType>
246 if (_sys.solutionUDotDot())
248 _need_grad_dotdot =
true;
249 return _grad_u_dotdot;
252 mooseError(
"MooseVariableFE: Second time derivative of solution (`u_dotdot`) is not stored. "
253 "Please set uDotDotRequested() to true in FEProblemBase before requesting "
257template <
typename OutputType>
273 _need_second_old =
true;
274 return _second_u_old;
279 _need_second_older =
true;
280 return _second_u_older;
285 _need_second_previous_nl =
true;
286 return _second_u_previous_nl;
296template <
typename OutputType>
312 _need_curl_old =
true;
318 _need_curl_older =
true;
319 return _curl_u_older;
323 mooseError(
"We don't currently support curl from the previous non-linear iteration");
327template <
typename OutputType>
343 _need_div_old =
true;
349 _need_div_older =
true;
354 mooseError(
"We don't currently support divergence from the previous non-linear iteration");
358template <
typename OutputType>
362 _second_phi = &_second_phi_assembly_method(_assembly, _fe_type);
366template <
typename OutputType>
370 _second_phi_face = &_second_phi_face_assembly_method(_assembly, _fe_type);
371 return *_second_phi_face;
374template <
typename OutputType>
378 _curl_phi = &_curl_phi_assembly_method(_assembly, _fe_type);
382template <
typename OutputType>
386 _curl_phi_face = &_curl_phi_face_assembly_method(_assembly, _fe_type);
387 return *_curl_phi_face;
390template <
typename OutputType>
394 _div_phi = &_div_phi_assembly_method(_assembly, _fe_type);
398template <
typename OutputType>
402 _div_phi_face = &_div_phi_face_assembly_method(_assembly, _fe_type);
403 return *_div_phi_face;
406template <
typename OutputType>
407template <
bool constant_monomial,
408 typename DestinationType,
410 typename DofValuesType>
414 const DofValuesType & dof_values,
415 const unsigned int nqp,
416 const std::size_t num_shapes)
418 if constexpr (constant_monomial)
419 libmesh_ignore(num_shapes);
422 constexpr bool is_real = std::is_same_v<OutputType, Real>;
423 constexpr bool is_real_vector = std::is_same_v<OutputType, RealVectorValue>;
424 constexpr bool is_eigen = std::is_same_v<OutputType, RealEigenVector>;
425 static_assert(is_real || is_real_vector || is_eigen,
"Unsupported type");
428 if constexpr (!is_eigen)
429 libmesh_ignore(
this);
432 using dest_array_type =
typename std::remove_reference_t<
decltype(dest)>::value_type;
433 constexpr bool is_value =
434 std::is_same_v<dest_array_type, OutputType> ||
435 std::is_same_v<dest_array_type, typename Moose::ADType<OutputType>::type>;
436 constexpr bool is_gradient =
437 std::is_same_v<dest_array_type, OutputGradient> ||
438 std::is_same_v<dest_array_type, typename Moose::ADType<OutputGradient>::type>;
439 constexpr bool is_second =
440 std::is_same_v<dest_array_type, OutputSecond> ||
441 std::is_same_v<dest_array_type, typename Moose::ADType<OutputSecond>::type>;
442 constexpr bool is_divergence =
443 std::is_same_v<dest_array_type, OutputDivergence> ||
444 std::is_same_v<dest_array_type, typename Moose::ADType<OutputDivergence>::type>;
445 static_assert(is_value || is_gradient || is_second || is_divergence,
446 "Unsupported destination array type");
449 const auto set_zero = [
this, &dest](
const auto qp)
451 if constexpr (!is_eigen)
452 libmesh_ignore(
this);
454 if constexpr (is_real || is_real_vector)
456 else if constexpr (is_eigen)
458 if constexpr (is_value)
459 dest[qp].setZero(this->_count);
460 else if constexpr (is_gradient)
461 dest[qp].setZero(this->_count, LIBMESH_DIM);
462 else if constexpr (is_second)
463 dest[qp].setZero(this->_count, LIBMESH_DIM * LIBMESH_DIM);
465 static_assert(Moose::always_false<OutputType, dest_array_type>,
"Unsupported type");
468 static_assert(Moose::always_false<OutputType, dest_array_type>,
"Unsupported type");
472 const auto accumulate = [&dest, &phi, &dof_values](
const auto i,
const auto qp)
474 if constexpr (is_real || is_real_vector || (is_eigen && is_value))
476 if constexpr (is_value || is_divergence)
477 dest[qp] += phi[i][qp] * dof_values[i];
478 else if constexpr (is_gradient || is_second)
479 dest[qp].add_scaled(phi[i][qp], dof_values[i]);
481 static_assert(Moose::always_false<OutputType, dest_array_type>,
"Unsupported type");
483 else if constexpr (is_eigen)
485 if constexpr (is_gradient)
488 dest[qp].col(d) += phi[i][qp](d) * dof_values[i];
490 else if constexpr (is_second)
492 for (
unsigned int d = 0, d1 = 0; d1 < LIBMESH_DIM; ++d1)
494 dest[qp].col(d++) += phi[i][qp](d1, d2) * dof_values[i];
497 static_assert(Moose::always_false<OutputType, dest_array_type>,
"Unsupported type");
500 static_assert(Moose::always_false<OutputType, dest_array_type>,
"Unsupported type");
506 if constexpr (constant_monomial)
508 mooseAssert(num_shapes == 1,
"Should have only one shape function for a constant monomial");
511 for (
unsigned int qp = 1; qp < nqp; ++qp)
517 for (
const auto qp : make_range(nqp))
519 for (
const auto i : make_range(num_shapes))
520 for (
const auto qp : make_range(nqp))
525template <
typename OutputType>
526template <
bool constant_monomial>
530 const auto num_dofs = _dof_indices.size();
531 const auto num_shapes = num_dofs / _count;
536 const bool is_transient = _subproblem.isTransient();
537 const auto nqp = _current_qrule->n_points();
538 const auto & active_coupleable_matrix_tags =
539 _subproblem.getActiveFEVariableCoupleableMatrixTags(_tid);
542 if constexpr (std::is_same_v<OutputType, RealEigenVector>)
544 if (_qrule == _current_qrule)
546 _mapped_grad_phi.resize(num_shapes);
547 for (
const auto i : make_range(num_shapes))
549 _mapped_grad_phi[i].resize(nqp, Eigen::Map<RealDIMValue>(
nullptr));
550 for (
const auto qp : make_range(nqp))
552 new (&_mapped_grad_phi[i][qp])
553 Eigen::Map<RealDIMValue>(
const_cast<Real *
>(&(*_current_grad_phi)[i][qp](0)));
558 _mapped_grad_phi_face.resize(num_shapes);
559 for (
const auto i : make_range(num_shapes))
561 _mapped_grad_phi_face[i].resize(nqp, Eigen::Map<RealDIMValue>(
nullptr));
562 for (
const auto qp : make_range(nqp))
564 new (&_mapped_grad_phi_face[i][qp])
565 Eigen::Map<RealDIMValue>(
const_cast<Real *
>(&(*_current_grad_phi)[i][qp](0)));
571 !(_need_second || _need_second_old || _need_second_older || _need_second_previous_nl) ||
573 "We're requiring a second calculation but have not set a second shape function!");
574 mooseAssert(!(_need_curl || _need_curl_old) || _current_curl_phi,
575 "We're requiring a curl calculation but have not set a curl shape function!");
576 mooseAssert(!(_need_div || _need_div_old) || _current_div_phi,
577 "We're requiring a divergence calculation but have not set a div shape function!");
581 fill<constant_monomial>(
582 _curl_u, *_current_curl_phi, _vector_tags_dof_u[_solution_tag], nqp, num_shapes);
583 if (is_transient && _need_curl_old)
584 fill<constant_monomial>(
585 _curl_u_old, *_current_curl_phi, _vector_tags_dof_u[_old_solution_tag], nqp, num_shapes);
589 fill<constant_monomial>(
590 _div_u, *_current_div_phi, _vector_tags_dof_u[_solution_tag], nqp, num_shapes);
591 if (is_transient && _need_div_old)
592 fill<constant_monomial>(
593 _div_u_old, *_current_div_phi, _vector_tags_dof_u[_old_solution_tag], nqp, num_shapes);
597 fill<constant_monomial>(
598 _second_u, *_current_second_phi, _vector_tags_dof_u[_solution_tag], nqp, num_shapes);
599 if (_need_second_previous_nl)
600 fill<constant_monomial>(_second_u_previous_nl,
601 *_current_second_phi,
602 _vector_tags_dof_u[_previous_nl_solution_tag],
607 for (
auto tag : _required_vector_tags)
609 if (_need_vector_tag_u[tag] && _sys.hasVector(tag))
611 mooseAssert(_sys.getVector(tag).closed(),
"Vector should be closed");
612 fill<constant_monomial>(
613 _vector_tag_u[tag], *_current_phi, _vector_tags_dof_u[tag], nqp, num_shapes);
615 if (_need_vector_tag_grad[tag] && _sys.hasVector(tag))
617 mooseAssert(_sys.getVector(tag).closed(),
"Vector should be closed");
618 fill<constant_monomial>(
619 _vector_tag_grad[tag], *_current_grad_phi, _vector_tags_dof_u[tag], nqp, num_shapes);
624 for (
auto tag : active_coupleable_matrix_tags)
625 if (_need_matrix_tag_u[tag])
626 fill<constant_monomial>(
627 _matrix_tag_u[tag], *_current_phi, _matrix_tags_dof_u[tag], nqp, num_shapes);
632 if (_need_second_old)
633 fill<constant_monomial>(_second_u_old,
634 *_current_second_phi,
635 _vector_tags_dof_u[_old_solution_tag],
638 if (_need_second_older)
639 fill<constant_monomial>(_second_u_older,
640 *_current_second_phi,
641 _vector_tags_dof_u[_older_solution_tag],
645 fill<constant_monomial>(_u_dot, *_current_phi, _dof_values_dot, nqp, num_shapes);
647 fill<constant_monomial>(_u_dotdot, *_current_phi, _dof_values_dotdot, nqp, num_shapes);
649 fill<constant_monomial>(_u_dot_old, *_current_phi, _dof_values_dot_old, nqp, num_shapes);
650 if (_need_u_dotdot_old)
651 fill<constant_monomial>(
652 _u_dotdot_old, *_current_phi, _dof_values_dotdot_old, nqp, num_shapes);
656 _du_dot_du.resize(nqp);
657 for (
const auto i : make_range(num_shapes))
658 for (
const auto qp : make_range(nqp))
659 _du_dot_du[qp] = _dof_du_dot_du[i];
661 if (_need_du_dotdot_du)
663 _du_dotdot_du.resize(nqp);
664 for (
const auto i : make_range(num_shapes))
665 for (
const auto qp : make_range(nqp))
666 _du_dotdot_du[qp] = _dof_du_dotdot_du[i];
670 fill<constant_monomial>(_grad_u_dot, *_current_grad_phi, _dof_values_dot, nqp, num_shapes);
671 if (_need_grad_dotdot)
672 fill<constant_monomial>(
673 _grad_u_dotdot, *_current_grad_phi, _dof_values_dotdot, nqp, num_shapes);
677 computeAD<constant_monomial>(num_dofs, nqp);
680template <
typename OutputType>
684 computeValuesInternal<
false>();
687template <
typename OutputType>
691 if (_dof_indices.size() == 0)
695 if (_elem->p_level())
698 computeValuesInternal<
true>();
701template <
typename OutputType>
705 const auto num_dofs = _dof_indices.size();
709 _ad_dof_values.resize(num_dofs);
710 for (
const auto i : make_range(num_dofs))
711 _ad_dof_values[i] = _vector_tags_dof_u[_solution_tag][i];
714 for (
const auto i : make_range(num_dofs))
717 const bool is_transient = _subproblem.isTransient();
718 if (is_transient && _need_ad_u_dot)
720 _ad_dofs_dot.resize(num_dofs);
721 if (_need_ad_u_dotdot)
722 _ad_dofs_dotdot.resize(num_dofs);
724 if (_time_integrator)
726 if (_time_integrator->dt())
728 for (
const auto i : make_range(num_dofs))
729 _ad_dofs_dot[i] = _ad_dof_values[i];
730 for (
const auto i : make_range(num_dofs))
731 _time_integrator->computeADTimeDerivatives(_ad_dofs_dot[i],
733 _need_ad_u_dotdot ? _ad_dofs_dotdot[i]
738 for (
const auto i : make_range(num_dofs))
740 _ad_dofs_dot[i] = 0.;
741 if (_need_ad_u_dotdot)
742 _ad_dofs_dotdot[i] = 0;
748 for (
const auto i : make_range(num_dofs))
750 _ad_dofs_dot[i] = _dof_values_dot[i];
751 if (_need_ad_u_dotdot)
752 _ad_dofs_dotdot[i] = _dof_values_dotdot[i];
761 const auto num_dofs = _dof_indices.size();
764 const auto n_test = num_dofs / _count;
765 mooseAssert(num_dofs == _count * n_test,
766 "Our assertions around number of dofs, test functions, and count are incorrect");
768 _ad_dof_values.resize(n_test);
770 for (
const auto i : make_range(n_test))
772 _ad_dof_values[i].resize(_count);
773 for (
const auto j : make_range(_count))
775 auto & dual_number = _ad_dof_values[i](j);
776 const auto global_dof_index = _dof_indices[j * n_test + i];
777 dual_number = (*_sys.currentSolution())(global_dof_index);
785template <
typename OutputType>
786template <
bool constant_monomial>
791 const auto n_test = num_dofs / _count;
795 fill<constant_monomial>(_ad_u, *_current_phi, _ad_dof_values, nqp, n_test);
802 if (_displaced && _current_ad_grad_phi)
803 fill<constant_monomial>(_ad_grad_u, *_current_ad_grad_phi, _ad_dof_values, nqp, n_test);
805 fill<constant_monomial>(_ad_grad_u, *_current_grad_phi, _ad_dof_values, nqp, n_test);
808 if constexpr (std::is_same_v<OutputType, Real>)
809 if (_need_ad_second_u)
810 fill<constant_monomial>(_ad_second_u, *_current_second_phi, _ad_dof_values, nqp, n_test);
813 fill<constant_monomial>(_ad_curl_u, *_current_curl_phi, _ad_dof_values, nqp, n_test);
815 const bool is_transient = _subproblem.isTransient();
820 if (_time_integrator)
821 fill<constant_monomial>(_ad_u_dot, *_current_phi, _ad_dofs_dot, nqp, n_test);
826 _ad_u_dot.resize(nqp);
827 for (
const auto qp : make_range(nqp))
828 _ad_u_dot[qp] = _u_dot[qp];
832 if (_need_ad_u_dotdot)
834 if (_time_integrator)
835 fill<constant_monomial>(_ad_u_dotdot, *_current_phi, _ad_dofs_dotdot, nqp, n_test);
838 _ad_u_dotdot.resize(nqp);
839 for (
const auto qp : make_range(nqp))
840 _ad_u_dotdot[qp] = _u_dotdot[qp];
844 if (_need_ad_grad_u_dot)
846 if (_time_integrator)
851 if (_displaced && _current_ad_grad_phi)
852 fill<constant_monomial>(_ad_grad_u_dot, *_current_ad_grad_phi, _ad_dofs_dot, nqp, n_test);
854 fill<constant_monomial>(_ad_grad_u_dot, *_current_grad_phi, _ad_dofs_dot, nqp, n_test);
858 _ad_grad_u_dot.resize(nqp);
859 for (
const auto qp : make_range(nqp))
860 _ad_grad_u_dot[qp] = _grad_u_dot[qp];
866template <
typename OutputType>
870 auto & dof_values = _vector_tags_dof_u[_solution_tag];
871 dof_values[index] = value;
872 _has_dof_values =
true;
874 auto & u = _vector_tag_u[_solution_tag];
875 const auto nqps = u.size();
876 const auto ndofs = dof_values.size();
877 for (
const auto qp : make_range(nqps))
879 for (
const auto qp : make_range(nqps))
880 for (
const auto i : make_range(ndofs))
881 u[qp] += (*_phi)[i][qp] * dof_values[i];
884template <
typename OutputType>
888 auto & dof_values = _vector_tags_dof_u[_solution_tag];
889 for (
unsigned int i = 0; i <
values.size(); i++)
890 dof_values[i] =
values(i);
892 _has_dof_values =
true;
894 auto & u = _vector_tag_u[_solution_tag];
895 const auto nqps = u.size();
896 const auto ndofs = dof_values.size();
897 for (
const auto qp : make_range(nqps))
899 for (
const auto qp : make_range(nqps))
900 for (
const auto i : make_range(ndofs))
901 u[qp] += (*_phi)[i][qp] * dof_values[i];
904template <
typename OutputType>
909 residual.set(_nodal_dof_index, v);
915 const RealEigenVector & v)
917 for (
const auto j : make_range(_count))
918 residual.set(_nodal_dof_index + j, v(j));
921template <
typename OutputType>
925 mooseAssert(_subproblem.mesh().isSemiLocal(
const_cast<Node *
>(&node)),
"Node is not Semilocal");
930 mooseAssert(node.n_dofs(_sys.number(), _var_num) > 0,
931 "Node " << node.id() <<
" does not contain any dofs for the "
932 << _sys.system().variable_name(_var_num) <<
" variable");
934 dof_id_type dof = node.dof_number(_sys.number(), _var_num, 0);
939 return (*_sys.currentSolution())(dof);
942 return _sys.solutionOld()(dof);
945 return _sys.solutionOlder()(dof);
948 mooseError(
"PreviousNL not currently supported for getNodalValue");
957 mooseAssert(_subproblem.mesh().isSemiLocal(
const_cast<Node *
>(&node)),
"Node is not Semilocal");
962 mooseAssert(node.n_dofs(_sys.number(), _var_num) > 0,
963 "Node " << node.id() <<
" does not contain any dofs for the "
964 << _sys.system().variable_name(_var_num) <<
" variable");
966 dof_id_type dof = node.dof_number(_sys.number(), _var_num, 0);
968 RealEigenVector v(_count);
972 for (
unsigned int i = 0; i < _count; ++i)
973 v(i) = (*_sys.currentSolution())(dof++);
977 for (
unsigned int i = 0; i < _count; ++i)
978 v(i) = _sys.solutionOld()(dof++);
982 for (
unsigned int i = 0; i < _count; ++i)
983 v(i) = _sys.solutionOlder()(dof++);
987 mooseError(
"PreviousNL not currently supported for getNodalValue");
992template <
typename OutputType>
996 const unsigned int idx)
const
998 static thread_local std::vector<dof_id_type> dof_indices;
999 _dof_map.dof_indices(elem, dof_indices, _var_num);
1004 return (*_sys.currentSolution())(dof_indices[idx]);
1007 return _sys.solutionOld()(dof_indices[idx]);
1010 return _sys.solutionOlder()(dof_indices[idx]);
1013 mooseError(
"PreviousNL not currently supported for getElementalValue");
1021 const unsigned int idx)
const
1024 "getElementalValue has a really bad API name. It is retrieving a value from the solution "
1025 "vector for a particular dof index. Generally speaking it has absolutely no equivalence to "
1026 "an 'elemental' value, which most people would consider to be something like an element "
1029 static thread_local std::vector<dof_id_type> dof_indices;
1030 _dof_map.array_dof_indices(elem, dof_indices, _var_num);
1031 mooseAssert(dof_indices.size() % _count == 0,
1032 "The number of array dof indices should divide cleanly by the variable count");
1033 const auto num_shapes = dof_indices.size() / _count;
1035 RealEigenVector v(_count);
1040 for (
unsigned int i = 0; i < _count; ++i)
1041 v(i) = (*_sys.currentSolution())(dof_indices[i * num_shapes + idx]);
1045 for (
unsigned int i = 0; i < _count; ++i)
1046 v(i) = _sys.solutionOld()(dof_indices[i * num_shapes + idx]);
1050 for (
unsigned int i = 0; i < _count; ++i)
1051 v(i) = _sys.solutionOlder()(dof_indices[i * num_shapes + idx]);
1055 mooseError(
"PreviousNL not currently supported for getElementalValue");
1060template <
typename OutputType>
1063 std::vector<dof_id_type> & dof_indices)
const
1065 if constexpr (std::is_same<OutputType, RealEigenVector>::value)
1066 _dof_map.array_dof_indices(elem, dof_indices, _var_num);
1068 _dof_map.dof_indices(elem, dof_indices, _var_num);
1071template <
typename OutputType>
1076 sol.add_vector(v, _dof_indices);
1079template <
typename OutputType>
1083 if (_sys.solutionUDot())
1085 _need_dof_values_dot =
true;
1086 return _dof_values_dot;
1089 mooseError(
"MooseVariableData: Time derivative of solution (`u_dot`) is not stored. Please set "
1090 "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
1093template <
typename OutputType>
1097 if (_sys.solutionUDotDot())
1099 _need_dof_values_dotdot =
true;
1100 return _dof_values_dotdot;
1103 mooseError(
"MooseVariableData: Second time derivative of solution (`u_dotdot`) is not stored. "
1104 "Please set uDotDotRequested() to true in FEProblemBase before requesting "
1108template <
typename OutputType>
1112 if (_sys.solutionUDotOld())
1114 _need_dof_values_dot_old =
true;
1115 return _dof_values_dot_old;
1118 mooseError(
"MooseVariableData: Old time derivative of solution (`u_dot_old`) is not stored. "
1119 "Please set uDotOldRequested() to true in FEProblemBase before requesting "
1123template <
typename OutputType>
1127 if (_sys.solutionUDotDotOld())
1129 _need_dof_values_dotdot_old =
true;
1130 return _dof_values_dotdot_old;
1133 mooseError(
"MooseVariableData: Old second time derivative of solution (`u_dotdot_old`) is not "
1134 "stored. Please set uDotDotOldRequested() to true in FEProblemBase before "
1135 "requesting `u_dotdot_old`.");
1138template <
typename OutputType>
1142 _need_dof_du_dot_du =
true;
1143 return _dof_du_dot_du;
1146template <
typename OutputType>
1150 _need_dof_du_dotdot_du =
true;
1151 return _dof_du_dotdot_du;
1154template <
typename OutputType>
1158 unsigned int nqp = _qrule->n_points();
1162 unsigned int num_dofs = _dof_indices.size();
1163 for (
const auto qp : make_range(nqp))
1165 _increment[qp] = 0.;
1166 for (
const auto i : make_range(num_dofs))
1167 _increment[qp] += (*_phi)[i][qp] * increment_vec(_dof_indices[i]);
1174 const NumericVector<Number> & increment_vec)
1176 unsigned int nqp = _qrule->n_points();
1178 _increment.resize(nqp);
1180 unsigned int num_dofs = _dof_indices.size();
1183 for (
const auto qp : make_range(nqp))
1185 for (
const auto i : make_range(num_dofs))
1186 for (
const auto j : make_range(_count))
1187 _increment[qp](j) += (*_phi)[i][qp] * increment_vec(_dof_indices[i] + j);
1192 for (
const auto qp : make_range(nqp))
1195 for (
const auto j : make_range(_count))
1196 for (
const auto i : make_range(num_dofs))
1198 _increment[qp](j) += (*_phi)[i][qp] * increment_vec(_dof_indices[i] + n);
1205template <
typename OutputType>
1210 mooseError(
"computeIncrementAtNode can only be called for nodal variables");
1212 _increment.resize(1);
1215 _increment[0] = increment_vec(_dof_indices[0]);
1221 const NumericVector<Number> & increment_vec)
1224 mooseError(
"computeIncrementAtNode can only be called for nodal variables");
1226 _increment.resize(1);
1230 for (
unsigned int j = 0; j < _count; j++)
1231 _increment[0](j) = increment_vec(_dof_indices[0] + j);
1235 const auto n_dof_indices = _dof_indices.size();
1236 for (
const auto j : make_range(_count))
1238 _increment[0](j) = increment_vec(_dof_indices[0] + n);
1244template <
typename OutputType>
1250 if (_sys.solutionUDot())
1252 _need_dof_values_dot =
true;
1253 return _nodal_value_dot;
1257 "MooseVariableData: Time derivative of solution (`u_dot`) is not stored. Please set "
1258 "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
1261 mooseError(
"Nodal values can be requested only on nodal variables, variable '",
1266template <
typename OutputType>
1272 if (_sys.solutionUDotDot())
1274 _need_dof_values_dotdot =
true;
1275 return _nodal_value_dotdot;
1279 "MooseVariableData: Second time derivative of solution (`u_dotdot`) is not stored. "
1280 "Please set uDotDotRequested() to true in FEProblemBase before requesting "
1284 mooseError(
"Nodal values can be requested only on nodal variables, variable '",
1289template <
typename OutputType>
1295 if (_sys.solutionUDotOld())
1297 _need_dof_values_dot_old =
true;
1298 return _nodal_value_dot_old;
1301 mooseError(
"MooseVariableData: Old time derivative of solution (`u_dot_old`) is not stored. "
1302 "Please set uDotOldRequested() to true in FEProblemBase before requesting "
1306 mooseError(
"Nodal values can be requested only on nodal variables, variable '",
1311template <
typename OutputType>
1317 if (_sys.solutionUDotDotOld())
1319 _need_dof_values_dotdot_old =
true;
1320 return _nodal_value_dotdot_old;
1324 "MooseVariableData: Old second time derivative of solution (`u_dotdot_old`) is not "
1325 "stored. Please set uDotDotOldRequested() to true in FEProblemBase before "
1326 "requesting `u_dotdot_old`.");
1329 mooseError(
"Nodal values can be requested only on nodal variables, variable '",
1334template <
typename OutputType>
1338 if (_has_dof_indices)
1346 assignADNodalValue();
1350 zeroSizeDofValues();
1353template <
typename OutputType>
1357 mooseAssert(_ad_dof_values.size(),
"The AD dof values container must have size greater than 0");
1358 _ad_nodal_value = _ad_dof_values[0];
1365 const auto num_dofs = _dof_indices.size();
1366 mooseAssert(_ad_dof_values.size() == num_dofs,
1367 "Our dof values container size should match the dof indices container size");
1368 for (
const auto i : make_range(num_dofs))
1369 _ad_nodal_value(i) = _ad_dof_values[i];
1372template <
typename OutputType>
1376 if constexpr (std::is_same<RealEigenVector, OutputType>::value)
1377 _dof_map.array_dof_indices(_elem, _dof_indices, _var_num);
1379 _dof_map.dof_indices(_elem, _dof_indices, _var_num);
1381 mooseAssert(_dof_indices.size() % _count == 0,
1382 "The number of dof indices should divide cleanly by the variable count");
1383 const auto num_shapes = _dof_indices.size() / _count;
1384 _vector_tags_dof_u[_solution_tag].resize(num_shapes);
1386 unsigned int nqp = _qrule->n_points();
1387 _vector_tag_u[_solution_tag].resize(nqp);
1390template <
typename OutputType>
1394 if constexpr (std::is_same<OutputType, RealEigenVector>::value)
1395 _dof_map.array_dof_indices(_elem, _dof_indices, _var_num);
1397 _dof_map.dof_indices(_elem, _dof_indices, _var_num);
1399 _has_dof_values =
false;
1403 _has_dof_indices = _dof_indices.size();
1406template <
typename OutputType>
1410 if constexpr (std::is_same<OutputType, RealEigenVector>::value)
1411 _dof_map.array_dof_indices(_node, _dof_indices, _var_num);
1413 _dof_map.dof_indices(_node, _dof_indices, _var_num);
1415 const auto n_dofs = _dof_indices.size();
1420 _nodal_dof_index = _dof_indices[0];
1421 _has_dof_indices =
true;
1424 _has_dof_indices =
false;
1427template <
typename OutputType>
1435 if constexpr (std::is_same<RealEigenVector, OutputType>::value)
1436 _dof_map.array_dof_indices(_elem, _dof_indices, _var_num);
1438 _dof_map.dof_indices(_elem, _dof_indices, _var_num);
1439 if (_elem->n_dofs(_sys.number(), _var_num) > 0)
1443 _nodal_dof_index = _dof_indices[0];
1447 mooseAssert(_dof_indices.size() % _count == 0,
1448 "The number of dof indices should be cleanly divisible by the variable count");
1449 const auto num_shapes = _dof_indices.size() / _count;
1450 for (
auto & dof_u : _vector_tags_dof_u)
1451 dof_u.resize(num_shapes);
1453 for (
auto & dof_u : _matrix_tags_dof_u)
1454 dof_u.resize(num_shapes);
1456 _has_dof_indices =
true;
1459 _has_dof_indices =
false;
1462 _has_dof_indices =
false;
1465template <
typename OutputType>
1469 _dof_indices.clear();
1470 for (
const auto & node_id : nodes)
1472 auto && nd = _subproblem.mesh().getMesh().query_node_ptr(node_id);
1473 if (nd && (_subproblem.mesh().isSemiLocal(
const_cast<Node *
>(nd))))
1475 if (nd->n_dofs(_sys.number(), _var_num) > 0)
1477 if constexpr (std::is_same<RealEigenVector, OutputType>::value)
1479 static thread_local std::vector<dof_id_type> dof_indices;
1480 _dof_map.array_dof_indices(nd, dof_indices, _var_num);
1481 for (
const auto dof : dof_indices)
1482 _dof_indices.push_back(dof);
1486 dof_id_type dof = nd->dof_number(_sys.number(), _var_num, 0);
1487 _dof_indices.push_back(dof);
1493 if (!_dof_indices.empty())
1494 _has_dof_indices =
true;
1496 _has_dof_indices =
false;
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
void mooseDeprecated(Args &&... args)
Emit a deprecated code/feature message with the given stringified, concatenated args.
std::array< Real, 2 > values
ShapeType
Users of this template class must specify the type of shape functions that will be used in the Jacobi...
void resize(unsigned int size)
Change the number of elements the array can store.
SystemBase & _sys
The MOOSE system which ultimately holds the vectors and matrices relevant to this variable data.
Moose::DOFType< OutputType >::type DofValue
const OutputType & nodalValueDotDot() const
void setGeometry(Moose::GeometryType gm_type)
Set the geometry type before calculating variables values.
std::function< const typename OutputTools< OutputShape >::VariablePhiSecond &(const Assembly &, libMesh::FEType)> _second_phi_assembly_method
const OutputType & nodalValueDot() const
const FieldVariableDivergence & divSln(Moose::SolutionState state) const
Local solution divergence getter.
void reinitNode()
Prepare degrees of freedom for the current node.
const FieldVariableCurl & curlSln(Moose::SolutionState state) const
Local solution curl getter.
const libMesh::FEType & _fe_type
const FieldVariablePhiDivergence & divPhiFace() const
divergence_phi_face getter
const FieldVariablePhiCurl & curlPhi() const
curl_phi getter
void setDofValue(const DofValue &value, unsigned int index)
dof value setters
const FieldVariableGradient & gradSlnDotDot() const
Local second time derivative of solution gradient getter.
void reinitNodes(const std::vector< dof_id_type > &nodes)
Set _dof_indices to the degrees of freedom existing on the passed-in nodes.
const FieldVariableValue & uDotDot() const
void computeConstantMonomialValues()
compute the values for const monomial variables
std::function< const typename OutputTools< OutputShape >::VariablePhiSecond &(const Assembly &, libMesh::FEType)> _second_phi_face_assembly_method
std::function< const typename OutputTools< OutputShape >::VariablePhiDivergence &(const Assembly &, libMesh::FEType)> _div_phi_face_assembly_method
const FieldVariableGradient & gradSlnDot() const
Local time derivative of solution gradient getter.
std::function< const typename OutputTools< OutputShape >::VariablePhiCurl &(const Assembly &, libMesh::FEType)> _curl_phi_face_assembly_method
const FieldVariableValue & uDotOld() const
const FieldVariablePhiGradient * _grad_phi_face
void computeIncrementAtQps(const libMesh::NumericVector< libMesh::Number > &increment_vec)
Compute and store incremental change in solution at QPs based on increment_vec.
void computeIncrementAtNode(const libMesh::NumericVector< libMesh::Number > &increment_vec)
Compute and store incremental change at the current node based on increment_vec.
std::function< const ADTemplateVariablePhiGradient< OutputShape > &(const Assembly &, libMesh::FEType)> _ad_grad_phi_assembly_method
DofValue getNodalValue(const Node &node, Moose::SolutionState state) const
bool _is_nodal
if variable is nodal
const FieldVariablePhiValue * _phi
const DofValues & dofValuesDot() const
std::function< const typename OutputTools< OutputShape >::VariablePhiGradient &(const Assembly &, libMesh::FEType)> _grad_phi_assembly_method
const FieldVariablePhiValue * _phi_face
void computeNodalValues()
compute nodal things
ADReal _ad_zero
A zero AD variable.
void computeValuesInternal()
Internal method for computeValues() and computeConstantMonomialValues()
const unsigned int _var_num
const FieldVariablePhiGradient * _grad_phi
const ADTemplateVariablePhiGradient< OutputShape > * _ad_grad_phi
const FieldVariablePhiSecond & secondPhi() const
second_phi getter
std::function< const typename OutputTools< OutputShape >::VariablePhiCurl &(const Assembly &, libMesh::FEType)> _curl_phi_assembly_method
const ADTemplateVariablePhiGradient< OutputShape > * _ad_grad_phi_face
void getDofIndices(const Elem *elem, std::vector< dof_id_type > &dof_indices) const
const FieldVariablePhiDivergence & divPhi() const
divergence_phi getter
const FieldVariableSecond & secondSln(Moose::SolutionState state) const
Local solution second spatial derivative getter.
void setDofValues(const DenseVector< DofValue > &values)
Set local DOF values and evaluate the values on quadrature points.
const FieldVariableValue & uDotDotOld() const
void addSolution(libMesh::NumericVector< libMesh::Number > &sol, const DenseVector< libMesh::Number > &v) const
Add passed in local DOF values to a solution vector.
const FieldVariableValue & uDot() const
void prepare()
Get the dof indices corresponding to the current element.
std::function< const typename OutputTools< OutputShape >::VariablePhiGradient &(const Assembly &, libMesh::FEType)> _grad_phi_face_assembly_method
std::function< const ADTemplateVariablePhiGradient< OutputShape > &(const Assembly &, libMesh::FEType)> _ad_grad_phi_face_assembly_method
const MooseArray< libMesh::Number > & dofValuesDuDotDu() const
void prepareIC()
prepare the initial condition
void fill(DestinationType &dest, const ShapeType &phi, const DofValuesType &dof_values, unsigned int nqp, std::size_t num_shapes)
std::function< const typename OutputTools< OutputShape >::VariablePhiDivergence &(const Assembly &, libMesh::FEType)> _div_phi_assembly_method
const OutputType & nodalValueDotOld() const
void fetchADDofValues()
Helper method for assigning the ad_dof* arrays.
void assignADNodalValue()
Helper method for assigning nodal values from their corresponding solution values (dof values as they...
const TimeIntegrator * _time_integrator
Pointer to time integrator.
void computeValues()
compute the variable values
void reinitAux()
Prepare dof indices and solution values for elemental auxiliary variables.
DofValue getElementalValue(const Elem *elem, Moose::SolutionState state, unsigned int idx=0) const
const Assembly & _assembly
Moose::ElementType _element_type
The element type this object is storing data for. This is either Element, Neighbor,...
void insertNodalValue(libMesh::NumericVector< libMesh::Number > &residual, const DofValue &v)
Write a nodal value to the passed-in solution vector.
libMesh::FEContinuity _continuity
Continuity type of the variable.
const FieldVariablePhiCurl & curlPhiFace() const
curl_phi_face getter
const FieldVariablePhiSecond & secondPhiFace() const
second_phi_face getter
const DofValues & dofValuesDotDotOld() const
const OutputType & nodalValueDotDotOld() const
MooseVariableData(const MooseVariableFE< 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)
const DofValues & dofValuesDotOld() const
std::function< const typename OutputTools< OutputShape >::VariablePhiValue &(const Assembly &, libMesh::FEType)> _phi_face_assembly_method
void computeAD(const unsigned int num_dofs, const unsigned int nqp)
compute AD things
const DofValues & dofValuesDotDot() const
const MooseArray< libMesh::Number > & dofValuesDuDotDotDu() const
std::function< const typename OutputTools< OutputType >::VariablePhiValue &(const Assembly &, libMesh::FEType)> _phi_assembly_method
Class for stuff related to variables.
Base class for a system (of equations)
const TimeIntegrator * queryTimeIntegrator(const unsigned int var_num) const
Retrieve the time integrator that integrates the given variable's equation.
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
bool doDerivatives(const SubProblem &subproblem, const SystemBase &sys)
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
void derivInsert(SemiDynamicSparseNumberArray< Real, libMesh::dof_id_type, NWrapper< N > > &derivs, libMesh::dof_id_type index, Real value)