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>
149 _assembly.needADGradPhi();
152template <
typename OutputType>
160 _current_qrule = _qrule;
162 _current_grad_phi = _grad_phi;
163 _current_second_phi = _second_phi;
164 _current_curl_phi = _curl_phi;
165 _current_div_phi = _div_phi;
166 _current_ad_grad_phi = _ad_grad_phi;
171 _current_qrule = _qrule_face;
172 _current_phi = _phi_face;
173 _current_grad_phi = _grad_phi_face;
174 _current_second_phi = _second_phi_face;
175 _current_curl_phi = _curl_phi_face;
176 _current_div_phi = _div_phi_face;
177 _current_ad_grad_phi = _ad_grad_phi_face;
183template <
typename OutputType>
187 if (_sys.solutionUDot())
193 mooseError(
"MooseVariableFE: Time derivative of solution (`u_dot`) is not stored. Please set "
194 "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
197template <
typename OutputType>
201 if (_sys.solutionUDotDot())
203 _need_u_dotdot =
true;
207 mooseError(
"MooseVariableFE: Second time derivative of solution (`u_dotdot`) is not stored. "
208 "Please set uDotDotRequested() to true in FEProblemBase before requesting "
212template <
typename OutputType>
216 if (_sys.solutionUDotOld())
218 _need_u_dot_old =
true;
222 mooseError(
"MooseVariableFE: Old time derivative of solution (`u_dot_old`) is not stored. "
223 "Please set uDotOldRequested() to true in FEProblemBase before requesting "
227template <
typename OutputType>
231 if (_sys.solutionUDotDotOld())
233 _need_u_dotdot_old =
true;
234 return _u_dotdot_old;
237 mooseError(
"MooseVariableFE: Old second time derivative of solution (`u_dotdot_old`) is not "
238 "stored. Please set uDotDotOldRequested() to true in FEProblemBase before "
239 "requesting `u_dotdot_old`");
242template <
typename OutputType>
246 if (_sys.solutionUDot())
248 _need_grad_dot =
true;
252 mooseError(
"MooseVariableFE: Time derivative of solution (`u_dot`) is not stored. Please set "
253 "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
256template <
typename OutputType>
260 if (_sys.solutionUDotDot())
262 _need_grad_dotdot =
true;
263 return _grad_u_dotdot;
266 mooseError(
"MooseVariableFE: Second time derivative of solution (`u_dotdot`) is not stored. "
267 "Please set uDotDotRequested() to true in FEProblemBase before requesting "
271template <
typename OutputType>
287 _need_second_old =
true;
288 return _second_u_old;
293 _need_second_older =
true;
294 return _second_u_older;
299 _need_second_previous_nl =
true;
300 return _second_u_previous_nl;
310template <
typename OutputType>
326 _need_curl_old =
true;
332 _need_curl_older =
true;
333 return _curl_u_older;
337 mooseError(
"We don't currently support curl from the previous non-linear iteration");
341template <
typename OutputType>
357 _need_div_old =
true;
363 _need_div_older =
true;
368 mooseError(
"We don't currently support divergence from the previous non-linear iteration");
372template <
typename OutputType>
376 _second_phi = &_second_phi_assembly_method(_assembly, _fe_type);
380template <
typename OutputType>
384 _second_phi_face = &_second_phi_face_assembly_method(_assembly, _fe_type);
385 return *_second_phi_face;
388template <
typename OutputType>
392 _curl_phi = &_curl_phi_assembly_method(_assembly, _fe_type);
396template <
typename OutputType>
400 _curl_phi_face = &_curl_phi_face_assembly_method(_assembly, _fe_type);
401 return *_curl_phi_face;
404template <
typename OutputType>
408 _div_phi = &_div_phi_assembly_method(_assembly, _fe_type);
412template <
typename OutputType>
416 _div_phi_face = &_div_phi_face_assembly_method(_assembly, _fe_type);
417 return *_div_phi_face;
420template <
typename OutputType>
421template <
bool constant_monomial,
422 typename DestinationType,
424 typename DofValuesType>
428 const DofValuesType & dof_values,
429 const unsigned int nqp,
430 const std::size_t num_shapes)
432 if constexpr (constant_monomial)
433 libmesh_ignore(num_shapes);
436 constexpr bool is_real = std::is_same_v<OutputType, Real>;
437 constexpr bool is_real_vector = std::is_same_v<OutputType, RealVectorValue>;
438 constexpr bool is_eigen = std::is_same_v<OutputType, RealEigenVector>;
439 static_assert(is_real || is_real_vector || is_eigen,
"Unsupported type");
442 if constexpr (!is_eigen)
443 libmesh_ignore(
this);
446 using dest_array_type =
typename std::remove_reference_t<
decltype(dest)>::value_type;
447 constexpr bool is_value =
448 std::is_same_v<dest_array_type, OutputType> ||
449 std::is_same_v<dest_array_type, typename Moose::ADType<OutputType>::type>;
450 constexpr bool is_gradient =
451 std::is_same_v<dest_array_type, OutputGradient> ||
452 std::is_same_v<dest_array_type, typename Moose::ADType<OutputGradient>::type>;
453 constexpr bool is_second =
454 std::is_same_v<dest_array_type, OutputSecond> ||
455 std::is_same_v<dest_array_type, typename Moose::ADType<OutputSecond>::type>;
456 constexpr bool is_divergence =
457 std::is_same_v<dest_array_type, OutputDivergence> ||
458 std::is_same_v<dest_array_type, typename Moose::ADType<OutputDivergence>::type>;
459 static_assert(is_value || is_gradient || is_second || is_divergence,
460 "Unsupported destination array type");
463 const auto set_zero = [
this, &dest](
const auto qp)
465 if constexpr (!is_eigen)
466 libmesh_ignore(
this);
468 if constexpr (is_real || is_real_vector)
470 else if constexpr (is_eigen)
472 if constexpr (is_value)
473 dest[qp].setZero(this->_count);
474 else if constexpr (is_gradient)
475 dest[qp].setZero(this->_count, LIBMESH_DIM);
476 else if constexpr (is_second)
477 dest[qp].setZero(this->_count, LIBMESH_DIM * LIBMESH_DIM);
479 static_assert(Moose::always_false<OutputType, dest_array_type>,
"Unsupported type");
482 static_assert(Moose::always_false<OutputType, dest_array_type>,
"Unsupported type");
486 const auto accumulate = [&dest, &phi, &dof_values](
const auto i,
const auto qp)
488 if constexpr (is_real || is_real_vector || (is_eigen && is_value))
490 if constexpr (is_value || is_divergence)
491 dest[qp] += phi[i][qp] * dof_values[i];
492 else if constexpr (is_gradient || is_second)
493 dest[qp].add_scaled(phi[i][qp], dof_values[i]);
495 static_assert(Moose::always_false<OutputType, dest_array_type>,
"Unsupported type");
497 else if constexpr (is_eigen)
499 if constexpr (is_gradient)
502 dest[qp].col(d) += phi[i][qp](d) * dof_values[i];
504 else if constexpr (is_second)
506 for (
unsigned int d = 0, d1 = 0; d1 < LIBMESH_DIM; ++d1)
508 dest[qp].col(d++) += phi[i][qp](d1, d2) * dof_values[i];
511 static_assert(Moose::always_false<OutputType, dest_array_type>,
"Unsupported type");
514 static_assert(Moose::always_false<OutputType, dest_array_type>,
"Unsupported type");
520 if constexpr (constant_monomial)
522 mooseAssert(num_shapes == 1,
"Should have only one shape function for a constant monomial");
525 for (
unsigned int qp = 1; qp < nqp; ++qp)
531 for (
const auto qp : make_range(nqp))
533 for (
const auto i : make_range(num_shapes))
534 for (
const auto qp : make_range(nqp))
539template <
typename OutputType>
540template <
bool constant_monomial>
544 const auto num_dofs = _dof_indices.size();
545 const auto num_shapes = num_dofs / _count;
550 const bool is_transient = _subproblem.isTransient();
551 const auto nqp = _current_qrule->n_points();
552 const auto & active_coupleable_matrix_tags =
553 _subproblem.getActiveFEVariableCoupleableMatrixTags(_tid);
556 if constexpr (std::is_same_v<OutputType, RealEigenVector>)
558 if (_qrule == _current_qrule)
560 _mapped_grad_phi.resize(num_shapes);
561 for (
const auto i : make_range(num_shapes))
563 _mapped_grad_phi[i].resize(nqp, Eigen::Map<RealDIMValue>(
nullptr));
564 for (
const auto qp : make_range(nqp))
566 new (&_mapped_grad_phi[i][qp])
567 Eigen::Map<RealDIMValue>(
const_cast<Real *
>(&(*_current_grad_phi)[i][qp](0)));
572 _mapped_grad_phi_face.resize(num_shapes);
573 for (
const auto i : make_range(num_shapes))
575 _mapped_grad_phi_face[i].resize(nqp, Eigen::Map<RealDIMValue>(
nullptr));
576 for (
const auto qp : make_range(nqp))
578 new (&_mapped_grad_phi_face[i][qp])
579 Eigen::Map<RealDIMValue>(
const_cast<Real *
>(&(*_current_grad_phi)[i][qp](0)));
585 !(_need_second || _need_second_old || _need_second_older || _need_second_previous_nl) ||
587 "We're requiring a second calculation but have not set a second shape function!");
588 mooseAssert(!(_need_curl || _need_curl_old) || _current_curl_phi,
589 "We're requiring a curl calculation but have not set a curl shape function!");
590 mooseAssert(!(_need_div || _need_div_old) || _current_div_phi,
591 "We're requiring a divergence calculation but have not set a div shape function!");
595 fill<constant_monomial>(
596 _curl_u, *_current_curl_phi, _vector_tags_dof_u[_solution_tag], nqp, num_shapes);
597 if (is_transient && _need_curl_old)
598 fill<constant_monomial>(
599 _curl_u_old, *_current_curl_phi, _vector_tags_dof_u[_old_solution_tag], nqp, num_shapes);
603 fill<constant_monomial>(
604 _div_u, *_current_div_phi, _vector_tags_dof_u[_solution_tag], nqp, num_shapes);
605 if (is_transient && _need_div_old)
606 fill<constant_monomial>(
607 _div_u_old, *_current_div_phi, _vector_tags_dof_u[_old_solution_tag], nqp, num_shapes);
611 fill<constant_monomial>(
612 _second_u, *_current_second_phi, _vector_tags_dof_u[_solution_tag], nqp, num_shapes);
613 if (_need_second_previous_nl)
614 fill<constant_monomial>(_second_u_previous_nl,
615 *_current_second_phi,
616 _vector_tags_dof_u[_previous_nl_solution_tag],
621 for (
auto tag : _required_vector_tags)
623 if (_need_vector_tag_u[tag] && _sys.hasVector(tag))
625 mooseAssert(_sys.getVector(tag).closed(),
"Vector should be closed");
626 fill<constant_monomial>(
627 _vector_tag_u[tag], *_current_phi, _vector_tags_dof_u[tag], nqp, num_shapes);
629 if (_need_vector_tag_grad[tag] && _sys.hasVector(tag))
631 mooseAssert(_sys.getVector(tag).closed(),
"Vector should be closed");
632 fill<constant_monomial>(
633 _vector_tag_grad[tag], *_current_grad_phi, _vector_tags_dof_u[tag], nqp, num_shapes);
638 for (
auto tag : active_coupleable_matrix_tags)
639 if (_need_matrix_tag_u[tag])
640 fill<constant_monomial>(
641 _matrix_tag_u[tag], *_current_phi, _matrix_tags_dof_u[tag], nqp, num_shapes);
646 if (_need_second_old)
647 fill<constant_monomial>(_second_u_old,
648 *_current_second_phi,
649 _vector_tags_dof_u[_old_solution_tag],
652 if (_need_second_older)
653 fill<constant_monomial>(_second_u_older,
654 *_current_second_phi,
655 _vector_tags_dof_u[_older_solution_tag],
659 fill<constant_monomial>(_u_dot, *_current_phi, _dof_values_dot, nqp, num_shapes);
661 fill<constant_monomial>(_u_dotdot, *_current_phi, _dof_values_dotdot, nqp, num_shapes);
663 fill<constant_monomial>(_u_dot_old, *_current_phi, _dof_values_dot_old, nqp, num_shapes);
664 if (_need_u_dotdot_old)
665 fill<constant_monomial>(
666 _u_dotdot_old, *_current_phi, _dof_values_dotdot_old, nqp, num_shapes);
670 _du_dot_du.resize(nqp);
671 for (
const auto i : make_range(num_shapes))
672 for (
const auto qp : make_range(nqp))
673 _du_dot_du[qp] = _dof_du_dot_du[i];
675 if (_need_du_dotdot_du)
677 _du_dotdot_du.resize(nqp);
678 for (
const auto i : make_range(num_shapes))
679 for (
const auto qp : make_range(nqp))
680 _du_dotdot_du[qp] = _dof_du_dotdot_du[i];
684 fill<constant_monomial>(_grad_u_dot, *_current_grad_phi, _dof_values_dot, nqp, num_shapes);
685 if (_need_grad_dotdot)
686 fill<constant_monomial>(
687 _grad_u_dotdot, *_current_grad_phi, _dof_values_dotdot, nqp, num_shapes);
693 if (_need_ad && (_need_ad_volume || _current_qrule != _qrule))
694 computeAD<constant_monomial>(num_dofs, nqp);
697template <
typename OutputType>
701 computeValuesInternal<
false>();
704template <
typename OutputType>
708 if (_dof_indices.size() == 0)
712 if (_elem->p_level())
715 computeValuesInternal<
true>();
718template <
typename OutputType>
722 const auto num_dofs = _dof_indices.size();
726 _ad_dof_values.resize(num_dofs);
727 for (
const auto i : make_range(num_dofs))
728 _ad_dof_values[i] = _vector_tags_dof_u[_solution_tag][i];
731 for (
const auto i : make_range(num_dofs))
734 const bool is_transient = _subproblem.isTransient();
735 if (is_transient && _need_ad_u_dot)
737 _ad_dofs_dot.resize(num_dofs);
738 if (_need_ad_u_dotdot)
739 _ad_dofs_dotdot.resize(num_dofs);
741 if (_time_integrator)
743 if (_time_integrator->dt())
745 for (
const auto i : make_range(num_dofs))
746 _ad_dofs_dot[i] = _ad_dof_values[i];
747 for (
const auto i : make_range(num_dofs))
748 _time_integrator->computeADTimeDerivatives(_ad_dofs_dot[i],
750 _need_ad_u_dotdot ? _ad_dofs_dotdot[i]
755 for (
const auto i : make_range(num_dofs))
757 _ad_dofs_dot[i] = 0.;
758 if (_need_ad_u_dotdot)
759 _ad_dofs_dotdot[i] = 0;
765 for (
const auto i : make_range(num_dofs))
767 _ad_dofs_dot[i] = _dof_values_dot[i];
768 if (_need_ad_u_dotdot)
769 _ad_dofs_dotdot[i] = _dof_values_dotdot[i];
778 const auto num_dofs = _dof_indices.size();
781 const auto n_test = num_dofs / _count;
782 mooseAssert(num_dofs == _count * n_test,
783 "Our assertions around number of dofs, test functions, and count are incorrect");
785 _ad_dof_values.resize(n_test);
787 for (
const auto i : make_range(n_test))
789 _ad_dof_values[i].resize(_count);
790 for (
const auto j : make_range(_count))
792 auto & dual_number = _ad_dof_values[i](j);
793 const auto global_dof_index = _dof_indices[j * n_test + i];
794 dual_number = (*_sys.currentSolution())(global_dof_index);
801 const bool is_transient = _subproblem.isTransient();
802 if (is_transient && _need_ad_u_dot)
804 _ad_dofs_dot.resize(n_test);
805 if (_need_ad_u_dotdot)
806 _ad_dofs_dotdot.resize(n_test);
808 for (
const auto i : make_range(n_test))
810 _ad_dofs_dot[i].resize(_count);
811 if (_need_ad_u_dotdot)
812 _ad_dofs_dotdot[i].resize(_count);
813 for (
const auto j : make_range(_count))
815 auto & dot = _ad_dofs_dot[i](j);
816 auto & dotdot = _need_ad_u_dotdot ? _ad_dofs_dotdot[i](j) : _ad_real_dummy;
817 if (_time_integrator)
819 if (_time_integrator->dt())
821 dot = _ad_dof_values[i](j);
822 _time_integrator->computeADTimeDerivatives(dot, _dof_indices[j * n_test + i], dotdot);
835 dot = _dof_values_dot[i](j);
836 if (_need_ad_u_dotdot)
837 dotdot = _dof_values_dotdot[i](j);
844template <
typename OutputType>
845template <
bool constant_monomial>
850 const auto n_test = num_dofs / _count;
854 fill<constant_monomial>(_ad_u, *_current_phi, _ad_dof_values, nqp, n_test);
859 const bool on_element_face =
861 if (_need_ad_grad_u && on_element_face && !_need_ad_grad_u_face)
862 _ad_grad_u.resize(0);
863 else if (_need_ad_grad_u)
868 if (_displaced && _current_ad_grad_phi)
869 fill<constant_monomial>(_ad_grad_u, *_current_ad_grad_phi, _ad_dof_values, nqp, n_test);
871 fill<constant_monomial>(_ad_grad_u, *_current_grad_phi, _ad_dof_values, nqp, n_test);
874 if constexpr (std::is_same_v<OutputType, Real>)
875 if (_need_ad_second_u)
876 fill<constant_monomial>(_ad_second_u, *_current_second_phi, _ad_dof_values, nqp, n_test);
879 fill<constant_monomial>(_ad_curl_u, *_current_curl_phi, _ad_dof_values, nqp, n_test);
882 fill<constant_monomial>(_ad_div_u, *_current_div_phi, _ad_dof_values, nqp, n_test);
884 const bool is_transient = _subproblem.isTransient();
889 if (_time_integrator)
890 fill<constant_monomial>(_ad_u_dot, *_current_phi, _ad_dofs_dot, nqp, n_test);
895 _ad_u_dot.resize(nqp);
896 for (
const auto qp : make_range(nqp))
897 _ad_u_dot[qp] = _u_dot[qp];
901 if (_need_ad_u_dotdot)
903 if (_time_integrator)
904 fill<constant_monomial>(_ad_u_dotdot, *_current_phi, _ad_dofs_dotdot, nqp, n_test);
907 _ad_u_dotdot.resize(nqp);
908 for (
const auto qp : make_range(nqp))
909 _ad_u_dotdot[qp] = _u_dotdot[qp];
915 if (_need_ad_grad_u_dot && on_element_face)
916 _ad_grad_u_dot.resize(0);
917 else if (_need_ad_grad_u_dot)
919 if (_time_integrator)
924 if (_displaced && _current_ad_grad_phi)
925 fill<constant_monomial>(_ad_grad_u_dot, *_current_ad_grad_phi, _ad_dofs_dot, nqp, n_test);
927 fill<constant_monomial>(_ad_grad_u_dot, *_current_grad_phi, _ad_dofs_dot, nqp, n_test);
931 _ad_grad_u_dot.resize(nqp);
932 for (
const auto qp : make_range(nqp))
933 _ad_grad_u_dot[qp] = _grad_u_dot[qp];
939template <
typename OutputType>
943 auto & dof_values = _vector_tags_dof_u[_solution_tag];
944 dof_values[index] = value;
945 _has_dof_values =
true;
947 auto & u = _vector_tag_u[_solution_tag];
948 const auto nqps = u.size();
949 const auto ndofs = dof_values.size();
950 for (
const auto qp : make_range(nqps))
952 for (
const auto qp : make_range(nqps))
953 for (
const auto i : make_range(ndofs))
954 u[qp] += (*_phi)[i][qp] * dof_values[i];
957template <
typename OutputType>
961 auto & dof_values = _vector_tags_dof_u[_solution_tag];
962 for (
unsigned int i = 0; i <
values.size(); i++)
963 dof_values[i] =
values(i);
965 _has_dof_values =
true;
967 auto & u = _vector_tag_u[_solution_tag];
968 const auto nqps = u.size();
969 const auto ndofs = dof_values.size();
970 for (
const auto qp : make_range(nqps))
972 for (
const auto qp : make_range(nqps))
973 for (
const auto i : make_range(ndofs))
974 u[qp] += (*_phi)[i][qp] * dof_values[i];
977template <
typename OutputType>
982 residual.set(_nodal_dof_index, v);
988 const RealEigenVector & v)
990 for (
const auto j : make_range(_count))
991 residual.set(_nodal_dof_index + j, v(j));
994template <
typename OutputType>
998 mooseAssert(_subproblem.mesh().isSemiLocal(
const_cast<Node *
>(&node)),
"Node is not Semilocal");
1003 mooseAssert(node.n_dofs(_sys.number(), _var_num) > 0,
1004 "Node " << node.id() <<
" does not contain any dofs for the "
1005 << _sys.system().variable_name(_var_num) <<
" variable");
1007 dof_id_type dof = node.dof_number(_sys.number(), _var_num, 0);
1012 return (*_sys.currentSolution())(dof);
1015 return _sys.solutionOld()(dof);
1018 return _sys.solutionOlder()(dof);
1021 mooseError(
"PreviousNL not currently supported for getNodalValue");
1030 mooseAssert(_subproblem.mesh().isSemiLocal(
const_cast<Node *
>(&node)),
"Node is not Semilocal");
1035 mooseAssert(node.n_dofs(_sys.number(), _var_num) > 0,
1036 "Node " << node.id() <<
" does not contain any dofs for the "
1037 << _sys.system().variable_name(_var_num) <<
" variable");
1039 dof_id_type dof = node.dof_number(_sys.number(), _var_num, 0);
1041 RealEigenVector v(_count);
1045 for (
unsigned int i = 0; i < _count; ++i)
1046 v(i) = (*_sys.currentSolution())(dof++);
1050 for (
unsigned int i = 0; i < _count; ++i)
1051 v(i) = _sys.solutionOld()(dof++);
1055 for (
unsigned int i = 0; i < _count; ++i)
1056 v(i) = _sys.solutionOlder()(dof++);
1060 mooseError(
"PreviousNL not currently supported for getNodalValue");
1065template <
typename OutputType>
1069 const unsigned int idx)
const
1071 static thread_local std::vector<dof_id_type> dof_indices;
1072 _dof_map.dof_indices(elem, dof_indices, _var_num);
1077 return (*_sys.currentSolution())(dof_indices[idx]);
1080 return _sys.solutionOld()(dof_indices[idx]);
1083 return _sys.solutionOlder()(dof_indices[idx]);
1086 mooseError(
"PreviousNL not currently supported for getElementalValue");
1094 const unsigned int idx)
const
1097 "getElementalValue has a really bad API name. It is retrieving a value from the solution "
1098 "vector for a particular dof index. Generally speaking it has absolutely no equivalence to "
1099 "an 'elemental' value, which most people would consider to be something like an element "
1102 static thread_local std::vector<dof_id_type> dof_indices;
1103 _dof_map.array_dof_indices(elem, dof_indices, _var_num);
1104 mooseAssert(dof_indices.size() % _count == 0,
1105 "The number of array dof indices should divide cleanly by the variable count");
1106 const auto num_shapes = dof_indices.size() / _count;
1108 RealEigenVector v(_count);
1113 for (
unsigned int i = 0; i < _count; ++i)
1114 v(i) = (*_sys.currentSolution())(dof_indices[i * num_shapes + idx]);
1118 for (
unsigned int i = 0; i < _count; ++i)
1119 v(i) = _sys.solutionOld()(dof_indices[i * num_shapes + idx]);
1123 for (
unsigned int i = 0; i < _count; ++i)
1124 v(i) = _sys.solutionOlder()(dof_indices[i * num_shapes + idx]);
1128 mooseError(
"PreviousNL not currently supported for getElementalValue");
1133template <
typename OutputType>
1136 std::vector<dof_id_type> & dof_indices)
const
1138 if constexpr (std::is_same<OutputType, RealEigenVector>::value)
1139 _dof_map.array_dof_indices(elem, dof_indices, _var_num);
1141 _dof_map.dof_indices(elem, dof_indices, _var_num);
1144template <
typename OutputType>
1149 sol.add_vector(v, _dof_indices);
1152template <
typename OutputType>
1156 if (_sys.solutionUDot())
1158 _need_dof_values_dot =
true;
1159 return _dof_values_dot;
1162 mooseError(
"MooseVariableData: Time derivative of solution (`u_dot`) is not stored. Please set "
1163 "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
1166template <
typename OutputType>
1170 if (_sys.solutionUDotDot())
1172 _need_dof_values_dotdot =
true;
1173 return _dof_values_dotdot;
1176 mooseError(
"MooseVariableData: Second time derivative of solution (`u_dotdot`) is not stored. "
1177 "Please set uDotDotRequested() to true in FEProblemBase before requesting "
1181template <
typename OutputType>
1185 if (_sys.solutionUDotOld())
1187 _need_dof_values_dot_old =
true;
1188 return _dof_values_dot_old;
1191 mooseError(
"MooseVariableData: Old time derivative of solution (`u_dot_old`) is not stored. "
1192 "Please set uDotOldRequested() to true in FEProblemBase before requesting "
1196template <
typename OutputType>
1200 if (_sys.solutionUDotDotOld())
1202 _need_dof_values_dotdot_old =
true;
1203 return _dof_values_dotdot_old;
1206 mooseError(
"MooseVariableData: Old second time derivative of solution (`u_dotdot_old`) is not "
1207 "stored. Please set uDotDotOldRequested() to true in FEProblemBase before "
1208 "requesting `u_dotdot_old`.");
1211template <
typename OutputType>
1215 _need_dof_du_dot_du =
true;
1216 return _dof_du_dot_du;
1219template <
typename OutputType>
1223 _need_dof_du_dotdot_du =
true;
1224 return _dof_du_dotdot_du;
1227template <
typename OutputType>
1231 unsigned int nqp = _qrule->n_points();
1235 unsigned int num_dofs = _dof_indices.size();
1236 for (
const auto qp : make_range(nqp))
1238 _increment[qp] = 0.;
1239 for (
const auto i : make_range(num_dofs))
1240 _increment[qp] += (*_phi)[i][qp] * increment_vec(_dof_indices[i]);
1247 const NumericVector<Number> & increment_vec)
1249 unsigned int nqp = _qrule->n_points();
1251 _increment.resize(nqp);
1253 unsigned int num_dofs = _dof_indices.size();
1256 for (
const auto qp : make_range(nqp))
1258 for (
const auto i : make_range(num_dofs))
1259 for (
const auto j : make_range(_count))
1260 _increment[qp](j) += (*_phi)[i][qp] * increment_vec(_dof_indices[i] + j);
1265 for (
const auto qp : make_range(nqp))
1268 for (
const auto j : make_range(_count))
1269 for (
const auto i : make_range(num_dofs))
1271 _increment[qp](j) += (*_phi)[i][qp] * increment_vec(_dof_indices[i] + n);
1278template <
typename OutputType>
1283 mooseError(
"computeIncrementAtNode can only be called for nodal variables");
1285 _increment.resize(1);
1288 _increment[0] = increment_vec(_dof_indices[0]);
1294 const NumericVector<Number> & increment_vec)
1297 mooseError(
"computeIncrementAtNode can only be called for nodal variables");
1299 _increment.resize(1);
1303 for (
unsigned int j = 0; j < _count; j++)
1304 _increment[0](j) = increment_vec(_dof_indices[0] + j);
1308 const auto n_dof_indices = _dof_indices.size();
1309 for (
const auto j : make_range(_count))
1311 _increment[0](j) = increment_vec(_dof_indices[0] + n);
1317template <
typename OutputType>
1323 if (_sys.solutionUDot())
1325 _need_dof_values_dot =
true;
1326 return _nodal_value_dot;
1330 "MooseVariableData: Time derivative of solution (`u_dot`) is not stored. Please set "
1331 "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
1334 mooseError(
"Nodal values can be requested only on nodal variables, variable '",
1339template <
typename OutputType>
1345 if (_sys.solutionUDotDot())
1347 _need_dof_values_dotdot =
true;
1348 return _nodal_value_dotdot;
1352 "MooseVariableData: Second time derivative of solution (`u_dotdot`) is not stored. "
1353 "Please set uDotDotRequested() to true in FEProblemBase before requesting "
1357 mooseError(
"Nodal values can be requested only on nodal variables, variable '",
1362template <
typename OutputType>
1368 if (_sys.solutionUDotOld())
1370 _need_dof_values_dot_old =
true;
1371 return _nodal_value_dot_old;
1374 mooseError(
"MooseVariableData: Old time derivative of solution (`u_dot_old`) is not stored. "
1375 "Please set uDotOldRequested() to true in FEProblemBase before requesting "
1379 mooseError(
"Nodal values can be requested only on nodal variables, variable '",
1384template <
typename OutputType>
1390 if (_sys.solutionUDotDotOld())
1392 _need_dof_values_dotdot_old =
true;
1393 return _nodal_value_dotdot_old;
1397 "MooseVariableData: Old second time derivative of solution (`u_dotdot_old`) is not "
1398 "stored. Please set uDotDotOldRequested() to true in FEProblemBase before "
1399 "requesting `u_dotdot_old`.");
1402 mooseError(
"Nodal values can be requested only on nodal variables, variable '",
1407template <
typename OutputType>
1411 if (_has_dof_indices)
1419 assignADNodalValue();
1423 zeroSizeDofValues();
1426template <
typename OutputType>
1430 mooseAssert(_ad_dof_values.size(),
"The AD dof values container must have size greater than 0");
1431 _ad_nodal_value = _ad_dof_values[0];
1438 const auto num_dofs = _dof_indices.size();
1439 mooseAssert(_ad_dof_values.size() == num_dofs,
1440 "Our dof values container size should match the dof indices container size");
1441 for (
const auto i : make_range(num_dofs))
1442 _ad_nodal_value(i) = _ad_dof_values[i];
1445template <
typename OutputType>
1449 if constexpr (std::is_same<RealEigenVector, OutputType>::value)
1450 _dof_map.array_dof_indices(_elem, _dof_indices, _var_num);
1452 _dof_map.dof_indices(_elem, _dof_indices, _var_num);
1454 mooseAssert(_dof_indices.size() % _count == 0,
1455 "The number of dof indices should divide cleanly by the variable count");
1456 const auto num_shapes = _dof_indices.size() / _count;
1457 _vector_tags_dof_u[_solution_tag].resize(num_shapes);
1459 unsigned int nqp = _qrule->n_points();
1460 _vector_tag_u[_solution_tag].resize(nqp);
1463template <
typename OutputType>
1467 if constexpr (std::is_same<OutputType, RealEigenVector>::value)
1468 _dof_map.array_dof_indices(_elem, _dof_indices, _var_num);
1470 _dof_map.dof_indices(_elem, _dof_indices, _var_num);
1472 _has_dof_values =
false;
1476 _has_dof_indices = _dof_indices.size();
1479template <
typename OutputType>
1483 if constexpr (std::is_same<OutputType, RealEigenVector>::value)
1484 _dof_map.array_dof_indices(_node, _dof_indices, _var_num);
1486 _dof_map.dof_indices(_node, _dof_indices, _var_num);
1488 const auto n_dofs = _dof_indices.size();
1493 _nodal_dof_index = _dof_indices[0];
1494 _has_dof_indices =
true;
1497 _has_dof_indices =
false;
1500template <
typename OutputType>
1508 if constexpr (std::is_same<RealEigenVector, OutputType>::value)
1509 _dof_map.array_dof_indices(_elem, _dof_indices, _var_num);
1511 _dof_map.dof_indices(_elem, _dof_indices, _var_num);
1512 if (_elem->n_dofs(_sys.number(), _var_num) > 0)
1516 _nodal_dof_index = _dof_indices[0];
1520 mooseAssert(_dof_indices.size() % _count == 0,
1521 "The number of dof indices should be cleanly divisible by the variable count");
1522 const auto num_shapes = _dof_indices.size() / _count;
1523 for (
auto & dof_u : _vector_tags_dof_u)
1524 dof_u.resize(num_shapes);
1526 for (
auto & dof_u : _matrix_tags_dof_u)
1527 dof_u.resize(num_shapes);
1529 _has_dof_indices =
true;
1532 _has_dof_indices =
false;
1535 _has_dof_indices =
false;
1538template <
typename OutputType>
1542 _dof_indices.clear();
1543 for (
const auto & node_id : nodes)
1545 auto && nd = _subproblem.mesh().getMesh().query_node_ptr(node_id);
1546 if (nd && (_subproblem.mesh().isSemiLocal(
const_cast<Node *
>(nd))))
1548 if (nd->n_dofs(_sys.number(), _var_num) > 0)
1550 if constexpr (std::is_same<RealEigenVector, OutputType>::value)
1552 static thread_local std::vector<dof_id_type> dof_indices;
1553 _dof_map.array_dof_indices(nd, dof_indices, _var_num);
1554 for (
const auto dof : dof_indices)
1555 _dof_indices.push_back(dof);
1559 dof_id_type dof = nd->dof_number(_sys.number(), _var_num, 0);
1560 _dof_indices.push_back(dof);
1566 if (!_dof_indices.empty())
1567 _has_dof_indices =
true;
1569 _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 face gradi...
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 needADGradPhi() const
Ask the assembly to compute the AD element shape function gradients, which this variable's AD gradien...
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)