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>
142 _assembly.needADGradPhiFace();
145template <
typename OutputType>
153 _current_qrule = _qrule;
155 _current_grad_phi = _grad_phi;
156 _current_second_phi = _second_phi;
157 _current_curl_phi = _curl_phi;
158 _current_div_phi = _div_phi;
159 _current_ad_grad_phi = _ad_grad_phi;
164 _current_qrule = _qrule_face;
165 _current_phi = _phi_face;
166 _current_grad_phi = _grad_phi_face;
167 _current_second_phi = _second_phi_face;
168 _current_curl_phi = _curl_phi_face;
169 _current_div_phi = _div_phi_face;
170 _current_ad_grad_phi = _ad_grad_phi_face;
176template <
typename OutputType>
180 if (_sys.solutionUDot())
186 mooseError(
"MooseVariableFE: Time derivative of solution (`u_dot`) is not stored. Please set "
187 "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
190template <
typename OutputType>
194 if (_sys.solutionUDotDot())
196 _need_u_dotdot =
true;
200 mooseError(
"MooseVariableFE: Second time derivative of solution (`u_dotdot`) is not stored. "
201 "Please set uDotDotRequested() to true in FEProblemBase before requesting "
205template <
typename OutputType>
209 if (_sys.solutionUDotOld())
211 _need_u_dot_old =
true;
215 mooseError(
"MooseVariableFE: Old time derivative of solution (`u_dot_old`) is not stored. "
216 "Please set uDotOldRequested() to true in FEProblemBase before requesting "
220template <
typename OutputType>
224 if (_sys.solutionUDotDotOld())
226 _need_u_dotdot_old =
true;
227 return _u_dotdot_old;
230 mooseError(
"MooseVariableFE: Old second time derivative of solution (`u_dotdot_old`) is not "
231 "stored. Please set uDotDotOldRequested() to true in FEProblemBase before "
232 "requesting `u_dotdot_old`");
235template <
typename OutputType>
239 if (_sys.solutionUDot())
241 _need_grad_dot =
true;
245 mooseError(
"MooseVariableFE: Time derivative of solution (`u_dot`) is not stored. Please set "
246 "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
249template <
typename OutputType>
253 if (_sys.solutionUDotDot())
255 _need_grad_dotdot =
true;
256 return _grad_u_dotdot;
259 mooseError(
"MooseVariableFE: Second time derivative of solution (`u_dotdot`) is not stored. "
260 "Please set uDotDotRequested() to true in FEProblemBase before requesting "
264template <
typename OutputType>
280 _need_second_old =
true;
281 return _second_u_old;
286 _need_second_older =
true;
287 return _second_u_older;
292 _need_second_previous_nl =
true;
293 return _second_u_previous_nl;
303template <
typename OutputType>
319 _need_curl_old =
true;
325 _need_curl_older =
true;
326 return _curl_u_older;
330 mooseError(
"We don't currently support curl from the previous non-linear iteration");
334template <
typename OutputType>
350 _need_div_old =
true;
356 _need_div_older =
true;
361 mooseError(
"We don't currently support divergence from the previous non-linear iteration");
365template <
typename OutputType>
369 _second_phi = &_second_phi_assembly_method(_assembly, _fe_type);
373template <
typename OutputType>
377 _second_phi_face = &_second_phi_face_assembly_method(_assembly, _fe_type);
378 return *_second_phi_face;
381template <
typename OutputType>
385 _curl_phi = &_curl_phi_assembly_method(_assembly, _fe_type);
389template <
typename OutputType>
393 _curl_phi_face = &_curl_phi_face_assembly_method(_assembly, _fe_type);
394 return *_curl_phi_face;
397template <
typename OutputType>
401 _div_phi = &_div_phi_assembly_method(_assembly, _fe_type);
405template <
typename OutputType>
409 _div_phi_face = &_div_phi_face_assembly_method(_assembly, _fe_type);
410 return *_div_phi_face;
413template <
typename OutputType>
414template <
bool constant_monomial,
415 typename DestinationType,
417 typename DofValuesType>
421 const DofValuesType & dof_values,
422 const unsigned int nqp,
423 const std::size_t num_shapes)
425 if constexpr (constant_monomial)
426 libmesh_ignore(num_shapes);
429 constexpr bool is_real = std::is_same_v<OutputType, Real>;
430 constexpr bool is_real_vector = std::is_same_v<OutputType, RealVectorValue>;
431 constexpr bool is_eigen = std::is_same_v<OutputType, RealEigenVector>;
432 static_assert(is_real || is_real_vector || is_eigen,
"Unsupported type");
435 if constexpr (!is_eigen)
436 libmesh_ignore(
this);
439 using dest_array_type =
typename std::remove_reference_t<
decltype(dest)>::value_type;
440 constexpr bool is_value =
441 std::is_same_v<dest_array_type, OutputType> ||
442 std::is_same_v<dest_array_type, typename Moose::ADType<OutputType>::type>;
443 constexpr bool is_gradient =
444 std::is_same_v<dest_array_type, OutputGradient> ||
445 std::is_same_v<dest_array_type, typename Moose::ADType<OutputGradient>::type>;
446 constexpr bool is_second =
447 std::is_same_v<dest_array_type, OutputSecond> ||
448 std::is_same_v<dest_array_type, typename Moose::ADType<OutputSecond>::type>;
449 constexpr bool is_divergence =
450 std::is_same_v<dest_array_type, OutputDivergence> ||
451 std::is_same_v<dest_array_type, typename Moose::ADType<OutputDivergence>::type>;
452 static_assert(is_value || is_gradient || is_second || is_divergence,
453 "Unsupported destination array type");
456 const auto set_zero = [
this, &dest](
const auto qp)
458 if constexpr (!is_eigen)
459 libmesh_ignore(
this);
461 if constexpr (is_real || is_real_vector)
463 else if constexpr (is_eigen)
465 if constexpr (is_value)
466 dest[qp].setZero(this->_count);
467 else if constexpr (is_gradient)
468 dest[qp].setZero(this->_count, LIBMESH_DIM);
469 else if constexpr (is_second)
470 dest[qp].setZero(this->_count, LIBMESH_DIM * LIBMESH_DIM);
472 static_assert(Moose::always_false<OutputType, dest_array_type>,
"Unsupported type");
475 static_assert(Moose::always_false<OutputType, dest_array_type>,
"Unsupported type");
479 const auto accumulate = [&dest, &phi, &dof_values](
const auto i,
const auto qp)
481 if constexpr (is_real || is_real_vector || (is_eigen && is_value))
483 if constexpr (is_value || is_divergence)
484 dest[qp] += phi[i][qp] * dof_values[i];
485 else if constexpr (is_gradient || is_second)
486 dest[qp].add_scaled(phi[i][qp], dof_values[i]);
488 static_assert(Moose::always_false<OutputType, dest_array_type>,
"Unsupported type");
490 else if constexpr (is_eigen)
492 if constexpr (is_gradient)
495 dest[qp].col(d) += phi[i][qp](d) * dof_values[i];
497 else if constexpr (is_second)
499 for (
unsigned int d = 0, d1 = 0; d1 < LIBMESH_DIM; ++d1)
501 dest[qp].col(d++) += phi[i][qp](d1, d2) * dof_values[i];
504 static_assert(Moose::always_false<OutputType, dest_array_type>,
"Unsupported type");
507 static_assert(Moose::always_false<OutputType, dest_array_type>,
"Unsupported type");
513 if constexpr (constant_monomial)
515 mooseAssert(num_shapes == 1,
"Should have only one shape function for a constant monomial");
518 for (
unsigned int qp = 1; qp < nqp; ++qp)
524 for (
const auto qp : make_range(nqp))
526 for (
const auto i : make_range(num_shapes))
527 for (
const auto qp : make_range(nqp))
532template <
typename OutputType>
533template <
bool constant_monomial>
537 const auto num_dofs = _dof_indices.size();
538 const auto num_shapes = num_dofs / _count;
543 const bool is_transient = _subproblem.isTransient();
544 const auto nqp = _current_qrule->n_points();
545 const auto & active_coupleable_matrix_tags =
546 _subproblem.getActiveFEVariableCoupleableMatrixTags(_tid);
549 if constexpr (std::is_same_v<OutputType, RealEigenVector>)
551 if (_qrule == _current_qrule)
553 _mapped_grad_phi.resize(num_shapes);
554 for (
const auto i : make_range(num_shapes))
556 _mapped_grad_phi[i].resize(nqp, Eigen::Map<RealDIMValue>(
nullptr));
557 for (
const auto qp : make_range(nqp))
559 new (&_mapped_grad_phi[i][qp])
560 Eigen::Map<RealDIMValue>(
const_cast<Real *
>(&(*_current_grad_phi)[i][qp](0)));
565 _mapped_grad_phi_face.resize(num_shapes);
566 for (
const auto i : make_range(num_shapes))
568 _mapped_grad_phi_face[i].resize(nqp, Eigen::Map<RealDIMValue>(
nullptr));
569 for (
const auto qp : make_range(nqp))
571 new (&_mapped_grad_phi_face[i][qp])
572 Eigen::Map<RealDIMValue>(
const_cast<Real *
>(&(*_current_grad_phi)[i][qp](0)));
578 !(_need_second || _need_second_old || _need_second_older || _need_second_previous_nl) ||
580 "We're requiring a second calculation but have not set a second shape function!");
581 mooseAssert(!(_need_curl || _need_curl_old) || _current_curl_phi,
582 "We're requiring a curl calculation but have not set a curl shape function!");
583 mooseAssert(!(_need_div || _need_div_old) || _current_div_phi,
584 "We're requiring a divergence calculation but have not set a div shape function!");
588 fill<constant_monomial>(
589 _curl_u, *_current_curl_phi, _vector_tags_dof_u[_solution_tag], nqp, num_shapes);
590 if (is_transient && _need_curl_old)
591 fill<constant_monomial>(
592 _curl_u_old, *_current_curl_phi, _vector_tags_dof_u[_old_solution_tag], nqp, num_shapes);
596 fill<constant_monomial>(
597 _div_u, *_current_div_phi, _vector_tags_dof_u[_solution_tag], nqp, num_shapes);
598 if (is_transient && _need_div_old)
599 fill<constant_monomial>(
600 _div_u_old, *_current_div_phi, _vector_tags_dof_u[_old_solution_tag], nqp, num_shapes);
604 fill<constant_monomial>(
605 _second_u, *_current_second_phi, _vector_tags_dof_u[_solution_tag], nqp, num_shapes);
606 if (_need_second_previous_nl)
607 fill<constant_monomial>(_second_u_previous_nl,
608 *_current_second_phi,
609 _vector_tags_dof_u[_previous_nl_solution_tag],
614 for (
auto tag : _required_vector_tags)
616 if (_need_vector_tag_u[tag] && _sys.hasVector(tag))
618 mooseAssert(_sys.getVector(tag).closed(),
"Vector should be closed");
619 fill<constant_monomial>(
620 _vector_tag_u[tag], *_current_phi, _vector_tags_dof_u[tag], nqp, num_shapes);
622 if (_need_vector_tag_grad[tag] && _sys.hasVector(tag))
624 mooseAssert(_sys.getVector(tag).closed(),
"Vector should be closed");
625 fill<constant_monomial>(
626 _vector_tag_grad[tag], *_current_grad_phi, _vector_tags_dof_u[tag], nqp, num_shapes);
631 for (
auto tag : active_coupleable_matrix_tags)
632 if (_need_matrix_tag_u[tag])
633 fill<constant_monomial>(
634 _matrix_tag_u[tag], *_current_phi, _matrix_tags_dof_u[tag], nqp, num_shapes);
639 if (_need_second_old)
640 fill<constant_monomial>(_second_u_old,
641 *_current_second_phi,
642 _vector_tags_dof_u[_old_solution_tag],
645 if (_need_second_older)
646 fill<constant_monomial>(_second_u_older,
647 *_current_second_phi,
648 _vector_tags_dof_u[_older_solution_tag],
652 fill<constant_monomial>(_u_dot, *_current_phi, _dof_values_dot, nqp, num_shapes);
654 fill<constant_monomial>(_u_dotdot, *_current_phi, _dof_values_dotdot, nqp, num_shapes);
656 fill<constant_monomial>(_u_dot_old, *_current_phi, _dof_values_dot_old, nqp, num_shapes);
657 if (_need_u_dotdot_old)
658 fill<constant_monomial>(
659 _u_dotdot_old, *_current_phi, _dof_values_dotdot_old, nqp, num_shapes);
663 _du_dot_du.resize(nqp);
664 for (
const auto i : make_range(num_shapes))
665 for (
const auto qp : make_range(nqp))
666 _du_dot_du[qp] = _dof_du_dot_du[i];
668 if (_need_du_dotdot_du)
670 _du_dotdot_du.resize(nqp);
671 for (
const auto i : make_range(num_shapes))
672 for (
const auto qp : make_range(nqp))
673 _du_dotdot_du[qp] = _dof_du_dotdot_du[i];
677 fill<constant_monomial>(_grad_u_dot, *_current_grad_phi, _dof_values_dot, nqp, num_shapes);
678 if (_need_grad_dotdot)
679 fill<constant_monomial>(
680 _grad_u_dotdot, *_current_grad_phi, _dof_values_dotdot, nqp, num_shapes);
686 if (_need_ad && (_need_ad_volume || _current_qrule != _qrule))
687 computeAD<constant_monomial>(num_dofs, nqp);
690template <
typename OutputType>
694 computeValuesInternal<
false>();
697template <
typename OutputType>
701 if (_dof_indices.size() == 0)
705 if (_elem->p_level())
708 computeValuesInternal<
true>();
711template <
typename OutputType>
715 const auto num_dofs = _dof_indices.size();
719 _ad_dof_values.resize(num_dofs);
720 for (
const auto i : make_range(num_dofs))
721 _ad_dof_values[i] = _vector_tags_dof_u[_solution_tag][i];
724 for (
const auto i : make_range(num_dofs))
727 const bool is_transient = _subproblem.isTransient();
728 if (is_transient && _need_ad_u_dot)
730 _ad_dofs_dot.resize(num_dofs);
731 if (_need_ad_u_dotdot)
732 _ad_dofs_dotdot.resize(num_dofs);
734 if (_time_integrator)
736 if (_time_integrator->dt())
738 for (
const auto i : make_range(num_dofs))
739 _ad_dofs_dot[i] = _ad_dof_values[i];
740 for (
const auto i : make_range(num_dofs))
741 _time_integrator->computeADTimeDerivatives(_ad_dofs_dot[i],
743 _need_ad_u_dotdot ? _ad_dofs_dotdot[i]
748 for (
const auto i : make_range(num_dofs))
750 _ad_dofs_dot[i] = 0.;
751 if (_need_ad_u_dotdot)
752 _ad_dofs_dotdot[i] = 0;
758 for (
const auto i : make_range(num_dofs))
760 _ad_dofs_dot[i] = _dof_values_dot[i];
761 if (_need_ad_u_dotdot)
762 _ad_dofs_dotdot[i] = _dof_values_dotdot[i];
771 const auto num_dofs = _dof_indices.size();
774 const auto n_test = num_dofs / _count;
775 mooseAssert(num_dofs == _count * n_test,
776 "Our assertions around number of dofs, test functions, and count are incorrect");
778 _ad_dof_values.resize(n_test);
780 for (
const auto i : make_range(n_test))
782 _ad_dof_values[i].resize(_count);
783 for (
const auto j : make_range(_count))
785 auto & dual_number = _ad_dof_values[i](j);
786 const auto global_dof_index = _dof_indices[j * n_test + i];
787 dual_number = (*_sys.currentSolution())(global_dof_index);
795template <
typename OutputType>
796template <
bool constant_monomial>
801 const auto n_test = num_dofs / _count;
805 fill<constant_monomial>(_ad_u, *_current_phi, _ad_dof_values, nqp, n_test);
810 const bool on_element_face =
812 if (_need_ad_grad_u && on_element_face && !_need_ad_grad_u_face)
813 _ad_grad_u.resize(0);
814 else if (_need_ad_grad_u)
819 if (_displaced && _current_ad_grad_phi)
820 fill<constant_monomial>(_ad_grad_u, *_current_ad_grad_phi, _ad_dof_values, nqp, n_test);
822 fill<constant_monomial>(_ad_grad_u, *_current_grad_phi, _ad_dof_values, nqp, n_test);
825 if constexpr (std::is_same_v<OutputType, Real>)
826 if (_need_ad_second_u)
827 fill<constant_monomial>(_ad_second_u, *_current_second_phi, _ad_dof_values, nqp, n_test);
830 fill<constant_monomial>(_ad_curl_u, *_current_curl_phi, _ad_dof_values, nqp, n_test);
832 const bool is_transient = _subproblem.isTransient();
837 if (_time_integrator)
838 fill<constant_monomial>(_ad_u_dot, *_current_phi, _ad_dofs_dot, nqp, n_test);
843 _ad_u_dot.resize(nqp);
844 for (
const auto qp : make_range(nqp))
845 _ad_u_dot[qp] = _u_dot[qp];
849 if (_need_ad_u_dotdot)
851 if (_time_integrator)
852 fill<constant_monomial>(_ad_u_dotdot, *_current_phi, _ad_dofs_dotdot, nqp, n_test);
855 _ad_u_dotdot.resize(nqp);
856 for (
const auto qp : make_range(nqp))
857 _ad_u_dotdot[qp] = _u_dotdot[qp];
863 if (_need_ad_grad_u_dot && on_element_face)
864 _ad_grad_u_dot.resize(0);
865 else if (_need_ad_grad_u_dot)
867 if (_time_integrator)
872 if (_displaced && _current_ad_grad_phi)
873 fill<constant_monomial>(_ad_grad_u_dot, *_current_ad_grad_phi, _ad_dofs_dot, nqp, n_test);
875 fill<constant_monomial>(_ad_grad_u_dot, *_current_grad_phi, _ad_dofs_dot, nqp, n_test);
879 _ad_grad_u_dot.resize(nqp);
880 for (
const auto qp : make_range(nqp))
881 _ad_grad_u_dot[qp] = _grad_u_dot[qp];
887template <
typename OutputType>
891 auto & dof_values = _vector_tags_dof_u[_solution_tag];
892 dof_values[index] = value;
893 _has_dof_values =
true;
895 auto & u = _vector_tag_u[_solution_tag];
896 const auto nqps = u.size();
897 const auto ndofs = dof_values.size();
898 for (
const auto qp : make_range(nqps))
900 for (
const auto qp : make_range(nqps))
901 for (
const auto i : make_range(ndofs))
902 u[qp] += (*_phi)[i][qp] * dof_values[i];
905template <
typename OutputType>
909 auto & dof_values = _vector_tags_dof_u[_solution_tag];
910 for (
unsigned int i = 0; i <
values.size(); i++)
911 dof_values[i] =
values(i);
913 _has_dof_values =
true;
915 auto & u = _vector_tag_u[_solution_tag];
916 const auto nqps = u.size();
917 const auto ndofs = dof_values.size();
918 for (
const auto qp : make_range(nqps))
920 for (
const auto qp : make_range(nqps))
921 for (
const auto i : make_range(ndofs))
922 u[qp] += (*_phi)[i][qp] * dof_values[i];
925template <
typename OutputType>
930 residual.set(_nodal_dof_index, v);
936 const RealEigenVector & v)
938 for (
const auto j : make_range(_count))
939 residual.set(_nodal_dof_index + j, v(j));
942template <
typename OutputType>
946 mooseAssert(_subproblem.mesh().isSemiLocal(
const_cast<Node *
>(&node)),
"Node is not Semilocal");
951 mooseAssert(node.n_dofs(_sys.number(), _var_num) > 0,
952 "Node " << node.id() <<
" does not contain any dofs for the "
953 << _sys.system().variable_name(_var_num) <<
" variable");
955 dof_id_type dof = node.dof_number(_sys.number(), _var_num, 0);
960 return (*_sys.currentSolution())(dof);
963 return _sys.solutionOld()(dof);
966 return _sys.solutionOlder()(dof);
969 mooseError(
"PreviousNL not currently supported for getNodalValue");
978 mooseAssert(_subproblem.mesh().isSemiLocal(
const_cast<Node *
>(&node)),
"Node is not Semilocal");
983 mooseAssert(node.n_dofs(_sys.number(), _var_num) > 0,
984 "Node " << node.id() <<
" does not contain any dofs for the "
985 << _sys.system().variable_name(_var_num) <<
" variable");
987 dof_id_type dof = node.dof_number(_sys.number(), _var_num, 0);
989 RealEigenVector v(_count);
993 for (
unsigned int i = 0; i < _count; ++i)
994 v(i) = (*_sys.currentSolution())(dof++);
998 for (
unsigned int i = 0; i < _count; ++i)
999 v(i) = _sys.solutionOld()(dof++);
1003 for (
unsigned int i = 0; i < _count; ++i)
1004 v(i) = _sys.solutionOlder()(dof++);
1008 mooseError(
"PreviousNL not currently supported for getNodalValue");
1013template <
typename OutputType>
1017 const unsigned int idx)
const
1019 static thread_local std::vector<dof_id_type> dof_indices;
1020 _dof_map.dof_indices(elem, dof_indices, _var_num);
1025 return (*_sys.currentSolution())(dof_indices[idx]);
1028 return _sys.solutionOld()(dof_indices[idx]);
1031 return _sys.solutionOlder()(dof_indices[idx]);
1034 mooseError(
"PreviousNL not currently supported for getElementalValue");
1042 const unsigned int idx)
const
1045 "getElementalValue has a really bad API name. It is retrieving a value from the solution "
1046 "vector for a particular dof index. Generally speaking it has absolutely no equivalence to "
1047 "an 'elemental' value, which most people would consider to be something like an element "
1050 static thread_local std::vector<dof_id_type> dof_indices;
1051 _dof_map.array_dof_indices(elem, dof_indices, _var_num);
1052 mooseAssert(dof_indices.size() % _count == 0,
1053 "The number of array dof indices should divide cleanly by the variable count");
1054 const auto num_shapes = dof_indices.size() / _count;
1056 RealEigenVector v(_count);
1061 for (
unsigned int i = 0; i < _count; ++i)
1062 v(i) = (*_sys.currentSolution())(dof_indices[i * num_shapes + idx]);
1066 for (
unsigned int i = 0; i < _count; ++i)
1067 v(i) = _sys.solutionOld()(dof_indices[i * num_shapes + idx]);
1071 for (
unsigned int i = 0; i < _count; ++i)
1072 v(i) = _sys.solutionOlder()(dof_indices[i * num_shapes + idx]);
1076 mooseError(
"PreviousNL not currently supported for getElementalValue");
1081template <
typename OutputType>
1084 std::vector<dof_id_type> & dof_indices)
const
1086 if constexpr (std::is_same<OutputType, RealEigenVector>::value)
1087 _dof_map.array_dof_indices(elem, dof_indices, _var_num);
1089 _dof_map.dof_indices(elem, dof_indices, _var_num);
1092template <
typename OutputType>
1097 sol.add_vector(v, _dof_indices);
1100template <
typename OutputType>
1104 if (_sys.solutionUDot())
1106 _need_dof_values_dot =
true;
1107 return _dof_values_dot;
1110 mooseError(
"MooseVariableData: Time derivative of solution (`u_dot`) is not stored. Please set "
1111 "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
1114template <
typename OutputType>
1118 if (_sys.solutionUDotDot())
1120 _need_dof_values_dotdot =
true;
1121 return _dof_values_dotdot;
1124 mooseError(
"MooseVariableData: Second time derivative of solution (`u_dotdot`) is not stored. "
1125 "Please set uDotDotRequested() to true in FEProblemBase before requesting "
1129template <
typename OutputType>
1133 if (_sys.solutionUDotOld())
1135 _need_dof_values_dot_old =
true;
1136 return _dof_values_dot_old;
1139 mooseError(
"MooseVariableData: Old time derivative of solution (`u_dot_old`) is not stored. "
1140 "Please set uDotOldRequested() to true in FEProblemBase before requesting "
1144template <
typename OutputType>
1148 if (_sys.solutionUDotDotOld())
1150 _need_dof_values_dotdot_old =
true;
1151 return _dof_values_dotdot_old;
1154 mooseError(
"MooseVariableData: Old second time derivative of solution (`u_dotdot_old`) is not "
1155 "stored. Please set uDotDotOldRequested() to true in FEProblemBase before "
1156 "requesting `u_dotdot_old`.");
1159template <
typename OutputType>
1163 _need_dof_du_dot_du =
true;
1164 return _dof_du_dot_du;
1167template <
typename OutputType>
1171 _need_dof_du_dotdot_du =
true;
1172 return _dof_du_dotdot_du;
1175template <
typename OutputType>
1179 unsigned int nqp = _qrule->n_points();
1183 unsigned int num_dofs = _dof_indices.size();
1184 for (
const auto qp : make_range(nqp))
1186 _increment[qp] = 0.;
1187 for (
const auto i : make_range(num_dofs))
1188 _increment[qp] += (*_phi)[i][qp] * increment_vec(_dof_indices[i]);
1195 const NumericVector<Number> & increment_vec)
1197 unsigned int nqp = _qrule->n_points();
1199 _increment.resize(nqp);
1201 unsigned int num_dofs = _dof_indices.size();
1204 for (
const auto qp : make_range(nqp))
1206 for (
const auto i : make_range(num_dofs))
1207 for (
const auto j : make_range(_count))
1208 _increment[qp](j) += (*_phi)[i][qp] * increment_vec(_dof_indices[i] + j);
1213 for (
const auto qp : make_range(nqp))
1216 for (
const auto j : make_range(_count))
1217 for (
const auto i : make_range(num_dofs))
1219 _increment[qp](j) += (*_phi)[i][qp] * increment_vec(_dof_indices[i] + n);
1226template <
typename OutputType>
1231 mooseError(
"computeIncrementAtNode can only be called for nodal variables");
1233 _increment.resize(1);
1236 _increment[0] = increment_vec(_dof_indices[0]);
1242 const NumericVector<Number> & increment_vec)
1245 mooseError(
"computeIncrementAtNode can only be called for nodal variables");
1247 _increment.resize(1);
1251 for (
unsigned int j = 0; j < _count; j++)
1252 _increment[0](j) = increment_vec(_dof_indices[0] + j);
1256 const auto n_dof_indices = _dof_indices.size();
1257 for (
const auto j : make_range(_count))
1259 _increment[0](j) = increment_vec(_dof_indices[0] + n);
1265template <
typename OutputType>
1271 if (_sys.solutionUDot())
1273 _need_dof_values_dot =
true;
1274 return _nodal_value_dot;
1278 "MooseVariableData: Time derivative of solution (`u_dot`) is not stored. Please set "
1279 "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
1282 mooseError(
"Nodal values can be requested only on nodal variables, variable '",
1287template <
typename OutputType>
1293 if (_sys.solutionUDotDot())
1295 _need_dof_values_dotdot =
true;
1296 return _nodal_value_dotdot;
1300 "MooseVariableData: Second time derivative of solution (`u_dotdot`) is not stored. "
1301 "Please set uDotDotRequested() to true in FEProblemBase before requesting "
1305 mooseError(
"Nodal values can be requested only on nodal variables, variable '",
1310template <
typename OutputType>
1316 if (_sys.solutionUDotOld())
1318 _need_dof_values_dot_old =
true;
1319 return _nodal_value_dot_old;
1322 mooseError(
"MooseVariableData: Old time derivative of solution (`u_dot_old`) is not stored. "
1323 "Please set uDotOldRequested() to true in FEProblemBase before requesting "
1327 mooseError(
"Nodal values can be requested only on nodal variables, variable '",
1332template <
typename OutputType>
1338 if (_sys.solutionUDotDotOld())
1340 _need_dof_values_dotdot_old =
true;
1341 return _nodal_value_dotdot_old;
1345 "MooseVariableData: Old second time derivative of solution (`u_dotdot_old`) is not "
1346 "stored. Please set uDotDotOldRequested() to true in FEProblemBase before "
1347 "requesting `u_dotdot_old`.");
1350 mooseError(
"Nodal values can be requested only on nodal variables, variable '",
1355template <
typename OutputType>
1359 if (_has_dof_indices)
1367 assignADNodalValue();
1371 zeroSizeDofValues();
1374template <
typename OutputType>
1378 mooseAssert(_ad_dof_values.size(),
"The AD dof values container must have size greater than 0");
1379 _ad_nodal_value = _ad_dof_values[0];
1386 const auto num_dofs = _dof_indices.size();
1387 mooseAssert(_ad_dof_values.size() == num_dofs,
1388 "Our dof values container size should match the dof indices container size");
1389 for (
const auto i : make_range(num_dofs))
1390 _ad_nodal_value(i) = _ad_dof_values[i];
1393template <
typename OutputType>
1397 if constexpr (std::is_same<RealEigenVector, OutputType>::value)
1398 _dof_map.array_dof_indices(_elem, _dof_indices, _var_num);
1400 _dof_map.dof_indices(_elem, _dof_indices, _var_num);
1402 mooseAssert(_dof_indices.size() % _count == 0,
1403 "The number of dof indices should divide cleanly by the variable count");
1404 const auto num_shapes = _dof_indices.size() / _count;
1405 _vector_tags_dof_u[_solution_tag].resize(num_shapes);
1407 unsigned int nqp = _qrule->n_points();
1408 _vector_tag_u[_solution_tag].resize(nqp);
1411template <
typename OutputType>
1415 if constexpr (std::is_same<OutputType, RealEigenVector>::value)
1416 _dof_map.array_dof_indices(_elem, _dof_indices, _var_num);
1418 _dof_map.dof_indices(_elem, _dof_indices, _var_num);
1420 _has_dof_values =
false;
1424 _has_dof_indices = _dof_indices.size();
1427template <
typename OutputType>
1431 if constexpr (std::is_same<OutputType, RealEigenVector>::value)
1432 _dof_map.array_dof_indices(_node, _dof_indices, _var_num);
1434 _dof_map.dof_indices(_node, _dof_indices, _var_num);
1436 const auto n_dofs = _dof_indices.size();
1441 _nodal_dof_index = _dof_indices[0];
1442 _has_dof_indices =
true;
1445 _has_dof_indices =
false;
1448template <
typename OutputType>
1456 if constexpr (std::is_same<RealEigenVector, OutputType>::value)
1457 _dof_map.array_dof_indices(_elem, _dof_indices, _var_num);
1459 _dof_map.dof_indices(_elem, _dof_indices, _var_num);
1460 if (_elem->n_dofs(_sys.number(), _var_num) > 0)
1464 _nodal_dof_index = _dof_indices[0];
1468 mooseAssert(_dof_indices.size() % _count == 0,
1469 "The number of dof indices should be cleanly divisible by the variable count");
1470 const auto num_shapes = _dof_indices.size() / _count;
1471 for (
auto & dof_u : _vector_tags_dof_u)
1472 dof_u.resize(num_shapes);
1474 for (
auto & dof_u : _matrix_tags_dof_u)
1475 dof_u.resize(num_shapes);
1477 _has_dof_indices =
true;
1480 _has_dof_indices =
false;
1483 _has_dof_indices =
false;
1486template <
typename OutputType>
1490 _dof_indices.clear();
1491 for (
const auto & node_id : nodes)
1493 auto && nd = _subproblem.mesh().getMesh().query_node_ptr(node_id);
1494 if (nd && (_subproblem.mesh().isSemiLocal(
const_cast<Node *
>(nd))))
1496 if (nd->n_dofs(_sys.number(), _var_num) > 0)
1498 if constexpr (std::is_same<RealEigenVector, OutputType>::value)
1500 static thread_local std::vector<dof_id_type> dof_indices;
1501 _dof_map.array_dof_indices(nd, dof_indices, _var_num);
1502 for (
const auto dof : dof_indices)
1503 _dof_indices.push_back(dof);
1507 dof_id_type dof = nd->dof_number(_sys.number(), _var_num, 0);
1508 _dof_indices.push_back(dof);
1514 if (!_dof_indices.empty())
1515 _has_dof_indices =
true;
1517 _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
void needADGradPhiFace() const
Ask the assembly to compute the AD face shape function gradients, which this variable's AD gradient a...
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)