https://mooseframework.inl.gov
Loading...
Searching...
No Matches
MooseVariableFV.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 "MooseVariableFV.h"
11#include "TimeIntegrator.h"
12#include "NonlinearSystemBase.h"
13#include "DisplacedSystem.h"
14#include "SystemBase.h"
15#include "SubProblem.h"
16#include "Assembly.h"
17#include "MathFVUtils.h"
18#include "FVUtils.h"
19#include "FVFluxBC.h"
20#include "FVDirichletBCBase.h"
21#include "GreenGaussGradient.h"
22
23#include "libmesh/numeric_vector.h"
24
25#include <climits>
26#include <typeinfo>
27
28using namespace Moose;
29
31
32template <typename OutputType>
35{
37 params.set<bool>("fv") = true;
38 params.set<MooseEnum>("family") = "MONOMIAL";
39 params.set<MooseEnum>("order") = "CONSTANT";
40 params.template addParam<bool>(
41 "two_term_boundary_expansion",
42 true,
43 "Whether to use a two-term Taylor expansion to calculate boundary face values. "
44 "If the two-term expansion is used, then the boundary face value depends on the "
45 "adjoining cell center gradient, which itself depends on the boundary face value. "
46 "Consequently an implicit solve is used to simultaneously solve for the adjoining cell "
47 "center gradient and boundary face value(s).");
48 MooseEnum face_interp_method("average skewness-corrected", "average");
49 params.template addParam<MooseEnum>("face_interp_method",
50 face_interp_method,
51 "Switch that can select between face interpolation methods.");
52 params.template addParam<bool>(
53 "cache_cell_gradients", true, "Whether to cache cell gradients or re-compute them.");
54
55 // Depending on the face interpolation we might have to do more than one layer ghosting.
57 "ElementSideNeighborLayers",
60 [](const InputParameters & obj_params, InputParameters & rm_params)
61 {
62 unsigned short layers = 1;
63 if (obj_params.get<MooseEnum>("face_interp_method") == "skewness-corrected")
64 layers = 2;
65
66 rm_params.set<unsigned short>("layers") = layers;
67 });
68 return params;
69}
70
71template <typename OutputType>
73 : MooseVariableField<OutputType>(parameters),
74 _solution(this->_sys.currentSolution()),
75 _phi(this->_assembly.template fePhi<OutputShape>(FEType(CONSTANT, MONOMIAL))),
76 _grad_phi(this->_assembly.template feGradPhi<OutputShape>(FEType(CONSTANT, MONOMIAL))),
77 _phi_face(this->_assembly.template fePhiFace<OutputShape>(FEType(CONSTANT, MONOMIAL))),
78 _grad_phi_face(this->_assembly.template feGradPhiFace<OutputShape>(FEType(CONSTANT, MONOMIAL))),
79 _phi_face_neighbor(
80 this->_assembly.template fePhiFaceNeighbor<OutputShape>(FEType(CONSTANT, MONOMIAL))),
81 _grad_phi_face_neighbor(
82 this->_assembly.template feGradPhiFaceNeighbor<OutputShape>(FEType(CONSTANT, MONOMIAL))),
83 _phi_neighbor(this->_assembly.template fePhiNeighbor<OutputShape>(FEType(CONSTANT, MONOMIAL))),
84 _grad_phi_neighbor(
85 this->_assembly.template feGradPhiNeighbor<OutputShape>(FEType(CONSTANT, MONOMIAL))),
86 _prev_elem(nullptr),
87 _two_term_boundary_expansion(this->isParamValid("two_term_boundary_expansion")
88 ? this->template getParam<bool>("two_term_boundary_expansion")
89 : true),
90 _cache_cell_gradients(this->isParamValid("cache_cell_gradients")
91 ? this->template getParam<bool>("cache_cell_gradients")
92 : true)
93{
94 _element_data = std::make_unique<MooseVariableDataFV<OutputType>>(
96 _neighbor_data = std::make_unique<MooseVariableDataFV<OutputType>>(
98
99 if (this->isParamValid("face_interp_method"))
100 {
101 const auto & interp_method = this->template getParam<MooseEnum>("face_interp_method");
102 if (interp_method == "average")
104 else if (interp_method == "skewness-corrected")
107 else
109}
110
111template <typename OutputType>
112void
114{
115 _element_data->clearDofIndices();
116}
117
118template <typename OutputType>
120MooseVariableFV<OutputType>::getElementalValue(const Elem * elem, unsigned int idx) const
121{
122 return _element_data->getElementalValue(elem, Moose::Current, idx);
123}
124
125template <typename OutputType>
127MooseVariableFV<OutputType>::getElementalValueOld(const Elem * elem, unsigned int idx) const
128{
129 return _element_data->getElementalValue(elem, Moose::Old, idx);
130}
131
132template <typename OutputType>
134MooseVariableFV<OutputType>::getElementalValueOlder(const Elem * elem, unsigned int idx) const
136 return _element_data->getElementalValue(elem, Moose::Older, idx);
137}
138
139template <typename OutputType>
140void
141MooseVariableFV<OutputType>::insert(NumericVector<Number> & residual)
142{
143 _element_data->insert(residual);
144}
145
146template <typename OutputType>
147void
149{
150 lowerDError();
151}
152
153template <typename OutputType>
154void
155MooseVariableFV<OutputType>::add(NumericVector<Number> & residual)
156{
157 _element_data->add(residual);
158}
159
160template <typename OutputType>
163{
164 return _element_data->dofValues();
165}
166
167template <typename OutputType>
170{
171 return _element_data->dofValuesOld();
172}
174template <typename OutputType>
177{
178 return _element_data->dofValuesOlder();
179}
180
181template <typename OutputType>
184{
185 return _element_data->dofValuesPreviousNL();
186}
187
188template <typename OutputType>
191{
192 return _neighbor_data->dofValues();
193}
194
195template <typename OutputType>
198{
199 return _neighbor_data->dofValuesOld();
200}
201
202template <typename OutputType>
205{
206 return _neighbor_data->dofValuesOlder();
207}
208
209template <typename OutputType>
212{
213 return _neighbor_data->dofValuesPreviousNL();
214}
215
216template <typename OutputType>
219{
220 return _element_data->dofValuesDot();
221}
222
223template <typename OutputType>
226{
227 return _element_data->dofValuesDotDot();
228}
229
230template <typename OutputType>
233{
234 return _element_data->dofValuesDotOld();
235}
236
237template <typename OutputType>
240{
241 return _element_data->dofValuesDotDotOld();
242}
243
244template <typename OutputType>
247{
248 return _neighbor_data->dofValuesDot();
249}
250
251template <typename OutputType>
254{
255 return _neighbor_data->dofValuesDotDot();
256}
257
258template <typename OutputType>
261{
262 return _neighbor_data->dofValuesDotOld();
263}
264
265template <typename OutputType>
268{
269 return _neighbor_data->dofValuesDotDotOld();
270}
271
272template <typename OutputType>
273const MooseArray<Number> &
275{
276 return _element_data->dofValuesDuDotDu();
277}
278
279template <typename OutputType>
280const MooseArray<Number> &
282{
283 return _element_data->dofValuesDuDotDotDu();
284}
285
286template <typename OutputType>
287const MooseArray<Number> &
289{
290 return _neighbor_data->dofValuesDuDotDu();
291}
292
293template <typename OutputType>
294const MooseArray<Number> &
296{
297 return _neighbor_data->dofValuesDuDotDotDu();
299
300template <typename OutputType>
301void
303{
304 _element_data->prepareIC();
305}
306
307template <typename OutputType>
308void
310{
311 _element_data->setGeometry(Moose::Volume);
312 _element_data->computeValues();
313}
314
315template <typename OutputType>
316void
318{
319 _element_data->setGeometry(Moose::Face);
320 _element_data->computeValues();
321}
323template <typename OutputType>
324void
326{
327 _neighbor_data->setGeometry(Moose::Face);
328 _neighbor_data->computeValues();
329}
330
331template <typename OutputType>
332void
334{
335 _neighbor_data->setGeometry(Moose::Volume);
336 _neighbor_data->computeValues();
337}
338
339template <typename OutputType>
340void
342{
343 _element_data->setGeometry(Moose::Face);
344 _neighbor_data->setGeometry(Moose::Face);
345
346 const auto facetype = fi.faceType(std::make_pair(this->number(), this->sys().number()));
348 return;
349 else if (facetype == FaceInfo::VarFaceNeighbors::BOTH)
350 {
351 _element_data->computeValuesFace(fi);
352 _neighbor_data->computeValuesFace(fi);
353 }
354 else if (facetype == FaceInfo::VarFaceNeighbors::ELEM)
355 _element_data->computeValuesFace(fi);
356 else if (facetype == FaceInfo::VarFaceNeighbors::NEIGHBOR)
357 _neighbor_data->computeValuesFace(fi);
358 else
359 mooseError("robert wrote broken MooseVariableFV code");
360}
361
362template <typename OutputType>
363OutputType
365{
366 Moose::initDofIndices(const_cast<MooseVariableFV<OutputType> &>(*this), *elem);
367 mooseAssert(this->_dof_indices.size() == 1, "Wrong size for dof indices");
368 OutputType value = (*this->_sys.currentSolution())(this->_dof_indices[0]);
369 return value;
370}
371
372template <typename OutputType>
375{
376 return {};
377}
378
379template <typename OutputType>
380void
381MooseVariableFV<OutputType>::setNodalValue(const OutputType & /*value*/, unsigned int /*idx*/)
383 mooseError("FV variables do not support setNodalValue");
384}
385
386template <typename OutputType>
387void
388MooseVariableFV<OutputType>::setDofValue(const DofValue & value, unsigned int index)
389{
390 _element_data->setDofValue(value, index);
391}
392
393template <typename OutputType>
394void
397 _element_data->setDofValues(values);
398}
399
400template <typename OutputType>
401void
403{
404 lowerDError();
405}
406
407template <typename OutputType>
408std::pair<bool, const FVDirichletBCBase *>
410{
411 for (const auto bnd_id : fi.boundaryIDs())
412 if (auto it = _boundary_id_to_dirichlet_bc.find(bnd_id);
413 it != _boundary_id_to_dirichlet_bc.end())
414 return {true, it->second};
416 return {false, nullptr};
417}
419template <typename OutputType>
420std::pair<bool, std::vector<const FVFluxBC *>>
423 for (const auto bnd_id : fi.boundaryIDs())
424 if (auto it = _boundary_id_to_flux_bc.find(bnd_id); it != _boundary_id_to_flux_bc.end())
425 return {true, it->second};
427 return std::make_pair(false, std::vector<const FVFluxBC *>());
430template <typename OutputType>
432MooseVariableFV<OutputType>::getElemValue(const Elem * const elem, const StateArg & state) const
434 mooseAssert(elem,
435 "The elem shall exist! This typically occurs when the "
436 "user wants to evaluate non-existing elements (nullptr) at physical boundaries.");
437 mooseAssert(
438 this->hasBlocks(elem->subdomain_id()),
439 "The variable should be defined on the element's subdomain! This typically occurs when the "
440 "user wants to evaluate the elements right next to the boundary of two variables (block "
441 "boundary). The subdomain which is queried: " +
442 Moose::stringify(this->activeSubdomains()) + " the subdomain of the element " +
443 std::to_string(elem->subdomain_id()));
444
446
447 mooseAssert(
448 this->_dof_indices.size() == 1,
449 "There should only be one dof-index for a constant monomial variable on any given element");
450
451 const dof_id_type index = this->_dof_indices[0];
452
453 // It's not safe to use solutionState(0) because it returns the libMesh System solution member
454 // which is wrong during things like finite difference Jacobian evaluation, e.g. when PETSc
455 // perturbs the solution vector we feed these perturbations into the current_local_solution
456 // while the libMesh solution is frozen in the non-perturbed state
457 const auto & global_soln =
458 (state.state == 0)
459 ? *this->_sys.currentSolution()
460 : std::as_const(this->_sys).solutionState(state.state, state.iteration_type);
461
462 ADReal value = global_soln(index);
463
464 if (ADReal::do_derivatives && state.state == 0 &&
465 this->_sys.number() == this->_subproblem.currentNlSysNum())
466 Moose::derivInsert(value.derivatives(), index, 1.);
467
468 return value;
469}
470
471template <typename OutputType>
472bool
474 const Elem *,
475 const Moose::StateArg &) const
476{
477 const auto & pr = getDirichletBC(fi);
478
479 // First member of this pair indicates whether we have a DirichletBC
480 return pr.first;
481}
482
483template <typename OutputType>
484ADReal
486 const Elem * const libmesh_dbg_var(elem),
487 const Moose::StateArg & state) const
488{
489 mooseAssert(isDirichletBoundaryFace(fi, elem, state),
490 "This function should only be called on Dirichlet boundary faces.");
491
492 const auto & diri_pr = getDirichletBC(fi);
493
494 mooseAssert(diri_pr.first,
495 "This functor should only be called if we are on a Dirichlet boundary face.");
496
497 const FVDirichletBCBase & bc = *diri_pr.second;
499 return ADReal(bc.boundaryValue(fi, state));
500}
501
502template <typename OutputType>
503bool
505 const Elem * const elem,
506 const Moose::StateArg & state) const
507{
508 if (isDirichletBoundaryFace(fi, elem, state))
509 return false;
510 else
511 return !this->isInternalFace(fi);
512}
513
514template <typename OutputType>
515ADReal
517 const bool two_term_expansion,
518 const bool correct_skewness,
519 const Elem * elem_to_extrapolate_from,
520 const StateArg & state) const
521{
522 mooseAssert(
523 isExtrapolatedBoundaryFace(fi, elem_to_extrapolate_from, state) || !two_term_expansion,
524 "We allow Dirichlet boundary conditions to call this method. However, the only way to "
525 "ensure we don't have infinite recursion, with Green Gauss gradients calling back to the "
526 "Dirichlet boundary condition calling back to this method, is to do a one term expansion");
527
528 ADReal boundary_value;
529 bool elem_to_extrapolate_from_is_fi_elem;
530 std::tie(elem_to_extrapolate_from, elem_to_extrapolate_from_is_fi_elem) =
531 [this, &fi, elem_to_extrapolate_from]() -> std::pair<const Elem *, bool>
532 {
533 if (elem_to_extrapolate_from)
534 // Somebody already specified the element to extropolate from
535 return {elem_to_extrapolate_from, elem_to_extrapolate_from == fi.elemPtr()};
536 else
537 {
538 const auto [elem_guaranteed_to_have_dofs,
539 other_elem,
540 elem_guaranteed_to_have_dofs_is_fi_elem] =
542 // We only care about the element guaranteed to have degrees of freedom and current C++
543 // doesn't allow us to not assign one of the returned items like python does
544 libmesh_ignore(other_elem);
545 // We will extrapolate from the element guaranteed to have degrees of freedom
546 return {elem_guaranteed_to_have_dofs, elem_guaranteed_to_have_dofs_is_fi_elem};
547 }
548 }();
549
550 if (two_term_expansion)
552 const Point vector_to_face = elem_to_extrapolate_from_is_fi_elem
553 ? (fi.faceCentroid() - fi.elemCentroid())
554 : (fi.faceCentroid() - fi.neighborCentroid());
555 boundary_value = adGradSln(elem_to_extrapolate_from, state, correct_skewness) * vector_to_face +
556 getElemValue(elem_to_extrapolate_from, state);
557 }
558 else
559 boundary_value = getElemValue(elem_to_extrapolate_from, state);
560
561 return boundary_value;
562}
563
564template <typename OutputType>
565ADReal
567 const StateArg & state,
568 const bool correct_skewness) const
569{
570 mooseAssert(!this->isInternalFace(fi),
571 "A boundary face value has been requested on an internal face.");
572
573 if (isDirichletBoundaryFace(fi, nullptr, state))
574 return getDirichletBoundaryFaceValue(fi, nullptr, state);
575 else if (isExtrapolatedBoundaryFace(fi, nullptr, state))
576 return getExtrapolatedBoundaryFaceValue(
577 fi, _two_term_boundary_expansion, correct_skewness, nullptr, state);
578
579 mooseError("Unknown boundary face type!");
580}
581
582template <typename OutputType>
583const VectorValue<ADReal> &
585 const StateArg & state,
586 const bool correct_skewness) const
587{
588 // We ensure that no caching takes place when we compute skewness-corrected
589 // quantities.
590 if (_cache_cell_gradients && !correct_skewness && state.state == 0)
591 {
592 auto it = _elem_to_grad.find(elem);
593
594 if (it != _elem_to_grad.end())
595 return it->second;
596 }
597
598 auto grad = FV::greenGaussGradient(
599 ElemArg({elem, correct_skewness}), state, *this, _two_term_boundary_expansion, this->_mesh);
600
601 if (_cache_cell_gradients && !correct_skewness && state.state == 0)
602 {
603 auto pr = _elem_to_grad.emplace(elem, std::move(grad));
604 mooseAssert(pr.second, "Insertion should have just happened.");
605 return pr.first->second;
606 }
607 else
608 {
609 _temp_cell_gradient = std::move(grad);
610 return _temp_cell_gradient;
611 }
612}
613
614template <typename OutputType>
615VectorValue<ADReal>
617 const StateArg & state,
618 const bool correct_skewness) const
619{
620 const auto face_type = fi.faceType(std::make_pair(this->number(), this->sys().number()));
621 mooseAssert(face_type != FaceInfo::VarFaceNeighbors::NEITHER,
622 "Gradient requested on a face where the variable is defined on neither side.");
623
624 const bool var_defined_on_elem = (face_type == FaceInfo::VarFaceNeighbors::BOTH) ||
626 const Elem * const elem_one = var_defined_on_elem ? &fi.elem() : fi.neighborPtr();
627 const Elem * const elem_two = var_defined_on_elem ? fi.neighborPtr() : &fi.elem();
628
629 const VectorValue<ADReal> elem_one_grad = adGradSln(elem_one, state, correct_skewness);
630
631 // If we have a neighbor then we interpolate between the two to the face. If we do not, then we
632 // apply a zero Hessian assumption and use the element centroid gradient as the uncorrected face
633 // gradient
634 if (face_type == FaceInfo::VarFaceNeighbors::BOTH)
635 {
636 mooseAssert(elem_two, "Face type indicates BOTH but neighbor information is missing.");
637 const VectorValue<ADReal> & elem_two_grad = adGradSln(elem_two, state, correct_skewness);
638
639 // Uncorrected gradient value
640 return Moose::FV::linearInterpolation(elem_one_grad, elem_two_grad, fi, var_defined_on_elem);
641 }
642 else
643 return elem_one_grad;
644}
646template <typename OutputType>
647VectorValue<ADReal>
649 const StateArg & state,
650 const bool correct_skewness) const
651{
652 const bool var_defined_on_elem = this->hasBlocks(fi.elem().subdomain_id());
653 const Elem * const elem = &fi.elem();
654 const Elem * const neighbor = fi.neighborPtr();
655
656 const bool is_internal_face = this->isInternalFace(fi);
657
658 const ADReal side_one_value = (!is_internal_face && !var_defined_on_elem)
659 ? getBoundaryFaceValue(fi, state, correct_skewness)
660 : getElemValue(elem, state);
661 const ADReal side_two_value = (var_defined_on_elem && !is_internal_face)
662 ? getBoundaryFaceValue(fi, state, correct_skewness)
663 : getElemValue(neighbor, state);
664
665 const auto delta =
666 this->isInternalFace(fi)
667 ? fi.dCNMag()
668 : (fi.faceCentroid() - (var_defined_on_elem ? fi.elemCentroid() : fi.neighborCentroid()))
669 .norm();
670
671 // This is the component of the gradient which is parallel to the line connecting
672 // the cell centers. Therefore, we can use our second order, central difference
673 // scheme to approximate it.
674 auto face_grad = ((side_two_value - side_one_value) / delta) * fi.eCN();
675
676 // We only need non-orthogonal correctors in 2+ dimensions
677 if (this->_mesh.dimension() > 1)
678 {
679 // We are using an orthogonal approach for the non-orthogonal correction, for more information
680 // see Hrvoje Jasak's PhD Thesis (Imperial College, 1996)
681 const auto & interpolated_gradient = uncorrectedAdGradSln(fi, state, correct_skewness);
682 face_grad += interpolated_gradient - (interpolated_gradient * fi.eCN()) * fi.eCN();
683 }
684
685 return face_grad;
686}
687
688template <typename OutputType>
689void
691{
692 if (!_dirichlet_map_setup)
693 determineBoundaryToDirichletBCMap();
694 if (!_flux_map_setup)
695 determineBoundaryToFluxBCMap();
696
697 clearCaches();
698}
699
700template <typename OutputType>
701void
703{
704 clearCaches();
705}
706
707template <typename OutputType>
708void
710{
711 _elem_to_grad.clear();
712}
713
714template <typename OutputType>
715unsigned int
717{
718 unsigned int state = 0;
719 state = std::max(state, _element_data->oldestSolutionStateRequested());
720 state = std::max(state, _neighbor_data->oldestSolutionStateRequested());
721 return state;
722}
723
724template <typename OutputType>
725void
727{
728 _element_data->clearDofIndices();
729 _neighbor_data->clearDofIndices();
730}
731
732template <typename OutputType>
735{
736 const FaceInfo * const fi = face.fi;
737 mooseAssert(fi, "The face information must be non-null");
738 if (isDirichletBoundaryFace(*fi, face.face_side, state))
739 return getDirichletBoundaryFaceValue(*fi, face.face_side, state);
740 else if (isExtrapolatedBoundaryFace(*fi, face.face_side, state))
741 {
742 bool two_term_boundary_expansion = _two_term_boundary_expansion;
744 if ((face.elem_is_upwind && face.face_side == fi->elemPtr()) ||
745 (!face.elem_is_upwind && face.face_side == fi->neighborPtr()))
746 two_term_boundary_expansion = false;
747 return getExtrapolatedBoundaryFaceValue(
748 *fi, two_term_boundary_expansion, face.correct_skewness, face.face_side, state);
749 }
750 else
751 {
752 mooseAssert(this->isInternalFace(*fi),
753 "We must be either Dirichlet, extrapolated, or internal");
754 return Moose::FV::interpolate(*this, face, state);
755 }
756}
757
758template <typename OutputType>
760MooseVariableFV<OutputType>::evaluate(const NodeArg & node_arg, const StateArg & state) const
761{
762 const auto & node_to_elem_map = this->_mesh.nodeToElemMap();
763 const auto & elem_ids = libmesh_map_find(node_to_elem_map, node_arg.node->id());
764 ValueType sum = 0;
765 Real total_weight = 0;
766 mooseAssert(elem_ids.size(), "There should always be at least one element connected to a node");
767 for (const auto elem_id : elem_ids)
768 {
769 const Elem * const elem = this->_mesh.queryElemPtr(elem_id);
770 mooseAssert(elem, "We should have this element available");
771 if (!this->hasBlocks(elem->subdomain_id()))
772 continue;
773 const ElemPointArg elem_point{
774 elem, *node_arg.node, _face_interp_method == Moose::FV::InterpMethod::SkewCorrectedAverage};
775 const auto weight = 1 / (*node_arg.node - elem->vertex_average()).norm();
776 sum += weight * (*this)(elem_point, state);
777 total_weight += weight;
778 }
779 return sum / total_weight;
780}
781
782template <typename OutputType>
785{
786 mooseError("evaluateDot not implemented for this class of finite volume variables");
787}
788
789template <>
790ADReal
791MooseVariableFV<Real>::evaluateDot(const ElemArg & elem_arg, const StateArg & state) const
792{
793 const Elem * const elem = elem_arg.elem;
794 mooseAssert(state.state == 0,
795 "We dot not currently support any time derivative evaluations other than for the "
796 "current time-step");
797 mooseAssert(_time_integrator && _time_integrator->dt(),
798 "A time derivative is being requested but we do not have a time integrator so we'll "
799 "have no idea how to compute it");
800
801 Moose::initDofIndices(const_cast<MooseVariableFV<Real> &>(*this), *elem);
802
803 mooseAssert(
804 this->_dof_indices.size() == 1,
805 "There should only be one dof-index for a constant monomial variable on any given element");
806
807 const dof_id_type dof_index = this->_dof_indices[0];
808
809 if (_var_kind == Moose::VAR_SOLVER)
810 {
811 ADReal dot = (*_solution)(dof_index);
812 if (ADReal::do_derivatives && state.state == 0 &&
813 _sys.number() == _subproblem.currentNlSysNum())
814 Moose::derivInsert(dot.derivatives(), dof_index, 1.);
815 _time_integrator->computeADTimeDerivatives(dot, dof_index, _ad_real_dummy);
816 return dot;
817 }
818 else
819 return (*_sys.solutionUDot())(dof_index);
820}
821
822template <>
823ADReal
824MooseVariableFV<Real>::evaluateDot(const FaceArg & face, const StateArg & state) const
825{
826 const FaceInfo * const fi = face.fi;
827 mooseAssert(fi, "The face information must be non-null");
828 if (isDirichletBoundaryFace(*fi, face.face_side, state))
829 return ADReal(0.0); // No time derivative if boundary value is set
830 else if (isExtrapolatedBoundaryFace(*fi, face.face_side, state))
831 {
832 mooseAssert(face.face_side && this->hasBlocks(face.face_side->subdomain_id()),
833 "If we are an extrapolated boundary face, then our FunctorBase::checkFace method "
834 "should have assigned a non-null element that we are defined on");
835 const auto elem_arg = ElemArg({face.face_side, face.correct_skewness});
836 // For extrapolated boundary faces, note that we take the value of the time derivative at the
837 // cell in contact with the face
838 return evaluateDot(elem_arg, state);
839 }
840 else
841 {
842 mooseAssert(this->isInternalFace(*fi),
843 "We must be either Dirichlet, extrapolated, or internal");
844 return Moose::FV::interpolate<ADReal, FunctorEvaluationKind::Dot>(*this, face, state);
845 }
846}
847
848template <>
849ADReal
850MooseVariableFV<Real>::evaluateDot(const ElemQpArg & elem_qp, const StateArg & state) const
851{
852 return evaluateDot(ElemArg({elem_qp.elem, /*correct_skewness*/ false}), state);
853}
854
855template <typename OutputType>
856void
858{
859 _element_data->prepareAux();
860 _neighbor_data->prepareAux();
861}
862
863template <typename OutputType>
864void
866{
867 mooseAssert(!Threads::in_threads,
868 "This routine has not been implemented for threads. Please query this routine before "
869 "a threaded region or contact a MOOSE developer to discuss.");
870
871 _boundary_id_to_dirichlet_bc.clear();
872 std::vector<FVDirichletBCBase *> bcs;
873
874 // I believe because query() returns by value but condition returns by reference that binding to a
875 // const lvalue reference results in the query() getting destructed and us holding onto a dangling
876 // reference. I think that condition returned by value we would be able to bind to a const lvalue
877 // reference here. But as it is we'll bind to a regular lvalue
878 const auto base_query = this->_subproblem.getMooseApp()
879 .theWarehouse()
880 .query()
881 .template condition<AttribSystem>("FVDirichletBC")
882 .template condition<AttribThread>(_tid)
883 .template condition<AttribVar>(_var_num)
884 .template condition<AttribSysNum>(this->_sys.number());
885
886 for (const auto bnd_id : this->_mesh.getBoundaryIDs())
887 {
888 auto base_query_copy = base_query;
889 base_query_copy.template condition<AttribBoundaries>(std::set<BoundaryID>({bnd_id}))
890 .queryInto(bcs);
891 mooseAssert(bcs.size() <= 1, "cannot have multiple dirichlet BCs on the same boundary");
892 if (!bcs.empty())
893 _boundary_id_to_dirichlet_bc.emplace(bnd_id, bcs[0]);
894 }
895
896 _dirichlet_map_setup = true;
897}
898
899template <typename OutputType>
900void
902{
903 mooseAssert(!Threads::in_threads,
904 "This routine has not been implemented for threads. Please query this routine before "
905 "a threaded region or contact a MOOSE developer to discuss.");
906
907 _boundary_id_to_flux_bc.clear();
908 std::vector<const FVFluxBC *> bcs;
909
910 // I believe because query() returns by value but condition returns by reference that binding to a
911 // const lvalue reference results in the query() getting destructed and us holding onto a dangling
912 // reference. I think that condition returned by value we would be able to bind to a const lvalue
913 // reference here. But as it is we'll bind to a regular lvalue
914 const auto base_query = this->_subproblem.getMooseApp()
915 .theWarehouse()
916 .query()
917 .template condition<AttribSystem>("FVFluxBC")
918 .template condition<AttribThread>(_tid)
919 .template condition<AttribVar>(_var_num)
920 .template condition<AttribSysNum>(this->_sys.number());
921
922 for (const auto bnd_id : this->_mesh.getBoundaryIDs())
923 {
924 auto base_query_copy = base_query;
925 base_query_copy.template condition<AttribBoundaries>(std::set<BoundaryID>({bnd_id}))
926 .queryInto(bcs);
927 if (!bcs.empty())
928 _boundary_id_to_flux_bc.emplace(bnd_id, bcs);
929 }
930
931 _flux_map_setup = true;
932}
933
934template <typename OutputType>
935void
937{
938 _element_data->sizeMatrixTagData();
939 _neighbor_data->sizeMatrixTagData();
940}
941
942template class MooseVariableFV<Real>;
943// TODO: implement vector fv variable support. This will require some template
944// specializations for various member functions in this and the FV variable
945// classes. And then you will need to uncomment out the line below:
946// template class MooseVariableFV<RealVectorValue>;
DualNumber< Real, DNDerivativeType, true > ADReal
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
registerMooseObject("MooseApp", MooseVariableFVReal)
std::array< Real, 2 > values
Definition MortarUtils.C:52
if(!dmm->_nl) SETERRQ(PETSC_COMM_WORLD
const Elem *const & elem() const
Return the current element.
Definition Assembly.h:414
const Elem *const & neighbor() const
Return the neighbor element.
Definition Assembly.h:470
Base class for finite volume Dirichlet boundaray conditions.
virtual ADReal boundaryValue(const FaceInfo &fi, const Moose::StateArg &state) const =0
This data structure is used to store geometric and variable related metadata about each cell face in ...
Definition FaceInfo.h:38
VarFaceNeighbors faceType(const std::pair< unsigned int, unsigned int > &var_sys) const
Returns which side(s) the given variable-system number pair is defined on for this face.
Definition FaceInfo.h:229
const Point & eCN() const
Definition FaceInfo.h:155
const std::set< BoundaryID > & boundaryIDs() const
Const getter for every associated boundary ID.
Definition FaceInfo.h:124
const Elem & elem() const
Definition FaceInfo.h:85
const Elem * neighborPtr() const
Definition FaceInfo.h:88
Real dCNMag() const
Definition FaceInfo.h:148
const Elem * elemPtr() const
Definition FaceInfo.h:86
const Point & neighborCentroid() const
Definition FaceInfo.h:247
const Point & elemCentroid() const
Returns the element centroids of the elements on the elem and neighbor sides of the face.
Definition FaceInfo.h:99
const Point & faceCentroid() const
Returns the coordinates of the face centroid.
Definition FaceInfo.h:75
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
std::vector< std::pair< R1, R2 > > get(const std::string &param1, const std::string &param2) const
Combine two vector parameters into a single vector of pairs.
void addRelationshipManager(const std::string &name, Moose::RelationshipManagerType rm_type, Moose::RelationshipManagerInputParameterCallback input_parameter_callback=nullptr)
Tells MOOSE about a RelationshipManager that this object needs.
T & set(const std::string &name, bool quiet_mode=false)
Returns a writable reference to the named parameters.
forward declarations
Definition MooseArray.h:18
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Definition MooseBase.h:199
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition MooseEnum.h:55
THREAD_ID _tid
Thread ID.
Assembly & _assembly
Assembly data.
SystemBase & _sys
System this variable is part of.
virtual void setNodalValue(const OutputType &value, unsigned int idx=0) override
virtual void computeNeighborValuesFace() override
Compute values at facial quadrature points for the neighbor.
const DofValues & dofValuesDot() const override
DofValue getElementalValue(const Elem *elem, unsigned int idx=0) const
Get the current value of this variable on an element.
std::unique_ptr< MooseVariableDataFV< OutputType > > _element_data
Holder for all the data associated with the "main" element.
static InputParameters validParams()
const DofValues & dofValuesDotDotOld() const override
DofValue getElementalValueOlder(const Elem *elem, unsigned int idx=0) const
Get the older value of this variable on an element.
const DofValues & dofValuesOld() const override
virtual VectorValue< ADReal > uncorrectedAdGradSln(const FaceInfo &fi, const StateArg &state, const bool correct_skewness=false) const
Retrieve (or potentially compute) the uncorrected gradient on the provided face.
virtual void prepareIC() override
Prepare the initial condition.
void clearDofIndices() override
Clear out the dof indices.
bool isExtrapolatedBoundaryFace(const FaceInfo &fi, const Elem *elem, const Moose::StateArg &state) const override
Returns whether this is an extrapolated boundary face.
void determineBoundaryToDirichletBCMap()
Setup the boundary to Dirichlet BC map.
Moose::FV::InterpMethod _face_interp_method
Decides if an average or skewed corrected average is used for the face interpolation.
OutputTools< OutputType >::OutputGradient getGradient(const Elem *elem) const
Compute the variable gradient value at a point on an element.
const MooseArray< libMesh::Number > & dofValuesDuDotDu() const override
const DofValues & dofValuesOldNeighbor() const override
virtual bool isDirichletBoundaryFace(const FaceInfo &fi, const Elem *elem, const Moose::StateArg &state) const
Determine whether a specified face side is a Dirichlet boundary face.
const MooseArray< libMesh::Number > & dofValuesDuDotDotDu() const override
std::pair< bool, std::vector< const FVFluxBC * > > getFluxBCs(const FaceInfo &fi) const
DofValue getElementalValueOld(const Elem *elem, unsigned int idx=0) const
Get the old value of this variable on an element.
const DofValues & dofValuesDotOldNeighbor() const override
virtual ADReal getExtrapolatedBoundaryFaceValue(const FaceInfo &fi, bool two_term_expansion, bool correct_skewness, const Elem *elem_side_to_extrapolate_from, const StateArg &state) const
Retrieves an extrapolated boundary value for the provided face.
OutputType getValue(const Elem *elem) const
Note: const monomial is always the case - higher order solns are reconstructed - so this is simpler f...
const DofValues & dofValuesPreviousNL() const override
const DofValues & dofValuesDotNeighbor() const override
const DofValues & dofValuesNeighbor() const override
const DofValues & dofValuesDotDot() const override
unsigned int oldestSolutionStateRequested() const override final
The oldest solution state that is requested for this variable (0 = current, 1 = old,...
virtual void insertLower(libMesh::NumericVector< libMesh::Number > &vector) override
Insert the currently cached degree of freedom values for a lower-dimensional element into the provide...
virtual void setDofValues(const DenseVector< DofValue > &values) override
Set local DOF values and evaluate the values on quadrature points.
ADReal getElemValue(const Elem *elem, const StateArg &state) const
Get the solution value for the provided element and seed the derivative for the corresponding dof ind...
ADReal getBoundaryFaceValue(const FaceInfo &fi, const StateArg &state, bool correct_skewness=false) const
Retrieve the solution value at a boundary face.
virtual void insert(libMesh::NumericVector< libMesh::Number > &vector) override
Insert the currently cached degree of freedom values into the provided vector.
virtual void residualSetup() override
Gets called just before the residual is computed and before this object is asked to do its job.
const DofValues & dofValuesPreviousNLNeighbor() const override
const DofValues & dofValuesOlder() const override
virtual void computeNeighborValues() override
Compute values at quadrature points for the neighbor.
std::pair< bool, const FVDirichletBCBase * > getDirichletBC(const FaceInfo &fi) const
MooseVariableFV(const InputParameters &parameters)
virtual void computeElemValuesFace() override
Compute values at facial quadrature points.
void clearAllDofIndices() final
virtual ADReal getDirichletBoundaryFaceValue(const FaceInfo &fi, const Elem *elem, const Moose::StateArg &state) const
Retrieves a Dirichlet boundary value for the provided face.
std::unique_ptr< MooseVariableDataFV< OutputType > > _neighbor_data
Holder for all the data associated with the neighbor element.
virtual void add(libMesh::NumericVector< libMesh::Number > &vector) override
Add the currently cached degree of freedom values into the provided vector.
virtual void setLowerDofValues(const DenseVector< DofValue > &values) override
Set local DOF values for a lower dimensional element and evaluate the values on quadrature points.
virtual void sizeMatrixTagData() override
Size data structures related to matrix tagging.
DotType evaluateDot(const ElemArg &elem, const StateArg &) const override final
Evaluate the functor time derivative with a given element.
void clearCaches()
clear finite volume caches
void determineBoundaryToFluxBCMap()
Setup the boundary to Flux BC map.
virtual void computeFaceValues(const FaceInfo &fi) override
Initializes/computes variable values from the solution vectors for the face represented by fi.
const MooseArray< libMesh::Number > & dofValuesDuDotDuNeighbor() const override
typename MooseVariableField< OutputType >::OutputShape OutputShape
virtual void prepareAux() override final
virtual void computeElemValues() override
Initializes/computes variable values from the solution vectors for the current element being operated...
const DofValues & dofValuesDotOld() const override
const DofValues & dofValuesDotDotNeighbor() const override
const DofValues & dofValues() const override
dof values getters
const ADTemplateVariableGradient< OutputType > & adGradSln() const override
AD grad solution getter.
virtual void jacobianSetup() override
Gets called just before the Jacobian is computed and before this object is asked to do its job.
const DofValues & dofValuesDotDotOldNeighbor() const override
virtual void setDofValue(const DofValue &value, unsigned int index) override
Degree of freedom value setters.
ValueType evaluate(const ElemArg &elem, const StateArg &) const override final
Evaluate the functor with a given element.
const DofValues & dofValuesOlderNeighbor() const override
const MooseArray< libMesh::Number > & dofValuesDuDotDotDuNeighbor() const override
Class for stuff related to variables.
typename MooseVariableDataBase< OutputType >::DofValue DofValue
static InputParameters validParams()
typename MooseVariableDataBase< OutputType >::DofValues DofValues
virtual const OutputTools< T >::VariableSecond & second()
The second derivative of the variable this object is operating on.
dof_id_type id() const
subdomain_id_type subdomain_id() const
std::tuple< const Elem *, const Elem *, bool > determineElemOneAndTwo(const FaceInfo &fi, const FVVar &var)
This utility determines element one and element two given a FaceInfo fi and variable var.
Definition FVUtils.h:130
void interpolate(InterpMethod m, T &result, const T2 &value1, const T3 &value2, const FaceInfo &fi, const bool one_is_elem)
Provides interpolation of face values for non-advection-specific purposes (although it can/will still...
libMesh::CompareTypes< T, T2 >::supertype linearInterpolation(const T &value1, const T2 &value2, const FaceInfo &fi, const bool one_is_elem, const InterpMethod interp_method=InterpMethod::Average)
A simple linear interpolation of values between cell centers to a cell face.
@ SkewCorrectedAverage
(gc*elem+(1-gc)*neighbor)+gradient*(rf-rf')
@ Average
gc*elem+(1-gc)*neighbor
libMesh::VectorValue< T > greenGaussGradient(const ElemArg &elem_arg, const StateArg &state_arg, const FunctorBase< T > &functor, const bool two_term_boundary_expansion, const MooseMesh &mesh, const bool force_green_gauss=false)
Compute a cell gradient using the method of Green-Gauss.
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
@ Current
Definition MooseTypes.h:263
std::string stringify(const T &t)
conversion to string
Definition Conversion.h:64
@ VAR_SOLVER
Definition MooseTypes.h:770
void initDofIndices(T &data, const Elem &elem)
void derivInsert(SemiDynamicSparseNumberArray< Real, libMesh::dof_id_type, NWrapper< N > > &derivs, libMesh::dof_id_type index, Real value)
Definition ADReal.h:21
A structure that is used to evaluate Moose functors logically at an element/cell center.
const libMesh::Elem * elem
A structure that is used to evaluate Moose functors at an arbitrary physical point contained within a...
Argument for requesting functor evaluation at a quadrature point location in an element.
const libMesh::Elem * elem
The element.
A structure defining a "face" evaluation calling argument for Moose functors.
bool elem_is_upwind
a boolean which states whether the face information element is upwind of the face
bool correct_skewness
Whether to perform skew correction.
Moose::FV::LimiterType limiter_type
a limiter which defines how the functor evaluated on either side of the face should be interpolated t...
const libMesh::Elem * face_side
A member that can be used to indicate whether there is a sidedness to this face.
const FaceInfo * fi
a face information object which defines our location in space
const libMesh::Node * node
The node which defines our location in space.
State argument for evaluating functors.
SolutionIterationType iteration_type
The solution iteration type, e.g. time or nonlinear.
unsigned int state
The state.