https://mooseframework.inl.gov
Loading...
Searching...
No Matches
MooseVariableData.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#include "MooseVariableData.h"
11#include "MooseVariableField.h"
12#include "Assembly.h"
13#include "MooseError.h"
14#include "DisplacedSystem.h"
15#include "TimeIntegrator.h"
16#include "MooseVariableFE.h"
17#include "MooseTypes.h"
18
19#include "libmesh/quadrature.h"
20#include "libmesh/fe_base.h"
21#include "libmesh/system.h"
22#include "libmesh/type_n_tensor.h"
23#include "libmesh/fe_interface.h"
24
25template <typename OutputType>
27 SystemBase & sys,
28 THREAD_ID tid,
29 Moose::ElementType element_type,
30 const QBase * const & qrule_in,
31 const QBase * const & qrule_face_in,
32 const Node * const & node,
33 const Elem * const & elem)
34
35 : MooseVariableDataBase<OutputType>(var, sys, tid),
36 _var(var),
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),
41 _ad_zero(0),
42 _has_dof_indices(false),
43 _qrule(qrule_in),
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),
55 _node(node),
56 _elem(elem),
57 _displaced(dynamic_cast<const DisplacedSystem *>(&_sys) ? true : false),
58 _current_side(_assembly.side())
59{
60 _continuity = FEInterface::get_continuity(_fe_type);
61
62 _is_nodal = (_continuity == C_ZERO || _continuity == C_ONE);
63
65
66 // Initialize AD zero with zero derivatives
67 const auto old_do = ADReal::do_derivatives;
68 ADReal::do_derivatives = true;
69 _ad_zero = 0.;
70 ADReal::do_derivatives = old_do;
71
72 switch (_element_type)
73 {
75 {
76 _phi_assembly_method = &Assembly::fePhi<OutputShape>;
77 _phi_face_assembly_method = &Assembly::fePhiFace<OutputShape>;
78 _grad_phi_assembly_method = &Assembly::feGradPhi<OutputShape>;
79 _grad_phi_face_assembly_method = &Assembly::feGradPhiFace<OutputShape>;
80 _second_phi_assembly_method = &Assembly::feSecondPhi<OutputShape>;
81 _second_phi_face_assembly_method = &Assembly::feSecondPhiFace<OutputShape>;
82 _curl_phi_assembly_method = &Assembly::feCurlPhi<OutputShape>;
83 _curl_phi_face_assembly_method = &Assembly::feCurlPhiFace<OutputShape>;
84 _div_phi_assembly_method = &Assembly::feDivPhi<OutputShape>;
85 _div_phi_face_assembly_method = &Assembly::feDivPhiFace<OutputShape>;
86 _ad_grad_phi_assembly_method = &Assembly::feADGradPhi<OutputShape>;
87 _ad_grad_phi_face_assembly_method = &Assembly::feADGradPhiFace<OutputShape>;
88
91 break;
92 }
94 {
95 _phi_assembly_method = &Assembly::fePhiNeighbor<OutputShape>;
96 _phi_face_assembly_method = &Assembly::fePhiFaceNeighbor<OutputShape>;
97 _grad_phi_assembly_method = &Assembly::feGradPhiNeighbor<OutputShape>;
98 _grad_phi_face_assembly_method = &Assembly::feGradPhiFaceNeighbor<OutputShape>;
99 _second_phi_assembly_method = &Assembly::feSecondPhiNeighbor<OutputShape>;
100 _second_phi_face_assembly_method = &Assembly::feSecondPhiFaceNeighbor<OutputShape>;
101 _curl_phi_assembly_method = &Assembly::feCurlPhiNeighbor<OutputShape>;
102 _curl_phi_face_assembly_method = &Assembly::feCurlPhiFaceNeighbor<OutputShape>;
103 _div_phi_assembly_method = &Assembly::feDivPhiNeighbor<OutputShape>;
104 _div_phi_face_assembly_method = &Assembly::feDivPhiFaceNeighbor<OutputShape>;
105
106 _ad_grad_phi = nullptr;
107 _ad_grad_phi_face = nullptr;
108 break;
109 }
111 {
112 if (_use_dual)
113 {
114 _phi_assembly_method = &Assembly::feDualPhiLower<OutputType>;
115 _phi_face_assembly_method = &Assembly::feDualPhiLower<OutputType>; // Place holder
116 _grad_phi_assembly_method = &Assembly::feGradDualPhiLower<OutputType>;
117 _grad_phi_face_assembly_method = &Assembly::feGradDualPhiLower<OutputType>; // Place holder
118 }
119 else
120 {
121 _phi_assembly_method = &Assembly::fePhiLower<OutputType>;
122 _phi_face_assembly_method = &Assembly::fePhiLower<OutputType>; // Place holder
123 _grad_phi_assembly_method = &Assembly::feGradPhiLower<OutputType>;
124 _grad_phi_face_assembly_method = &Assembly::feGradPhiLower<OutputType>; // Place holder
125 }
126
127 _ad_grad_phi = nullptr;
128 _ad_grad_phi_face = nullptr;
129 break;
130 }
131 }
136}
137
138template <typename OutputType>
139void
141{
142 _assembly.needADGradPhiFace();
143}
144
145template <typename OutputType>
146void
148{
149 _assembly.needADGradPhi();
150}
151
152template <typename OutputType>
153void
155{
156 switch (gm_type)
157 {
158 case Moose::Volume:
159 {
160 _current_qrule = _qrule;
161 _current_phi = _phi;
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;
167 break;
168 }
169 case Moose::Face:
170 {
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;
178 break;
179 }
180 }
181}
182
183template <typename OutputType>
186{
187 if (_sys.solutionUDot())
188 {
189 _need_u_dot = true;
190 return _u_dot;
191 }
192 else
193 mooseError("MooseVariableFE: Time derivative of solution (`u_dot`) is not stored. Please set "
194 "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
195}
196
197template <typename OutputType>
200{
201 if (_sys.solutionUDotDot())
202 {
203 _need_u_dotdot = true;
204 return _u_dotdot;
205 }
206 else
207 mooseError("MooseVariableFE: Second time derivative of solution (`u_dotdot`) is not stored. "
208 "Please set uDotDotRequested() to true in FEProblemBase before requesting "
209 "`u_dotdot`.");
210}
211
212template <typename OutputType>
215{
216 if (_sys.solutionUDotOld())
217 {
218 _need_u_dot_old = true;
219 return _u_dot_old;
220 }
221 else
222 mooseError("MooseVariableFE: Old time derivative of solution (`u_dot_old`) is not stored. "
223 "Please set uDotOldRequested() to true in FEProblemBase before requesting "
224 "`u_dot_old`.");
225}
226
227template <typename OutputType>
230{
231 if (_sys.solutionUDotDotOld())
232 {
233 _need_u_dotdot_old = true;
234 return _u_dotdot_old;
235 }
236 else
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`");
240}
241
242template <typename OutputType>
245{
246 if (_sys.solutionUDot())
247 {
248 _need_grad_dot = true;
249 return _grad_u_dot;
250 }
251 else
252 mooseError("MooseVariableFE: Time derivative of solution (`u_dot`) is not stored. Please set "
253 "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
254}
255
256template <typename OutputType>
259{
260 if (_sys.solutionUDotDot())
261 {
262 _need_grad_dotdot = true;
263 return _grad_u_dotdot;
264 }
265 else
266 mooseError("MooseVariableFE: Second time derivative of solution (`u_dotdot`) is not stored. "
267 "Please set uDotDotRequested() to true in FEProblemBase before requesting "
268 "`u_dotdot`.");
269}
270
271template <typename OutputType>
274{
275 secondPhi();
276 secondPhiFace();
277 switch (state)
278 {
279 case Moose::Current:
280 {
281 _need_second = true;
282 return _second_u;
283 }
284
285 case Moose::Old:
286 {
287 _need_second_old = true;
288 return _second_u_old;
289 }
290
291 case Moose::Older:
292 {
293 _need_second_older = true;
294 return _second_u_older;
295 }
296
298 {
299 _need_second_previous_nl = true;
300 return _second_u_previous_nl;
301 }
302
303 default:
304 // We should never get here but gcc requires that we have a default. See
305 // htpps://stackoverflow.com/questions/18680378/after-defining-case-for-all-enum-values-compiler-still-says-control-reaches-e
306 mooseError("Unknown SolutionState!");
307 }
308}
309
310template <typename OutputType>
313{
314 curlPhi();
315 curlPhiFace();
316 switch (state)
317 {
318 case Moose::Current:
319 {
320 _need_curl = true;
321 return _curl_u;
322 }
323
324 case Moose::Old:
325 {
326 _need_curl_old = true;
327 return _curl_u_old;
328 }
329
330 case Moose::Older:
331 {
332 _need_curl_older = true;
333 return _curl_u_older;
334 }
335
336 default:
337 mooseError("We don't currently support curl from the previous non-linear iteration");
338 }
339}
340
341template <typename OutputType>
344{
345 divPhi();
346 divPhiFace();
347 switch (state)
348 {
349 case Moose::Current:
350 {
351 _need_div = true;
352 return _div_u;
353 }
354
355 case Moose::Old:
356 {
357 _need_div_old = true;
358 return _div_u_old;
359 }
360
361 case Moose::Older:
362 {
363 _need_div_older = true;
364 return _div_u_older;
365 }
366
367 default:
368 mooseError("We don't currently support divergence from the previous non-linear iteration");
369 }
370}
371
372template <typename OutputType>
375{
376 _second_phi = &_second_phi_assembly_method(_assembly, _fe_type);
377 return *_second_phi;
378}
379
380template <typename OutputType>
383{
384 _second_phi_face = &_second_phi_face_assembly_method(_assembly, _fe_type);
385 return *_second_phi_face;
386}
387
388template <typename OutputType>
391{
392 _curl_phi = &_curl_phi_assembly_method(_assembly, _fe_type);
393 return *_curl_phi;
394}
395
396template <typename OutputType>
399{
400 _curl_phi_face = &_curl_phi_face_assembly_method(_assembly, _fe_type);
401 return *_curl_phi_face;
402}
403
404template <typename OutputType>
407{
408 _div_phi = &_div_phi_assembly_method(_assembly, _fe_type);
409 return *_div_phi;
410}
411
412template <typename OutputType>
415{
416 _div_phi_face = &_div_phi_face_assembly_method(_assembly, _fe_type);
417 return *_div_phi_face;
418}
419
420template <typename OutputType>
421template <bool constant_monomial,
422 typename DestinationType,
423 typename ShapeType,
424 typename DofValuesType>
425void
427 const ShapeType & phi,
428 const DofValuesType & dof_values,
429 const unsigned int nqp,
430 const std::size_t num_shapes)
431{
432 if constexpr (constant_monomial)
433 libmesh_ignore(num_shapes);
434
435 // Deduce OutputType
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");
440
441 // this is only used in the RealEigenVector case to get this->_count
442 if constexpr (!is_eigen)
443 libmesh_ignore(this);
444
445 // Deduce type of value within dest MooseArray
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");
461
462 // Sets a value to zero at a quadrature point
463 const auto set_zero = [this, &dest](const auto qp)
464 {
465 if constexpr (!is_eigen)
466 libmesh_ignore(this);
467
468 if constexpr (is_real || is_real_vector)
469 dest[qp] = 0;
470 else if constexpr (is_eigen)
471 {
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);
478 else
479 static_assert(Moose::always_false<OutputType, dest_array_type>, "Unsupported type");
480 }
481 else
482 static_assert(Moose::always_false<OutputType, dest_array_type>, "Unsupported type");
483 };
484
485 // Accumulates a value
486 const auto accumulate = [&dest, &phi, &dof_values](const auto i, const auto qp)
487 {
488 if constexpr (is_real || is_real_vector || (is_eigen && is_value))
489 {
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]);
494 else
495 static_assert(Moose::always_false<OutputType, dest_array_type>, "Unsupported type");
496 }
497 else if constexpr (is_eigen)
498 {
499 if constexpr (is_gradient)
500 {
501 for (const auto d : make_range(Moose::dim))
502 dest[qp].col(d) += phi[i][qp](d) * dof_values[i];
503 }
504 else if constexpr (is_second)
505 {
506 for (unsigned int d = 0, d1 = 0; d1 < LIBMESH_DIM; ++d1)
507 for (const auto d2 : make_range(Moose::dim))
508 dest[qp].col(d++) += phi[i][qp](d1, d2) * dof_values[i];
509 }
510 else
511 static_assert(Moose::always_false<OutputType, dest_array_type>, "Unsupported type");
512 }
513 else
514 static_assert(Moose::always_false<OutputType, dest_array_type>, "Unsupported type");
515 };
516
517 dest.resize(nqp);
518
519 // Monomial case, accumulate dest[0] and set dest[>0] to dest[0]
520 if constexpr (constant_monomial)
521 {
522 mooseAssert(num_shapes == 1, "Should have only one shape function for a constant monomial");
523 set_zero(0);
524 accumulate(0, 0);
525 for (unsigned int qp = 1; qp < nqp; ++qp)
526 dest[qp] = dest[0];
527 }
528 // Non constant monomial case
529 else
530 {
531 for (const auto qp : make_range(nqp))
532 set_zero(qp);
533 for (const auto i : make_range(num_shapes))
534 for (const auto qp : make_range(nqp))
535 accumulate(i, qp);
536 }
537}
538
539template <typename OutputType>
540template <bool constant_monomial>
541void
543{
544 const auto num_dofs = _dof_indices.size();
545 const auto num_shapes = num_dofs / _count;
546
547 if (num_dofs > 0)
548 fetchDofValues();
549
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);
554
555 // Map grad_phi using Eigen so that we can perform array operations easier
556 if constexpr (std::is_same_v<OutputType, RealEigenVector>)
557 {
558 if (_qrule == _current_qrule)
559 {
560 _mapped_grad_phi.resize(num_shapes);
561 for (const auto i : make_range(num_shapes))
562 {
563 _mapped_grad_phi[i].resize(nqp, Eigen::Map<RealDIMValue>(nullptr));
564 for (const auto qp : make_range(nqp))
565 // Note: this does NOT do any allocation. It is "reconstructing" the object in place
566 new (&_mapped_grad_phi[i][qp])
567 Eigen::Map<RealDIMValue>(const_cast<Real *>(&(*_current_grad_phi)[i][qp](0)));
568 }
569 }
570 else
571 {
572 _mapped_grad_phi_face.resize(num_shapes);
573 for (const auto i : make_range(num_shapes))
574 {
575 _mapped_grad_phi_face[i].resize(nqp, Eigen::Map<RealDIMValue>(nullptr));
576 for (const auto qp : make_range(nqp))
577 // Note: this does NOT do any allocation. It is "reconstructing" the object in place
578 new (&_mapped_grad_phi_face[i][qp])
579 Eigen::Map<RealDIMValue>(const_cast<Real *>(&(*_current_grad_phi)[i][qp](0)));
580 }
581 }
582 }
583
584 mooseAssert(
585 !(_need_second || _need_second_old || _need_second_older || _need_second_previous_nl) ||
586 _current_second_phi,
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!");
592
593 // Curl
594 if (_need_curl)
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);
600
601 // Div
602 if (_need_div)
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);
608
609 // Second
610 if (_need_second)
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],
617 nqp,
618 num_shapes);
619
620 // Vector tags
621 for (auto tag : _required_vector_tags)
622 {
623 if (_need_vector_tag_u[tag] && _sys.hasVector(tag))
624 {
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);
628 }
629 if (_need_vector_tag_grad[tag] && _sys.hasVector(tag))
630 {
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);
634 }
635 }
636
637 // Matrix tags
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);
642
643 // Derivatives and old values
644 if (is_transient)
645 {
646 if (_need_second_old)
647 fill<constant_monomial>(_second_u_old,
648 *_current_second_phi,
649 _vector_tags_dof_u[_old_solution_tag],
650 nqp,
651 num_shapes);
652 if (_need_second_older)
653 fill<constant_monomial>(_second_u_older,
654 *_current_second_phi,
655 _vector_tags_dof_u[_older_solution_tag],
656 nqp,
657 num_shapes);
658 if (_need_u_dot)
659 fill<constant_monomial>(_u_dot, *_current_phi, _dof_values_dot, nqp, num_shapes);
660 if (_need_u_dotdot)
661 fill<constant_monomial>(_u_dotdot, *_current_phi, _dof_values_dotdot, nqp, num_shapes);
662 if (_need_u_dot_old)
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);
667
668 if (_need_du_dot_du)
669 {
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];
674 }
675 if (_need_du_dotdot_du)
676 {
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];
681 }
682
683 if (_need_grad_dot)
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);
688 }
689
690 // A variable whose AD was only ever requested through the face-scoped accessors has no
691 // consumer on element interiors, so seeding the derivatives there is wasted work. In the
692 // volume context _current_qrule is _qrule; see setGeometry().
693 if (_need_ad && (_need_ad_volume || _current_qrule != _qrule))
694 computeAD<constant_monomial>(num_dofs, nqp);
695}
696
697template <typename OutputType>
698void
700{
701 computeValuesInternal</* constant_monomial = */ false>();
702}
703
704template <typename OutputType>
705void
707{
708 if (_dof_indices.size() == 0)
709 return;
710
711 // Monomial optimizations are not appropriate after p-refinement
712 if (_elem->p_level())
713 computeValues();
714 else
715 computeValuesInternal</* constant_monomial = */ true>();
716}
717
718template <typename OutputType>
719void
721{
722 const auto num_dofs = _dof_indices.size();
723
724 const bool do_derivatives = Moose::doDerivatives(_subproblem, _sys);
725
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];
729 // NOTE! You have to do this AFTER setting the value!
730 if (do_derivatives)
731 for (const auto i : make_range(num_dofs))
732 Moose::derivInsert(_ad_dof_values[i].derivatives(), _dof_indices[i], 1.);
733
734 const bool is_transient = _subproblem.isTransient();
735 if (is_transient && _need_ad_u_dot)
736 {
737 _ad_dofs_dot.resize(num_dofs);
738 if (_need_ad_u_dotdot)
739 _ad_dofs_dotdot.resize(num_dofs);
740
741 if (_time_integrator)
742 {
743 if (_time_integrator->dt())
744 {
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],
749 _dof_indices[i],
750 _need_ad_u_dotdot ? _ad_dofs_dotdot[i]
751 : _ad_real_dummy);
752 }
753 else
754 // Executing something with a time derivative at initial should not put a NaN
755 for (const auto i : make_range(num_dofs))
756 {
757 _ad_dofs_dot[i] = 0.;
758 if (_need_ad_u_dotdot)
759 _ad_dofs_dotdot[i] = 0;
760 }
761 }
762 // We are too early in the setup to have a time integrator, so we are not really using the
763 // AD-derivatives. We set the AD value of the derivatives to the nonAD value
764 else
765 for (const auto i : make_range(num_dofs))
766 {
767 _ad_dofs_dot[i] = _dof_values_dot[i];
768 if (_need_ad_u_dotdot)
769 _ad_dofs_dotdot[i] = _dof_values_dotdot[i];
770 }
771 }
772}
773
774template <>
775void
777{
778 const auto num_dofs = _dof_indices.size();
779
780 const bool do_derivatives = Moose::doDerivatives(_subproblem, _sys);
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");
784
785 _ad_dof_values.resize(n_test);
786 // Test is outer, count is inner
787 for (const auto i : make_range(n_test))
788 {
789 _ad_dof_values[i].resize(_count);
790 for (const auto j : make_range(_count))
791 {
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);
795 // NOTE! You have to do this AFTER setting the value!
796 if (do_derivatives)
797 Moose::derivInsert(dual_number.derivatives(), global_dof_index, 1.);
798 }
799 }
800
801 const bool is_transient = _subproblem.isTransient();
802 if (is_transient && _need_ad_u_dot)
803 {
804 _ad_dofs_dot.resize(n_test);
805 if (_need_ad_u_dotdot)
806 _ad_dofs_dotdot.resize(n_test);
807
808 for (const auto i : make_range(n_test))
809 {
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))
814 {
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)
818 {
819 if (_time_integrator->dt())
820 {
821 dot = _ad_dof_values[i](j);
822 _time_integrator->computeADTimeDerivatives(dot, _dof_indices[j * n_test + i], dotdot);
823 }
824 else
825 {
826 // Executing something with a time derivative at initial should not put a NaN
827 dot = 0;
828 dotdot = 0;
829 }
830 }
831 // We are too early in the setup to have a time integrator, so we are not really using
832 // the AD-derivatives. We set the AD value of the derivatives to the nonAD value
833 else
834 {
835 dot = _dof_values_dot[i](j);
836 if (_need_ad_u_dotdot)
837 dotdot = _dof_values_dotdot[i](j);
838 }
839 }
840 }
841 }
842}
843
844template <typename OutputType>
845template <bool constant_monomial>
846void
847MooseVariableData<OutputType>::computeAD(const unsigned int num_dofs, const unsigned int nqp)
848{
849 fetchADDofValues();
850 const auto n_test = num_dofs / _count;
851
852 // Values
853 if (_need_ad_u)
854 fill<constant_monomial>(_ad_u, *_current_phi, _ad_dof_values, nqp, n_test);
855 // Grad. On an element face, only fill the gradient when a face object requested it. Otherwise it
856 // stays empty so that a face object that read it through the volume accessor adGradSln() fails
857 // the bounds assertion instead of silently using gradients built without the AD face shape
858 // function gradients. Neighbor data never uses AD shape function gradients and is not affected.
859 const bool on_element_face =
860 _element_type == Moose::ElementType::Element && _current_qrule != _qrule;
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)
864 {
865 // The latter check here is for handling the fact that we have not yet implemented
866 // calculation of ad_grad_phi for neighbor and neighbor-face, so if we are in that
867 // situation we need to default to using the non-ad grad_phi
868 if (_displaced && _current_ad_grad_phi)
869 fill<constant_monomial>(_ad_grad_u, *_current_ad_grad_phi, _ad_dof_values, nqp, n_test);
870 else
871 fill<constant_monomial>(_ad_grad_u, *_current_grad_phi, _ad_dof_values, nqp, n_test);
872 }
873 // Second
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);
877 // Curl
878 if (_need_ad_curl_u)
879 fill<constant_monomial>(_ad_curl_u, *_current_curl_phi, _ad_dof_values, nqp, n_test);
880 // Div
881 if (_need_ad_div_u)
882 fill<constant_monomial>(_ad_div_u, *_current_div_phi, _ad_dof_values, nqp, n_test);
883
884 const bool is_transient = _subproblem.isTransient();
885 if (is_transient)
886 {
887 if (_need_ad_u_dot)
888 {
889 if (_time_integrator)
890 fill<constant_monomial>(_ad_u_dot, *_current_phi, _ad_dofs_dot, nqp, n_test);
891 // We are too early in the setup to have a time integrator, so we are not really using the
892 // AD-derivatives. We set the AD value of the derivatives to the nonAD value
893 else
894 {
895 _ad_u_dot.resize(nqp);
896 for (const auto qp : make_range(nqp))
897 _ad_u_dot[qp] = _u_dot[qp];
898 }
899 }
900
901 if (_need_ad_u_dotdot)
902 {
903 if (_time_integrator)
904 fill<constant_monomial>(_ad_u_dotdot, *_current_phi, _ad_dofs_dotdot, nqp, n_test);
905 else
906 {
907 _ad_u_dotdot.resize(nqp);
908 for (const auto qp : make_range(nqp))
909 _ad_u_dotdot[qp] = _u_dotdot[qp];
910 }
911 }
912
913 // The gradient time derivative is volume-only, so on an element face it is left empty for the
914 // same reason as the gradient above
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)
918 {
919 if (_time_integrator)
920 {
921 // The latter check here is for handling the fact that we have not yet implemented
922 // calculation of ad_grad_phi for neighbor and neighbor-face, so if we are in that
923 // situation we need to default to using the non-ad grad_phi
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);
926 else
927 fill<constant_monomial>(_ad_grad_u_dot, *_current_grad_phi, _ad_dofs_dot, nqp, n_test);
928 }
929 else
930 {
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];
934 }
935 }
936 }
937}
938
939template <typename OutputType>
940void
941MooseVariableData<OutputType>::setDofValue(const DofValue & value, unsigned int index)
942{
943 auto & dof_values = _vector_tags_dof_u[_solution_tag];
944 dof_values[index] = value;
945 _has_dof_values = true;
946
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))
951 u[qp] *= 0.;
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];
955}
956
957template <typename OutputType>
958void
960{
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);
964
965 _has_dof_values = true;
966
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))
971 u[qp] *= 0.;
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];
975}
976
977template <typename OutputType>
978void
979MooseVariableData<OutputType>::insertNodalValue(NumericVector<Number> & residual,
980 const DofValue & v)
981{
982 residual.set(_nodal_dof_index, v);
983}
984
985template <>
986void
988 const RealEigenVector & v)
989{
990 for (const auto j : make_range(_count))
991 residual.set(_nodal_dof_index + j, v(j));
992}
993
994template <typename OutputType>
997{
998 mooseAssert(_subproblem.mesh().isSemiLocal(const_cast<Node *>(&node)), "Node is not Semilocal");
999
1000 // Make sure that the node has DOFs
1001 /* Note, this is a reproduction of an assert within libMesh::Node::dof_number, this is done to
1002 * produce a better error (see misc/check_error.node_value_off_block) */
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");
1006
1007 dof_id_type dof = node.dof_number(_sys.number(), _var_num, 0);
1008
1009 switch (state)
1010 {
1011 case Moose::Current:
1012 return (*_sys.currentSolution())(dof);
1013
1014 case Moose::Old:
1015 return _sys.solutionOld()(dof);
1016
1017 case Moose::Older:
1018 return _sys.solutionOlder()(dof);
1019
1020 default:
1021 mooseError("PreviousNL not currently supported for getNodalValue");
1022 }
1023}
1024
1025template <>
1026RealEigenVector
1028 Moose::SolutionState state) const
1029{
1030 mooseAssert(_subproblem.mesh().isSemiLocal(const_cast<Node *>(&node)), "Node is not Semilocal");
1031
1032 // Make sure that the node has DOFs
1033 /* Note, this is a reproduction of an assert within libMesh::Node::dof_number, this is done to
1034 * produce a better error (see misc/check_error.node_value_off_block) */
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");
1038
1039 dof_id_type dof = node.dof_number(_sys.number(), _var_num, 0);
1040
1041 RealEigenVector v(_count);
1042 switch (state)
1043 {
1044 case Moose::Current:
1045 for (unsigned int i = 0; i < _count; ++i)
1046 v(i) = (*_sys.currentSolution())(dof++);
1047 break;
1048
1049 case Moose::Old:
1050 for (unsigned int i = 0; i < _count; ++i)
1051 v(i) = _sys.solutionOld()(dof++);
1052 break;
1053
1054 case Moose::Older:
1055 for (unsigned int i = 0; i < _count; ++i)
1056 v(i) = _sys.solutionOlder()(dof++);
1057 break;
1058
1059 default:
1060 mooseError("PreviousNL not currently supported for getNodalValue");
1061 }
1062 return v;
1063}
1064
1065template <typename OutputType>
1068 const Moose::SolutionState state,
1069 const unsigned int idx) const
1070{
1071 static thread_local std::vector<dof_id_type> dof_indices;
1072 _dof_map.dof_indices(elem, dof_indices, _var_num);
1073
1074 switch (state)
1075 {
1076 case Moose::Current:
1077 return (*_sys.currentSolution())(dof_indices[idx]);
1078
1079 case Moose::Old:
1080 return _sys.solutionOld()(dof_indices[idx]);
1081
1082 case Moose::Older:
1083 return _sys.solutionOlder()(dof_indices[idx]);
1084
1085 default:
1086 mooseError("PreviousNL not currently supported for getElementalValue");
1087 }
1088}
1089
1090template <>
1091RealEigenVector
1093 const Moose::SolutionState state,
1094 const unsigned int idx) const
1095{
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 "
1100 "average value");
1101
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;
1107
1108 RealEigenVector v(_count);
1109
1110 switch (state)
1111 {
1112 case Moose::Current:
1113 for (unsigned int i = 0; i < _count; ++i)
1114 v(i) = (*_sys.currentSolution())(dof_indices[i * num_shapes + idx]);
1115 break;
1116
1117 case Moose::Old:
1118 for (unsigned int i = 0; i < _count; ++i)
1119 v(i) = _sys.solutionOld()(dof_indices[i * num_shapes + idx]);
1120 break;
1121
1122 case Moose::Older:
1123 for (unsigned int i = 0; i < _count; ++i)
1124 v(i) = _sys.solutionOlder()(dof_indices[i * num_shapes + idx]);
1125 break;
1126
1127 default:
1128 mooseError("PreviousNL not currently supported for getElementalValue");
1129 }
1130 return v;
1131}
1132
1133template <typename OutputType>
1134void
1136 std::vector<dof_id_type> & dof_indices) const
1137{
1138 if constexpr (std::is_same<OutputType, RealEigenVector>::value)
1139 _dof_map.array_dof_indices(elem, dof_indices, _var_num);
1140 else
1141 _dof_map.dof_indices(elem, dof_indices, _var_num);
1142}
1143
1144template <typename OutputType>
1145void
1147 const DenseVector<Number> & v) const
1148{
1149 sol.add_vector(v, _dof_indices);
1150}
1151
1152template <typename OutputType>
1155{
1156 if (_sys.solutionUDot())
1157 {
1158 _need_dof_values_dot = true;
1159 return _dof_values_dot;
1160 }
1161 else
1162 mooseError("MooseVariableData: Time derivative of solution (`u_dot`) is not stored. Please set "
1163 "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
1164}
1165
1166template <typename OutputType>
1169{
1170 if (_sys.solutionUDotDot())
1171 {
1172 _need_dof_values_dotdot = true;
1173 return _dof_values_dotdot;
1174 }
1175 else
1176 mooseError("MooseVariableData: Second time derivative of solution (`u_dotdot`) is not stored. "
1177 "Please set uDotDotRequested() to true in FEProblemBase before requesting "
1178 "`u_dotdot`.");
1179}
1180
1181template <typename OutputType>
1184{
1185 if (_sys.solutionUDotOld())
1186 {
1187 _need_dof_values_dot_old = true;
1188 return _dof_values_dot_old;
1189 }
1190 else
1191 mooseError("MooseVariableData: Old time derivative of solution (`u_dot_old`) is not stored. "
1192 "Please set uDotOldRequested() to true in FEProblemBase before requesting "
1193 "`u_dot_old`.");
1194}
1195
1196template <typename OutputType>
1199{
1200 if (_sys.solutionUDotDotOld())
1201 {
1202 _need_dof_values_dotdot_old = true;
1203 return _dof_values_dotdot_old;
1204 }
1205 else
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`.");
1209}
1210
1211template <typename OutputType>
1212const MooseArray<Number> &
1214{
1215 _need_dof_du_dot_du = true;
1216 return _dof_du_dot_du;
1217}
1218
1219template <typename OutputType>
1220const MooseArray<Number> &
1222{
1223 _need_dof_du_dotdot_du = true;
1224 return _dof_du_dotdot_du;
1225}
1226
1227template <typename OutputType>
1228void
1229MooseVariableData<OutputType>::computeIncrementAtQps(const NumericVector<Number> & increment_vec)
1230{
1231 unsigned int nqp = _qrule->n_points();
1232
1233 _increment.resize(nqp);
1234 // Compute the increment at each quadrature point
1235 unsigned int num_dofs = _dof_indices.size();
1236 for (const auto qp : make_range(nqp))
1237 {
1238 _increment[qp] = 0.;
1239 for (const auto i : make_range(num_dofs))
1240 _increment[qp] += (*_phi)[i][qp] * increment_vec(_dof_indices[i]);
1241 }
1242}
1243
1244template <>
1245void
1247 const NumericVector<Number> & increment_vec)
1248{
1249 unsigned int nqp = _qrule->n_points();
1250
1251 _increment.resize(nqp);
1252 // Compute the increment at each quadrature point
1253 unsigned int num_dofs = _dof_indices.size();
1254 if (isNodal())
1255 {
1256 for (const auto qp : make_range(nqp))
1257 {
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);
1261 }
1262 }
1263 else
1264 {
1265 for (const auto qp : make_range(nqp))
1266 {
1267 unsigned int n = 0;
1268 for (const auto j : make_range(_count))
1269 for (const auto i : make_range(num_dofs))
1270 {
1271 _increment[qp](j) += (*_phi)[i][qp] * increment_vec(_dof_indices[i] + n);
1272 n += num_dofs;
1273 }
1274 }
1275 }
1276}
1277
1278template <typename OutputType>
1279void
1280MooseVariableData<OutputType>::computeIncrementAtNode(const NumericVector<Number> & increment_vec)
1281{
1282 if (!isNodal())
1283 mooseError("computeIncrementAtNode can only be called for nodal variables");
1284
1285 _increment.resize(1);
1286
1287 // Compute the increment for the current DOF
1288 _increment[0] = increment_vec(_dof_indices[0]);
1289}
1290
1291template <>
1292void
1294 const NumericVector<Number> & increment_vec)
1295{
1296 if (!isNodal())
1297 mooseError("computeIncrementAtNode can only be called for nodal variables");
1298
1299 _increment.resize(1);
1300
1301 // Compute the increment for the current DOF
1302 if (isNodal())
1303 for (unsigned int j = 0; j < _count; j++)
1304 _increment[0](j) = increment_vec(_dof_indices[0] + j);
1305 else
1306 {
1307 unsigned int n = 0;
1308 const auto n_dof_indices = _dof_indices.size();
1309 for (const auto j : make_range(_count))
1310 {
1311 _increment[0](j) = increment_vec(_dof_indices[0] + n);
1312 n += n_dof_indices;
1313 }
1314 }
1315}
1316
1317template <typename OutputType>
1318const OutputType &
1320{
1321 if (isNodal())
1322 {
1323 if (_sys.solutionUDot())
1324 {
1325 _need_dof_values_dot = true;
1326 return _nodal_value_dot;
1327 }
1328 else
1329 mooseError(
1330 "MooseVariableData: Time derivative of solution (`u_dot`) is not stored. Please set "
1331 "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
1332 }
1333 else
1334 mooseError("Nodal values can be requested only on nodal variables, variable '",
1335 var().name(),
1336 "' is not nodal.");
1337}
1338
1339template <typename OutputType>
1340const OutputType &
1342{
1343 if (isNodal())
1344 {
1345 if (_sys.solutionUDotDot())
1346 {
1347 _need_dof_values_dotdot = true;
1348 return _nodal_value_dotdot;
1349 }
1350 else
1351 mooseError(
1352 "MooseVariableData: Second time derivative of solution (`u_dotdot`) is not stored. "
1353 "Please set uDotDotRequested() to true in FEProblemBase before requesting "
1354 "`u_dotdot`.");
1355 }
1356 else
1357 mooseError("Nodal values can be requested only on nodal variables, variable '",
1358 var().name(),
1359 "' is not nodal.");
1360}
1361
1362template <typename OutputType>
1363const OutputType &
1365{
1366 if (isNodal())
1367 {
1368 if (_sys.solutionUDotOld())
1369 {
1370 _need_dof_values_dot_old = true;
1371 return _nodal_value_dot_old;
1372 }
1373 else
1374 mooseError("MooseVariableData: Old time derivative of solution (`u_dot_old`) is not stored. "
1375 "Please set uDotOldRequested() to true in FEProblemBase before requesting "
1376 "`u_dot_old`.");
1377 }
1378 else
1379 mooseError("Nodal values can be requested only on nodal variables, variable '",
1380 var().name(),
1381 "' is not nodal.");
1382}
1383
1384template <typename OutputType>
1385const OutputType &
1387{
1388 if (isNodal())
1389 {
1390 if (_sys.solutionUDotDotOld())
1391 {
1392 _need_dof_values_dotdot_old = true;
1393 return _nodal_value_dotdot_old;
1394 }
1395 else
1396 mooseError(
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`.");
1400 }
1401 else
1402 mooseError("Nodal values can be requested only on nodal variables, variable '",
1403 var().name(),
1404 "' is not nodal.");
1405}
1406
1407template <typename OutputType>
1408void
1410{
1411 if (_has_dof_indices)
1412 {
1413 fetchDofValues();
1414 assignNodalValue();
1415
1416 if (_need_ad)
1417 {
1418 fetchADDofValues();
1419 assignADNodalValue();
1420 }
1421 }
1422 else
1423 zeroSizeDofValues();
1424}
1425
1426template <typename OutputType>
1427void
1429{
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];
1432}
1433
1434template <>
1435void
1437{
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];
1443}
1444
1445template <typename OutputType>
1446void
1448{
1449 if constexpr (std::is_same<RealEigenVector, OutputType>::value)
1450 _dof_map.array_dof_indices(_elem, _dof_indices, _var_num);
1451 else
1452 _dof_map.dof_indices(_elem, _dof_indices, _var_num);
1453
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);
1458
1459 unsigned int nqp = _qrule->n_points();
1460 _vector_tag_u[_solution_tag].resize(nqp);
1461}
1462
1463template <typename OutputType>
1464void
1466{
1467 if constexpr (std::is_same<OutputType, RealEigenVector>::value)
1468 _dof_map.array_dof_indices(_elem, _dof_indices, _var_num);
1469 else
1470 _dof_map.dof_indices(_elem, _dof_indices, _var_num);
1471
1472 _has_dof_values = false;
1473
1474 // FIXME: remove this when the Richard's module is migrated to use the new NodalCoupleable
1475 // interface.
1476 _has_dof_indices = _dof_indices.size();
1477}
1478
1479template <typename OutputType>
1480void
1482{
1483 if constexpr (std::is_same<OutputType, RealEigenVector>::value)
1484 _dof_map.array_dof_indices(_node, _dof_indices, _var_num);
1485 else
1486 _dof_map.dof_indices(_node, _dof_indices, _var_num);
1487
1488 const auto n_dofs = _dof_indices.size();
1489 if (n_dofs)
1490 {
1491 // For standard variables. _nodal_dof_index is retrieved by nodalDofIndex() which is used in
1492 // NodalBC for example
1493 _nodal_dof_index = _dof_indices[0];
1494 _has_dof_indices = true;
1495 }
1496 else
1497 _has_dof_indices = false;
1498}
1499
1500template <typename OutputType>
1501void
1503{
1504 /* FIXME: this method is only for elemental auxiliary variables, so
1505 * we may want to rename it */
1506 if (_elem)
1507 {
1508 if constexpr (std::is_same<RealEigenVector, OutputType>::value)
1509 _dof_map.array_dof_indices(_elem, _dof_indices, _var_num);
1510 else
1511 _dof_map.dof_indices(_elem, _dof_indices, _var_num);
1512 if (_elem->n_dofs(_sys.number(), _var_num) > 0)
1513 {
1514 // FIXME: Setting _nodal_dof_index inside of a method that apparently is only for "elemental"
1515 // aux variables seems absolutely absurd
1516 _nodal_dof_index = _dof_indices[0];
1517
1518 fetchDofValues();
1519
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);
1525
1526 for (auto & dof_u : _matrix_tags_dof_u)
1527 dof_u.resize(num_shapes);
1528
1529 _has_dof_indices = true;
1530 }
1531 else
1532 _has_dof_indices = false;
1533 }
1534 else
1535 _has_dof_indices = false;
1536}
1537
1538template <typename OutputType>
1539void
1540MooseVariableData<OutputType>::reinitNodes(const std::vector<dof_id_type> & nodes)
1541{
1542 _dof_indices.clear();
1543 for (const auto & node_id : nodes)
1544 {
1545 auto && nd = _subproblem.mesh().getMesh().query_node_ptr(node_id);
1546 if (nd && (_subproblem.mesh().isSemiLocal(const_cast<Node *>(nd))))
1547 {
1548 if (nd->n_dofs(_sys.number(), _var_num) > 0)
1549 {
1550 if constexpr (std::is_same<RealEigenVector, OutputType>::value)
1551 {
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);
1556 }
1557 else
1558 {
1559 dof_id_type dof = nd->dof_number(_sys.number(), _var_num, 0);
1560 _dof_indices.push_back(dof);
1561 }
1562 }
1563 }
1564 }
1565
1566 if (!_dof_indices.empty())
1567 _has_dof_indices = true;
1568 else
1569 _has_dof_indices = false;
1570}
1571
1572template class MooseVariableData<Real>;
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
void mooseDeprecated(Args &&... args)
Emit a deprecated code/feature message with the given stringified, concatenated args.
Definition MooseError.h:363
unsigned int THREAD_ID
Definition MooseTypes.h:237
std::array< Real, 2 > values
Definition MortarUtils.C:52
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.
Definition MooseArray.h:216
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)
Definition SystemBase.h:87
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)
Definition ADUtils.C:83
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
Definition Moose.h:175
SolutionState
Definition MooseTypes.h:262
@ Current
Definition MooseTypes.h:263
@ PreviousNL
Definition MooseTypes.h:266
void derivInsert(SemiDynamicSparseNumberArray< Real, libMesh::dof_id_type, NWrapper< N > > &derivs, libMesh::dof_id_type index, Real value)
Definition ADReal.h:21