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 switch (gm_type)
150 {
151 case Moose::Volume:
152 {
153 _current_qrule = _qrule;
154 _current_phi = _phi;
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;
160 break;
161 }
162 case Moose::Face:
163 {
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;
171 break;
172 }
173 }
174}
175
176template <typename OutputType>
179{
180 if (_sys.solutionUDot())
181 {
182 _need_u_dot = true;
183 return _u_dot;
184 }
185 else
186 mooseError("MooseVariableFE: Time derivative of solution (`u_dot`) is not stored. Please set "
187 "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
188}
189
190template <typename OutputType>
193{
194 if (_sys.solutionUDotDot())
195 {
196 _need_u_dotdot = true;
197 return _u_dotdot;
198 }
199 else
200 mooseError("MooseVariableFE: Second time derivative of solution (`u_dotdot`) is not stored. "
201 "Please set uDotDotRequested() to true in FEProblemBase before requesting "
202 "`u_dotdot`.");
203}
204
205template <typename OutputType>
208{
209 if (_sys.solutionUDotOld())
210 {
211 _need_u_dot_old = true;
212 return _u_dot_old;
213 }
214 else
215 mooseError("MooseVariableFE: Old time derivative of solution (`u_dot_old`) is not stored. "
216 "Please set uDotOldRequested() to true in FEProblemBase before requesting "
217 "`u_dot_old`.");
218}
219
220template <typename OutputType>
223{
224 if (_sys.solutionUDotDotOld())
225 {
226 _need_u_dotdot_old = true;
227 return _u_dotdot_old;
228 }
229 else
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`");
233}
234
235template <typename OutputType>
238{
239 if (_sys.solutionUDot())
240 {
241 _need_grad_dot = true;
242 return _grad_u_dot;
243 }
244 else
245 mooseError("MooseVariableFE: Time derivative of solution (`u_dot`) is not stored. Please set "
246 "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
247}
248
249template <typename OutputType>
252{
253 if (_sys.solutionUDotDot())
254 {
255 _need_grad_dotdot = true;
256 return _grad_u_dotdot;
257 }
258 else
259 mooseError("MooseVariableFE: Second time derivative of solution (`u_dotdot`) is not stored. "
260 "Please set uDotDotRequested() to true in FEProblemBase before requesting "
261 "`u_dotdot`.");
262}
263
264template <typename OutputType>
267{
268 secondPhi();
269 secondPhiFace();
270 switch (state)
271 {
272 case Moose::Current:
273 {
274 _need_second = true;
275 return _second_u;
276 }
277
278 case Moose::Old:
279 {
280 _need_second_old = true;
281 return _second_u_old;
282 }
283
284 case Moose::Older:
285 {
286 _need_second_older = true;
287 return _second_u_older;
288 }
289
291 {
292 _need_second_previous_nl = true;
293 return _second_u_previous_nl;
294 }
295
296 default:
297 // We should never get here but gcc requires that we have a default. See
298 // htpps://stackoverflow.com/questions/18680378/after-defining-case-for-all-enum-values-compiler-still-says-control-reaches-e
299 mooseError("Unknown SolutionState!");
300 }
301}
302
303template <typename OutputType>
306{
307 curlPhi();
308 curlPhiFace();
309 switch (state)
310 {
311 case Moose::Current:
312 {
313 _need_curl = true;
314 return _curl_u;
315 }
316
317 case Moose::Old:
318 {
319 _need_curl_old = true;
320 return _curl_u_old;
321 }
322
323 case Moose::Older:
324 {
325 _need_curl_older = true;
326 return _curl_u_older;
327 }
328
329 default:
330 mooseError("We don't currently support curl from the previous non-linear iteration");
331 }
332}
333
334template <typename OutputType>
337{
338 divPhi();
339 divPhiFace();
340 switch (state)
341 {
342 case Moose::Current:
343 {
344 _need_div = true;
345 return _div_u;
346 }
347
348 case Moose::Old:
349 {
350 _need_div_old = true;
351 return _div_u_old;
352 }
353
354 case Moose::Older:
355 {
356 _need_div_older = true;
357 return _div_u_older;
358 }
359
360 default:
361 mooseError("We don't currently support divergence from the previous non-linear iteration");
362 }
363}
364
365template <typename OutputType>
368{
369 _second_phi = &_second_phi_assembly_method(_assembly, _fe_type);
370 return *_second_phi;
371}
372
373template <typename OutputType>
376{
377 _second_phi_face = &_second_phi_face_assembly_method(_assembly, _fe_type);
378 return *_second_phi_face;
379}
380
381template <typename OutputType>
384{
385 _curl_phi = &_curl_phi_assembly_method(_assembly, _fe_type);
386 return *_curl_phi;
387}
388
389template <typename OutputType>
392{
393 _curl_phi_face = &_curl_phi_face_assembly_method(_assembly, _fe_type);
394 return *_curl_phi_face;
395}
396
397template <typename OutputType>
400{
401 _div_phi = &_div_phi_assembly_method(_assembly, _fe_type);
402 return *_div_phi;
403}
404
405template <typename OutputType>
408{
409 _div_phi_face = &_div_phi_face_assembly_method(_assembly, _fe_type);
410 return *_div_phi_face;
411}
412
413template <typename OutputType>
414template <bool constant_monomial,
415 typename DestinationType,
416 typename ShapeType,
417 typename DofValuesType>
418void
420 const ShapeType & phi,
421 const DofValuesType & dof_values,
422 const unsigned int nqp,
423 const std::size_t num_shapes)
424{
425 if constexpr (constant_monomial)
426 libmesh_ignore(num_shapes);
427
428 // Deduce OutputType
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");
433
434 // this is only used in the RealEigenVector case to get this->_count
435 if constexpr (!is_eigen)
436 libmesh_ignore(this);
437
438 // Deduce type of value within dest MooseArray
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");
454
455 // Sets a value to zero at a quadrature point
456 const auto set_zero = [this, &dest](const auto qp)
457 {
458 if constexpr (!is_eigen)
459 libmesh_ignore(this);
460
461 if constexpr (is_real || is_real_vector)
462 dest[qp] = 0;
463 else if constexpr (is_eigen)
464 {
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);
471 else
472 static_assert(Moose::always_false<OutputType, dest_array_type>, "Unsupported type");
473 }
474 else
475 static_assert(Moose::always_false<OutputType, dest_array_type>, "Unsupported type");
476 };
477
478 // Accumulates a value
479 const auto accumulate = [&dest, &phi, &dof_values](const auto i, const auto qp)
480 {
481 if constexpr (is_real || is_real_vector || (is_eigen && is_value))
482 {
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]);
487 else
488 static_assert(Moose::always_false<OutputType, dest_array_type>, "Unsupported type");
489 }
490 else if constexpr (is_eigen)
491 {
492 if constexpr (is_gradient)
493 {
494 for (const auto d : make_range(Moose::dim))
495 dest[qp].col(d) += phi[i][qp](d) * dof_values[i];
496 }
497 else if constexpr (is_second)
498 {
499 for (unsigned int d = 0, d1 = 0; d1 < LIBMESH_DIM; ++d1)
500 for (const auto d2 : make_range(Moose::dim))
501 dest[qp].col(d++) += phi[i][qp](d1, d2) * dof_values[i];
502 }
503 else
504 static_assert(Moose::always_false<OutputType, dest_array_type>, "Unsupported type");
505 }
506 else
507 static_assert(Moose::always_false<OutputType, dest_array_type>, "Unsupported type");
508 };
509
510 dest.resize(nqp);
511
512 // Monomial case, accumulate dest[0] and set dest[>0] to dest[0]
513 if constexpr (constant_monomial)
514 {
515 mooseAssert(num_shapes == 1, "Should have only one shape function for a constant monomial");
516 set_zero(0);
517 accumulate(0, 0);
518 for (unsigned int qp = 1; qp < nqp; ++qp)
519 dest[qp] = dest[0];
520 }
521 // Non constant monomial case
522 else
523 {
524 for (const auto qp : make_range(nqp))
525 set_zero(qp);
526 for (const auto i : make_range(num_shapes))
527 for (const auto qp : make_range(nqp))
528 accumulate(i, qp);
529 }
530}
531
532template <typename OutputType>
533template <bool constant_monomial>
534void
536{
537 const auto num_dofs = _dof_indices.size();
538 const auto num_shapes = num_dofs / _count;
539
540 if (num_dofs > 0)
541 fetchDofValues();
542
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);
547
548 // Map grad_phi using Eigen so that we can perform array operations easier
549 if constexpr (std::is_same_v<OutputType, RealEigenVector>)
550 {
551 if (_qrule == _current_qrule)
552 {
553 _mapped_grad_phi.resize(num_shapes);
554 for (const auto i : make_range(num_shapes))
555 {
556 _mapped_grad_phi[i].resize(nqp, Eigen::Map<RealDIMValue>(nullptr));
557 for (const auto qp : make_range(nqp))
558 // Note: this does NOT do any allocation. It is "reconstructing" the object in place
559 new (&_mapped_grad_phi[i][qp])
560 Eigen::Map<RealDIMValue>(const_cast<Real *>(&(*_current_grad_phi)[i][qp](0)));
561 }
562 }
563 else
564 {
565 _mapped_grad_phi_face.resize(num_shapes);
566 for (const auto i : make_range(num_shapes))
567 {
568 _mapped_grad_phi_face[i].resize(nqp, Eigen::Map<RealDIMValue>(nullptr));
569 for (const auto qp : make_range(nqp))
570 // Note: this does NOT do any allocation. It is "reconstructing" the object in place
571 new (&_mapped_grad_phi_face[i][qp])
572 Eigen::Map<RealDIMValue>(const_cast<Real *>(&(*_current_grad_phi)[i][qp](0)));
573 }
574 }
575 }
576
577 mooseAssert(
578 !(_need_second || _need_second_old || _need_second_older || _need_second_previous_nl) ||
579 _current_second_phi,
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!");
585
586 // Curl
587 if (_need_curl)
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);
593
594 // Div
595 if (_need_div)
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);
601
602 // Second
603 if (_need_second)
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],
610 nqp,
611 num_shapes);
612
613 // Vector tags
614 for (auto tag : _required_vector_tags)
615 {
616 if (_need_vector_tag_u[tag] && _sys.hasVector(tag))
617 {
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);
621 }
622 if (_need_vector_tag_grad[tag] && _sys.hasVector(tag))
623 {
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);
627 }
628 }
629
630 // Matrix tags
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);
635
636 // Derivatives and old values
637 if (is_transient)
638 {
639 if (_need_second_old)
640 fill<constant_monomial>(_second_u_old,
641 *_current_second_phi,
642 _vector_tags_dof_u[_old_solution_tag],
643 nqp,
644 num_shapes);
645 if (_need_second_older)
646 fill<constant_monomial>(_second_u_older,
647 *_current_second_phi,
648 _vector_tags_dof_u[_older_solution_tag],
649 nqp,
650 num_shapes);
651 if (_need_u_dot)
652 fill<constant_monomial>(_u_dot, *_current_phi, _dof_values_dot, nqp, num_shapes);
653 if (_need_u_dotdot)
654 fill<constant_monomial>(_u_dotdot, *_current_phi, _dof_values_dotdot, nqp, num_shapes);
655 if (_need_u_dot_old)
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);
660
661 if (_need_du_dot_du)
662 {
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];
667 }
668 if (_need_du_dotdot_du)
669 {
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];
674 }
675
676 if (_need_grad_dot)
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);
681 }
682
683 // A variable whose AD was only ever requested through the face-scoped accessors has no
684 // consumer on element interiors, so seeding the derivatives there is wasted work. In the
685 // volume context _current_qrule is _qrule; see setGeometry().
686 if (_need_ad && (_need_ad_volume || _current_qrule != _qrule))
687 computeAD<constant_monomial>(num_dofs, nqp);
688}
689
690template <typename OutputType>
691void
693{
694 computeValuesInternal</* constant_monomial = */ false>();
695}
696
697template <typename OutputType>
698void
700{
701 if (_dof_indices.size() == 0)
702 return;
703
704 // Monomial optimizations are not appropriate after p-refinement
705 if (_elem->p_level())
706 computeValues();
707 else
708 computeValuesInternal</* constant_monomial = */ true>();
709}
710
711template <typename OutputType>
712void
714{
715 const auto num_dofs = _dof_indices.size();
716
717 const bool do_derivatives = Moose::doDerivatives(_subproblem, _sys);
718
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];
722 // NOTE! You have to do this AFTER setting the value!
723 if (do_derivatives)
724 for (const auto i : make_range(num_dofs))
725 Moose::derivInsert(_ad_dof_values[i].derivatives(), _dof_indices[i], 1.);
726
727 const bool is_transient = _subproblem.isTransient();
728 if (is_transient && _need_ad_u_dot)
729 {
730 _ad_dofs_dot.resize(num_dofs);
731 if (_need_ad_u_dotdot)
732 _ad_dofs_dotdot.resize(num_dofs);
733
734 if (_time_integrator)
735 {
736 if (_time_integrator->dt())
737 {
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],
742 _dof_indices[i],
743 _need_ad_u_dotdot ? _ad_dofs_dotdot[i]
744 : _ad_real_dummy);
745 }
746 else
747 // Executing something with a time derivative at initial should not put a NaN
748 for (const auto i : make_range(num_dofs))
749 {
750 _ad_dofs_dot[i] = 0.;
751 if (_need_ad_u_dotdot)
752 _ad_dofs_dotdot[i] = 0;
753 }
754 }
755 // We are too early in the setup to have a time integrator, so we are not really using the
756 // AD-derivatives. We set the AD value of the derivatives to the nonAD value
757 else
758 for (const auto i : make_range(num_dofs))
759 {
760 _ad_dofs_dot[i] = _dof_values_dot[i];
761 if (_need_ad_u_dotdot)
762 _ad_dofs_dotdot[i] = _dof_values_dotdot[i];
763 }
764 }
765}
766
767template <>
768void
770{
771 const auto num_dofs = _dof_indices.size();
772
773 const bool do_derivatives = Moose::doDerivatives(_subproblem, _sys);
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");
777
778 _ad_dof_values.resize(n_test);
779 // Test is outer, count is inner
780 for (const auto i : make_range(n_test))
781 {
782 _ad_dof_values[i].resize(_count);
783 for (const auto j : make_range(_count))
784 {
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);
788 // NOTE! You have to do this AFTER setting the value!
789 if (do_derivatives)
790 Moose::derivInsert(dual_number.derivatives(), global_dof_index, 1.);
791 }
792 }
793}
794
795template <typename OutputType>
796template <bool constant_monomial>
797void
798MooseVariableData<OutputType>::computeAD(const unsigned int num_dofs, const unsigned int nqp)
799{
800 fetchADDofValues();
801 const auto n_test = num_dofs / _count;
802
803 // Values
804 if (_need_ad_u)
805 fill<constant_monomial>(_ad_u, *_current_phi, _ad_dof_values, nqp, n_test);
806 // Grad. On an element face, only fill the gradient when a face object requested it. Otherwise it
807 // stays empty so that a face object that read it through the volume accessor adGradSln() fails
808 // the bounds assertion instead of silently using gradients built without the AD face shape
809 // function gradients. Neighbor data never uses AD shape function gradients and is not affected.
810 const bool on_element_face =
811 _element_type == Moose::ElementType::Element && _current_qrule != _qrule;
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)
815 {
816 // The latter check here is for handling the fact that we have not yet implemented
817 // calculation of ad_grad_phi for neighbor and neighbor-face, so if we are in that
818 // situation we need to default to using the non-ad grad_phi
819 if (_displaced && _current_ad_grad_phi)
820 fill<constant_monomial>(_ad_grad_u, *_current_ad_grad_phi, _ad_dof_values, nqp, n_test);
821 else
822 fill<constant_monomial>(_ad_grad_u, *_current_grad_phi, _ad_dof_values, nqp, n_test);
823 }
824 // Second
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);
828 // Curl
829 if (_need_ad_curl_u)
830 fill<constant_monomial>(_ad_curl_u, *_current_curl_phi, _ad_dof_values, nqp, n_test);
831
832 const bool is_transient = _subproblem.isTransient();
833 if (is_transient)
834 {
835 if (_need_ad_u_dot)
836 {
837 if (_time_integrator)
838 fill<constant_monomial>(_ad_u_dot, *_current_phi, _ad_dofs_dot, nqp, n_test);
839 // We are too early in the setup to have a time integrator, so we are not really using the
840 // AD-derivatives. We set the AD value of the derivatives to the nonAD value
841 else
842 {
843 _ad_u_dot.resize(nqp);
844 for (const auto qp : make_range(nqp))
845 _ad_u_dot[qp] = _u_dot[qp];
846 }
847 }
848
849 if (_need_ad_u_dotdot)
850 {
851 if (_time_integrator)
852 fill<constant_monomial>(_ad_u_dotdot, *_current_phi, _ad_dofs_dotdot, nqp, n_test);
853 else
854 {
855 _ad_u_dotdot.resize(nqp);
856 for (const auto qp : make_range(nqp))
857 _ad_u_dotdot[qp] = _u_dotdot[qp];
858 }
859 }
860
861 // The gradient time derivative is volume-only, so on an element face it is left empty for the
862 // same reason as the gradient above
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)
866 {
867 if (_time_integrator)
868 {
869 // The latter check here is for handling the fact that we have not yet implemented
870 // calculation of ad_grad_phi for neighbor and neighbor-face, so if we are in that
871 // situation we need to default to using the non-ad grad_phi
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);
874 else
875 fill<constant_monomial>(_ad_grad_u_dot, *_current_grad_phi, _ad_dofs_dot, nqp, n_test);
876 }
877 else
878 {
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];
882 }
883 }
884 }
885}
886
887template <typename OutputType>
888void
889MooseVariableData<OutputType>::setDofValue(const DofValue & value, unsigned int index)
890{
891 auto & dof_values = _vector_tags_dof_u[_solution_tag];
892 dof_values[index] = value;
893 _has_dof_values = true;
894
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))
899 u[qp] *= 0.;
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];
903}
904
905template <typename OutputType>
906void
908{
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);
912
913 _has_dof_values = true;
914
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))
919 u[qp] *= 0.;
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];
923}
924
925template <typename OutputType>
926void
927MooseVariableData<OutputType>::insertNodalValue(NumericVector<Number> & residual,
928 const DofValue & v)
929{
930 residual.set(_nodal_dof_index, v);
931}
932
933template <>
934void
936 const RealEigenVector & v)
937{
938 for (const auto j : make_range(_count))
939 residual.set(_nodal_dof_index + j, v(j));
940}
941
942template <typename OutputType>
945{
946 mooseAssert(_subproblem.mesh().isSemiLocal(const_cast<Node *>(&node)), "Node is not Semilocal");
947
948 // Make sure that the node has DOFs
949 /* Note, this is a reproduction of an assert within libMesh::Node::dof_number, this is done to
950 * produce a better error (see misc/check_error.node_value_off_block) */
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");
954
955 dof_id_type dof = node.dof_number(_sys.number(), _var_num, 0);
956
957 switch (state)
958 {
959 case Moose::Current:
960 return (*_sys.currentSolution())(dof);
961
962 case Moose::Old:
963 return _sys.solutionOld()(dof);
964
965 case Moose::Older:
966 return _sys.solutionOlder()(dof);
967
968 default:
969 mooseError("PreviousNL not currently supported for getNodalValue");
970 }
971}
972
973template <>
974RealEigenVector
976 Moose::SolutionState state) const
977{
978 mooseAssert(_subproblem.mesh().isSemiLocal(const_cast<Node *>(&node)), "Node is not Semilocal");
979
980 // Make sure that the node has DOFs
981 /* Note, this is a reproduction of an assert within libMesh::Node::dof_number, this is done to
982 * produce a better error (see misc/check_error.node_value_off_block) */
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");
986
987 dof_id_type dof = node.dof_number(_sys.number(), _var_num, 0);
988
989 RealEigenVector v(_count);
990 switch (state)
991 {
992 case Moose::Current:
993 for (unsigned int i = 0; i < _count; ++i)
994 v(i) = (*_sys.currentSolution())(dof++);
995 break;
996
997 case Moose::Old:
998 for (unsigned int i = 0; i < _count; ++i)
999 v(i) = _sys.solutionOld()(dof++);
1000 break;
1001
1002 case Moose::Older:
1003 for (unsigned int i = 0; i < _count; ++i)
1004 v(i) = _sys.solutionOlder()(dof++);
1005 break;
1006
1007 default:
1008 mooseError("PreviousNL not currently supported for getNodalValue");
1009 }
1010 return v;
1011}
1012
1013template <typename OutputType>
1016 const Moose::SolutionState state,
1017 const unsigned int idx) const
1018{
1019 static thread_local std::vector<dof_id_type> dof_indices;
1020 _dof_map.dof_indices(elem, dof_indices, _var_num);
1021
1022 switch (state)
1023 {
1024 case Moose::Current:
1025 return (*_sys.currentSolution())(dof_indices[idx]);
1026
1027 case Moose::Old:
1028 return _sys.solutionOld()(dof_indices[idx]);
1029
1030 case Moose::Older:
1031 return _sys.solutionOlder()(dof_indices[idx]);
1032
1033 default:
1034 mooseError("PreviousNL not currently supported for getElementalValue");
1035 }
1036}
1037
1038template <>
1039RealEigenVector
1041 const Moose::SolutionState state,
1042 const unsigned int idx) const
1043{
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 "
1048 "average value");
1049
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;
1055
1056 RealEigenVector v(_count);
1057
1058 switch (state)
1059 {
1060 case Moose::Current:
1061 for (unsigned int i = 0; i < _count; ++i)
1062 v(i) = (*_sys.currentSolution())(dof_indices[i * num_shapes + idx]);
1063 break;
1064
1065 case Moose::Old:
1066 for (unsigned int i = 0; i < _count; ++i)
1067 v(i) = _sys.solutionOld()(dof_indices[i * num_shapes + idx]);
1068 break;
1069
1070 case Moose::Older:
1071 for (unsigned int i = 0; i < _count; ++i)
1072 v(i) = _sys.solutionOlder()(dof_indices[i * num_shapes + idx]);
1073 break;
1074
1075 default:
1076 mooseError("PreviousNL not currently supported for getElementalValue");
1077 }
1078 return v;
1079}
1080
1081template <typename OutputType>
1082void
1084 std::vector<dof_id_type> & dof_indices) const
1085{
1086 if constexpr (std::is_same<OutputType, RealEigenVector>::value)
1087 _dof_map.array_dof_indices(elem, dof_indices, _var_num);
1088 else
1089 _dof_map.dof_indices(elem, dof_indices, _var_num);
1090}
1091
1092template <typename OutputType>
1093void
1095 const DenseVector<Number> & v) const
1096{
1097 sol.add_vector(v, _dof_indices);
1098}
1099
1100template <typename OutputType>
1103{
1104 if (_sys.solutionUDot())
1105 {
1106 _need_dof_values_dot = true;
1107 return _dof_values_dot;
1108 }
1109 else
1110 mooseError("MooseVariableData: Time derivative of solution (`u_dot`) is not stored. Please set "
1111 "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
1112}
1113
1114template <typename OutputType>
1117{
1118 if (_sys.solutionUDotDot())
1119 {
1120 _need_dof_values_dotdot = true;
1121 return _dof_values_dotdot;
1122 }
1123 else
1124 mooseError("MooseVariableData: Second time derivative of solution (`u_dotdot`) is not stored. "
1125 "Please set uDotDotRequested() to true in FEProblemBase before requesting "
1126 "`u_dotdot`.");
1127}
1128
1129template <typename OutputType>
1132{
1133 if (_sys.solutionUDotOld())
1134 {
1135 _need_dof_values_dot_old = true;
1136 return _dof_values_dot_old;
1137 }
1138 else
1139 mooseError("MooseVariableData: Old time derivative of solution (`u_dot_old`) is not stored. "
1140 "Please set uDotOldRequested() to true in FEProblemBase before requesting "
1141 "`u_dot_old`.");
1142}
1143
1144template <typename OutputType>
1147{
1148 if (_sys.solutionUDotDotOld())
1149 {
1150 _need_dof_values_dotdot_old = true;
1151 return _dof_values_dotdot_old;
1152 }
1153 else
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`.");
1157}
1158
1159template <typename OutputType>
1160const MooseArray<Number> &
1162{
1163 _need_dof_du_dot_du = true;
1164 return _dof_du_dot_du;
1165}
1166
1167template <typename OutputType>
1168const MooseArray<Number> &
1170{
1171 _need_dof_du_dotdot_du = true;
1172 return _dof_du_dotdot_du;
1173}
1174
1175template <typename OutputType>
1176void
1177MooseVariableData<OutputType>::computeIncrementAtQps(const NumericVector<Number> & increment_vec)
1178{
1179 unsigned int nqp = _qrule->n_points();
1180
1181 _increment.resize(nqp);
1182 // Compute the increment at each quadrature point
1183 unsigned int num_dofs = _dof_indices.size();
1184 for (const auto qp : make_range(nqp))
1185 {
1186 _increment[qp] = 0.;
1187 for (const auto i : make_range(num_dofs))
1188 _increment[qp] += (*_phi)[i][qp] * increment_vec(_dof_indices[i]);
1189 }
1190}
1191
1192template <>
1193void
1195 const NumericVector<Number> & increment_vec)
1196{
1197 unsigned int nqp = _qrule->n_points();
1198
1199 _increment.resize(nqp);
1200 // Compute the increment at each quadrature point
1201 unsigned int num_dofs = _dof_indices.size();
1202 if (isNodal())
1203 {
1204 for (const auto qp : make_range(nqp))
1205 {
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);
1209 }
1210 }
1211 else
1212 {
1213 for (const auto qp : make_range(nqp))
1214 {
1215 unsigned int n = 0;
1216 for (const auto j : make_range(_count))
1217 for (const auto i : make_range(num_dofs))
1218 {
1219 _increment[qp](j) += (*_phi)[i][qp] * increment_vec(_dof_indices[i] + n);
1220 n += num_dofs;
1221 }
1222 }
1223 }
1224}
1225
1226template <typename OutputType>
1227void
1228MooseVariableData<OutputType>::computeIncrementAtNode(const NumericVector<Number> & increment_vec)
1229{
1230 if (!isNodal())
1231 mooseError("computeIncrementAtNode can only be called for nodal variables");
1232
1233 _increment.resize(1);
1234
1235 // Compute the increment for the current DOF
1236 _increment[0] = increment_vec(_dof_indices[0]);
1237}
1238
1239template <>
1240void
1242 const NumericVector<Number> & increment_vec)
1243{
1244 if (!isNodal())
1245 mooseError("computeIncrementAtNode can only be called for nodal variables");
1246
1247 _increment.resize(1);
1248
1249 // Compute the increment for the current DOF
1250 if (isNodal())
1251 for (unsigned int j = 0; j < _count; j++)
1252 _increment[0](j) = increment_vec(_dof_indices[0] + j);
1253 else
1254 {
1255 unsigned int n = 0;
1256 const auto n_dof_indices = _dof_indices.size();
1257 for (const auto j : make_range(_count))
1258 {
1259 _increment[0](j) = increment_vec(_dof_indices[0] + n);
1260 n += n_dof_indices;
1261 }
1262 }
1263}
1264
1265template <typename OutputType>
1266const OutputType &
1268{
1269 if (isNodal())
1270 {
1271 if (_sys.solutionUDot())
1272 {
1273 _need_dof_values_dot = true;
1274 return _nodal_value_dot;
1275 }
1276 else
1277 mooseError(
1278 "MooseVariableData: Time derivative of solution (`u_dot`) is not stored. Please set "
1279 "uDotRequested() to true in FEProblemBase before requesting `u_dot`.");
1280 }
1281 else
1282 mooseError("Nodal values can be requested only on nodal variables, variable '",
1283 var().name(),
1284 "' is not nodal.");
1285}
1286
1287template <typename OutputType>
1288const OutputType &
1290{
1291 if (isNodal())
1292 {
1293 if (_sys.solutionUDotDot())
1294 {
1295 _need_dof_values_dotdot = true;
1296 return _nodal_value_dotdot;
1297 }
1298 else
1299 mooseError(
1300 "MooseVariableData: Second time derivative of solution (`u_dotdot`) is not stored. "
1301 "Please set uDotDotRequested() to true in FEProblemBase before requesting "
1302 "`u_dotdot`.");
1303 }
1304 else
1305 mooseError("Nodal values can be requested only on nodal variables, variable '",
1306 var().name(),
1307 "' is not nodal.");
1308}
1309
1310template <typename OutputType>
1311const OutputType &
1313{
1314 if (isNodal())
1315 {
1316 if (_sys.solutionUDotOld())
1317 {
1318 _need_dof_values_dot_old = true;
1319 return _nodal_value_dot_old;
1320 }
1321 else
1322 mooseError("MooseVariableData: Old time derivative of solution (`u_dot_old`) is not stored. "
1323 "Please set uDotOldRequested() to true in FEProblemBase before requesting "
1324 "`u_dot_old`.");
1325 }
1326 else
1327 mooseError("Nodal values can be requested only on nodal variables, variable '",
1328 var().name(),
1329 "' is not nodal.");
1330}
1331
1332template <typename OutputType>
1333const OutputType &
1335{
1336 if (isNodal())
1337 {
1338 if (_sys.solutionUDotDotOld())
1339 {
1340 _need_dof_values_dotdot_old = true;
1341 return _nodal_value_dotdot_old;
1342 }
1343 else
1344 mooseError(
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`.");
1348 }
1349 else
1350 mooseError("Nodal values can be requested only on nodal variables, variable '",
1351 var().name(),
1352 "' is not nodal.");
1353}
1354
1355template <typename OutputType>
1356void
1358{
1359 if (_has_dof_indices)
1360 {
1361 fetchDofValues();
1362 assignNodalValue();
1363
1364 if (_need_ad)
1365 {
1366 fetchADDofValues();
1367 assignADNodalValue();
1368 }
1369 }
1370 else
1371 zeroSizeDofValues();
1372}
1373
1374template <typename OutputType>
1375void
1377{
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];
1380}
1381
1382template <>
1383void
1385{
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];
1391}
1392
1393template <typename OutputType>
1394void
1396{
1397 if constexpr (std::is_same<RealEigenVector, OutputType>::value)
1398 _dof_map.array_dof_indices(_elem, _dof_indices, _var_num);
1399 else
1400 _dof_map.dof_indices(_elem, _dof_indices, _var_num);
1401
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);
1406
1407 unsigned int nqp = _qrule->n_points();
1408 _vector_tag_u[_solution_tag].resize(nqp);
1409}
1410
1411template <typename OutputType>
1412void
1414{
1415 if constexpr (std::is_same<OutputType, RealEigenVector>::value)
1416 _dof_map.array_dof_indices(_elem, _dof_indices, _var_num);
1417 else
1418 _dof_map.dof_indices(_elem, _dof_indices, _var_num);
1419
1420 _has_dof_values = false;
1421
1422 // FIXME: remove this when the Richard's module is migrated to use the new NodalCoupleable
1423 // interface.
1424 _has_dof_indices = _dof_indices.size();
1425}
1426
1427template <typename OutputType>
1428void
1430{
1431 if constexpr (std::is_same<OutputType, RealEigenVector>::value)
1432 _dof_map.array_dof_indices(_node, _dof_indices, _var_num);
1433 else
1434 _dof_map.dof_indices(_node, _dof_indices, _var_num);
1435
1436 const auto n_dofs = _dof_indices.size();
1437 if (n_dofs)
1438 {
1439 // For standard variables. _nodal_dof_index is retrieved by nodalDofIndex() which is used in
1440 // NodalBC for example
1441 _nodal_dof_index = _dof_indices[0];
1442 _has_dof_indices = true;
1443 }
1444 else
1445 _has_dof_indices = false;
1446}
1447
1448template <typename OutputType>
1449void
1451{
1452 /* FIXME: this method is only for elemental auxiliary variables, so
1453 * we may want to rename it */
1454 if (_elem)
1455 {
1456 if constexpr (std::is_same<RealEigenVector, OutputType>::value)
1457 _dof_map.array_dof_indices(_elem, _dof_indices, _var_num);
1458 else
1459 _dof_map.dof_indices(_elem, _dof_indices, _var_num);
1460 if (_elem->n_dofs(_sys.number(), _var_num) > 0)
1461 {
1462 // FIXME: Setting _nodal_dof_index inside of a method that apparently is only for "elemental"
1463 // aux variables seems absolutely absurd
1464 _nodal_dof_index = _dof_indices[0];
1465
1466 fetchDofValues();
1467
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);
1473
1474 for (auto & dof_u : _matrix_tags_dof_u)
1475 dof_u.resize(num_shapes);
1476
1477 _has_dof_indices = true;
1478 }
1479 else
1480 _has_dof_indices = false;
1481 }
1482 else
1483 _has_dof_indices = false;
1484}
1485
1486template <typename OutputType>
1487void
1488MooseVariableData<OutputType>::reinitNodes(const std::vector<dof_id_type> & nodes)
1489{
1490 _dof_indices.clear();
1491 for (const auto & node_id : nodes)
1492 {
1493 auto && nd = _subproblem.mesh().getMesh().query_node_ptr(node_id);
1494 if (nd && (_subproblem.mesh().isSemiLocal(const_cast<Node *>(nd))))
1495 {
1496 if (nd->n_dofs(_sys.number(), _var_num) > 0)
1497 {
1498 if constexpr (std::is_same<RealEigenVector, OutputType>::value)
1499 {
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);
1504 }
1505 else
1506 {
1507 dof_id_type dof = nd->dof_number(_sys.number(), _var_num, 0);
1508 _dof_indices.push_back(dof);
1509 }
1510 }
1511 }
1512 }
1513
1514 if (!_dof_indices.empty())
1515 _has_dof_indices = true;
1516 else
1517 _has_dof_indices = false;
1518}
1519
1520template 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 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)
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