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 // A finite volume variable is always a CONSTANT MONOMIAL, whose basis has no p-refined
41 // counterpart, so the p-refinement parameters are fixed here and hidden from the user
42 params.set<bool>("p_refinement") = false;
43 params.suppressParameter<bool>("p_refinement");
44 params.suppressParameter<bool>("disable_p_refinement");
45 params.template addParam<bool>(
46 "two_term_boundary_expansion",
47 true,
48 "Whether to use a two-term Taylor expansion to calculate boundary face values. "
49 "If the two-term expansion is used, then the boundary face value depends on the "
50 "adjoining cell center gradient, which itself depends on the boundary face value. "
51 "Consequently an implicit solve is used to simultaneously solve for the adjoining cell "
52 "center gradient and boundary face value(s).");
53 MooseEnum face_interp_method("average skewness-corrected", "average");
54 params.template addParam<MooseEnum>("face_interp_method",
55 face_interp_method,
56 "Switch that can select between face interpolation methods.");
57 params.template addParam<bool>(
58 "cache_cell_gradients", true, "Whether to cache cell gradients or re-compute them.");
59
60 // Depending on the face interpolation we might have to do more than one layer ghosting.
62 "ElementSideNeighborLayers",
65 [](const InputParameters & obj_params, InputParameters & rm_params)
66 {
67 unsigned short layers = 1;
68 if (obj_params.get<MooseEnum>("face_interp_method") == "skewness-corrected")
69 layers = 2;
70
71 rm_params.set<unsigned short>("layers") = layers;
72 });
73 return params;
74}
75
76template <typename OutputType>
78 : MooseVariableField<OutputType>(parameters),
79 _solution(this->_sys.currentSolution()),
80 _phi(this->_assembly.template fePhi<OutputShape>(this->_fe_type)),
81 _grad_phi(this->_assembly.template feGradPhi<OutputShape>(this->_fe_type)),
82 _phi_face(this->_assembly.template fePhiFace<OutputShape>(this->_fe_type)),
83 _grad_phi_face(this->_assembly.template feGradPhiFace<OutputShape>(this->_fe_type)),
84 _phi_face_neighbor(this->_assembly.template fePhiFaceNeighbor<OutputShape>(this->_fe_type)),
85 _grad_phi_face_neighbor(
86 this->_assembly.template feGradPhiFaceNeighbor<OutputShape>(this->_fe_type)),
87 _phi_neighbor(this->_assembly.template fePhiNeighbor<OutputShape>(this->_fe_type)),
88 _grad_phi_neighbor(this->_assembly.template feGradPhiNeighbor<OutputShape>(this->_fe_type)),
89 _prev_elem(nullptr),
90 _two_term_boundary_expansion(this->isParamValid("two_term_boundary_expansion")
91 ? this->template getParam<bool>("two_term_boundary_expansion")
92 : true),
93 _cache_cell_gradients(this->isParamValid("cache_cell_gradients")
94 ? this->template getParam<bool>("cache_cell_gradients")
95 : true)
96{
97 _element_data = std::make_unique<MooseVariableDataFV<OutputType>>(
99 _neighbor_data = std::make_unique<MooseVariableDataFV<OutputType>>(
101
102 if (this->isParamValid("face_interp_method"))
103 {
104 const auto & interp_method = this->template getParam<MooseEnum>("face_interp_method");
105 if (interp_method == "average")
107 else if (interp_method == "skewness-corrected")
109 }
110 else
112}
113
114template <typename OutputType>
115void
117{
118 _element_data->clearDofIndices();
119}
120
121template <typename OutputType>
123MooseVariableFV<OutputType>::getElementalValue(const Elem * elem, unsigned int idx) const
124{
125 return _element_data->getElementalValue(elem, Moose::Current, idx);
126}
127
128template <typename OutputType>
130MooseVariableFV<OutputType>::getElementalValueOld(const Elem * elem, unsigned int idx) const
131{
132 return _element_data->getElementalValue(elem, Moose::Old, idx);
133}
135template <typename OutputType>
137MooseVariableFV<OutputType>::getElementalValueOlder(const Elem * elem, unsigned int idx) const
138{
139 return _element_data->getElementalValue(elem, Moose::Older, idx);
140}
141
142template <typename OutputType>
143void
144MooseVariableFV<OutputType>::insert(NumericVector<Number> & residual)
145{
146 _element_data->insert(residual);
147}
148
149template <typename OutputType>
150void
152{
153 lowerDError();
154}
155
156template <typename OutputType>
157void
158MooseVariableFV<OutputType>::add(NumericVector<Number> & residual)
159{
160 _element_data->add(residual);
161}
162
163template <typename OutputType>
166{
167 return _element_data->dofValues();
168}
170template <typename OutputType>
174 return _element_data->dofValuesOld();
176
177template <typename OutputType>
180{
181 return _element_data->dofValuesOlder();
182}
183
184template <typename OutputType>
187{
188 return _element_data->dofValuesPreviousNL();
189}
190
191template <typename OutputType>
194{
195 return _neighbor_data->dofValues();
197
198template <typename OutputType>
201{
202 return _neighbor_data->dofValuesOld();
203}
204
205template <typename OutputType>
208{
209 return _neighbor_data->dofValuesOlder();
210}
211
212template <typename OutputType>
215{
216 return _neighbor_data->dofValuesPreviousNL();
217}
218
219template <typename OutputType>
222{
223 return _element_data->dofValuesDot();
224}
225
226template <typename OutputType>
229{
230 return _element_data->dofValuesDotDot();
231}
232
233template <typename OutputType>
236{
237 return _element_data->dofValuesDotOld();
238}
239
240template <typename OutputType>
243{
244 return _element_data->dofValuesDotDotOld();
245}
246
247template <typename OutputType>
250{
251 return _neighbor_data->dofValuesDot();
252}
253
254template <typename OutputType>
257{
258 return _neighbor_data->dofValuesDotDot();
259}
260
261template <typename OutputType>
264{
265 return _neighbor_data->dofValuesDotOld();
266}
267
268template <typename OutputType>
271{
272 return _neighbor_data->dofValuesDotDotOld();
273}
274
275template <typename OutputType>
276const MooseArray<Number> &
278{
279 return _element_data->dofValuesDuDotDu();
280}
281
282template <typename OutputType>
285{
286 return _element_data->dofValuesDuDotDotDu();
287}
288
289template <typename OutputType>
290const MooseArray<Number> &
292{
293 return _neighbor_data->dofValuesDuDotDu();
294}
295
296template <typename OutputType>
297const MooseArray<Number> &
299{
300 return _neighbor_data->dofValuesDuDotDotDu();
301}
302
303template <typename OutputType>
304void
306{
307 _element_data->prepareIC();
308}
309
310template <typename OutputType>
311void
313{
314 _element_data->setGeometry(Moose::Volume);
315 _element_data->computeValues();
316}
317
318template <typename OutputType>
319void
321{
322 _element_data->setGeometry(Moose::Face);
323 _element_data->computeValues();
324}
325
326template <typename OutputType>
327void
329{
330 _neighbor_data->setGeometry(Moose::Face);
331 _neighbor_data->computeValues();
332}
333
334template <typename OutputType>
335void
337{
338 _neighbor_data->setGeometry(Moose::Volume);
339 _neighbor_data->computeValues();
340}
341
342template <typename OutputType>
343void
345{
346 _element_data->setGeometry(Moose::Face);
347 _neighbor_data->setGeometry(Moose::Face);
348
349 const auto facetype = fi.faceType(std::make_pair(this->number(), this->sys().number()));
351 return;
352 else if (facetype == FaceInfo::VarFaceNeighbors::BOTH)
353 {
354 _element_data->computeValuesFace(fi);
355 _neighbor_data->computeValuesFace(fi);
356 }
357 else if (facetype == FaceInfo::VarFaceNeighbors::ELEM)
358 _element_data->computeValuesFace(fi);
359 else if (facetype == FaceInfo::VarFaceNeighbors::NEIGHBOR)
360 _neighbor_data->computeValuesFace(fi);
361 else
362 mooseError("robert wrote broken MooseVariableFV code");
363}
364
365template <typename OutputType>
366OutputType
368{
369 Moose::initDofIndices(const_cast<MooseVariableFV<OutputType> &>(*this), *elem);
370 mooseAssert(this->_dof_indices.size() == 1, "Wrong size for dof indices");
371 OutputType value = (*this->_sys.currentSolution())(this->_dof_indices[0]);
372 return value;
373}
374
375template <typename OutputType>
378{
379 return {};
380}
381
382template <typename OutputType>
383void
385{
386 mooseError("FV variables do not support setNodalValue");
387}
388
389template <typename OutputType>
390void
391MooseVariableFV<OutputType>::setDofValue(const DofValue & value, unsigned int index)
392{
393 _element_data->setDofValue(value, index);
394}
396template <typename OutputType>
397void
399{
400 _element_data->setDofValues(values);
401}
403template <typename OutputType>
404void
406{
407 lowerDError();
408}
409
410template <typename OutputType>
411std::pair<bool, const FVDirichletBCBase *>
413{
414 for (const auto bnd_id : fi.boundaryIDs())
415 if (auto it = _boundary_id_to_dirichlet_bc.find(bnd_id);
416 it != _boundary_id_to_dirichlet_bc.end())
417 return {true, it->second};
419 return {false, nullptr};
422template <typename OutputType>
423std::pair<bool, std::vector<const FVFluxBC *>>
426 for (const auto bnd_id : fi.boundaryIDs())
427 if (auto it = _boundary_id_to_flux_bc.find(bnd_id); it != _boundary_id_to_flux_bc.end())
428 return {true, it->second};
430 return std::make_pair(false, std::vector<const FVFluxBC *>());
433template <typename OutputType>
435MooseVariableFV<OutputType>::getElemValue(const Elem * const elem, const StateArg & state) const
437 mooseAssert(elem,
438 "The elem shall exist! This typically occurs when the "
439 "user wants to evaluate non-existing elements (nullptr) at physical boundaries.");
440 mooseAssert(
441 this->hasBlocks(elem->subdomain_id()),
442 "The variable should be defined on the element's subdomain! This typically occurs when the "
443 "user wants to evaluate the elements right next to the boundary of two variables (block "
444 "boundary). The subdomain which is queried: " +
445 Moose::stringify(this->activeSubdomains()) + " the subdomain of the element " +
446 std::to_string(elem->subdomain_id()));
447
448 Moose::initDofIndices(const_cast<MooseVariableFV<OutputType> &>(*this), *elem);
449
450 mooseAssert(
451 this->_dof_indices.size() == 1,
452 "There should only be one dof-index for a constant monomial variable on any given element");
453
454 const dof_id_type index = this->_dof_indices[0];
455
456 // It's not safe to use solutionState(0) because it returns the libMesh System solution member
457 // which is wrong during things like finite difference Jacobian evaluation, e.g. when PETSc
458 // perturbs the solution vector we feed these perturbations into the current_local_solution
459 // while the libMesh solution is frozen in the non-perturbed state
460 const auto & global_soln =
461 (state.state == 0)
462 ? *this->_sys.currentSolution()
463 : std::as_const(this->_sys).solutionState(state.state, state.iteration_type);
465 ADReal value = global_soln(index);
467 if (ADReal::do_derivatives && state.state == 0 &&
468 this->_sys.number() == this->_subproblem.currentNlSysNum())
469 Moose::derivInsert(value.derivatives(), index, 1.);
470
471 return value;
472}
473
474template <typename OutputType>
475bool
477 const Elem *,
478 const Moose::StateArg &) const
480 const auto & pr = getDirichletBC(fi);
481
482 // First member of this pair indicates whether we have a DirichletBC
483 return pr.first;
484}
485
486template <typename OutputType>
487ADReal
489 const Elem * const libmesh_dbg_var(elem),
490 const Moose::StateArg & state) const
491{
492 mooseAssert(isDirichletBoundaryFace(fi, elem, state),
493 "This function should only be called on Dirichlet boundary faces.");
494
495 const auto & diri_pr = getDirichletBC(fi);
496
497 mooseAssert(diri_pr.first,
498 "This functor should only be called if we are on a Dirichlet boundary face.");
499
500 const FVDirichletBCBase & bc = *diri_pr.second;
501
502 return ADReal(bc.boundaryValue(fi, state));
503}
504
505template <typename OutputType>
506bool
508 const Elem * const elem,
509 const Moose::StateArg & state) const
510{
511 if (isDirichletBoundaryFace(fi, elem, state))
512 return false;
513 else
514 return !this->isInternalFace(fi);
515}
516
517template <typename OutputType>
518ADReal
520 const bool two_term_expansion,
521 const bool correct_skewness,
522 const Elem * elem_to_extrapolate_from,
523 const StateArg & state) const
524{
525 mooseAssert(
526 isExtrapolatedBoundaryFace(fi, elem_to_extrapolate_from, state) || !two_term_expansion,
527 "We allow Dirichlet boundary conditions to call this method. However, the only way to "
528 "ensure we don't have infinite recursion, with Green Gauss gradients calling back to the "
529 "Dirichlet boundary condition calling back to this method, is to do a one term expansion");
530
531 ADReal boundary_value;
532 bool elem_to_extrapolate_from_is_fi_elem;
533 std::tie(elem_to_extrapolate_from, elem_to_extrapolate_from_is_fi_elem) =
534 [this, &fi, elem_to_extrapolate_from]() -> std::pair<const Elem *, bool>
535 {
536 if (elem_to_extrapolate_from)
537 // Somebody already specified the element to extropolate from
538 return {elem_to_extrapolate_from, elem_to_extrapolate_from == fi.elemPtr()};
539 else
541 const auto [elem_guaranteed_to_have_dofs,
542 other_elem,
543 elem_guaranteed_to_have_dofs_is_fi_elem] =
545 // We only care about the element guaranteed to have degrees of freedom and current C++
546 // doesn't allow us to not assign one of the returned items like python does
547 libmesh_ignore(other_elem);
548 // We will extrapolate from the element guaranteed to have degrees of freedom
549 return {elem_guaranteed_to_have_dofs, elem_guaranteed_to_have_dofs_is_fi_elem};
551 }();
552
553 if (two_term_expansion)
554 {
555 const Point vector_to_face = elem_to_extrapolate_from_is_fi_elem
556 ? (fi.faceCentroid() - fi.elemCentroid())
557 : (fi.faceCentroid() - fi.neighborCentroid());
558 boundary_value = adGradSln(elem_to_extrapolate_from, state, correct_skewness) * vector_to_face +
559 getElemValue(elem_to_extrapolate_from, state);
560 }
561 else
562 boundary_value = getElemValue(elem_to_extrapolate_from, state);
563
564 return boundary_value;
565}
567template <typename OutputType>
568ADReal
570 const StateArg & state,
571 const bool correct_skewness) const
572{
573 mooseAssert(!this->isInternalFace(fi),
574 "A boundary face value has been requested on an internal face.");
575
576 if (isDirichletBoundaryFace(fi, nullptr, state))
577 return getDirichletBoundaryFaceValue(fi, nullptr, state);
578 else if (isExtrapolatedBoundaryFace(fi, nullptr, state))
579 return getExtrapolatedBoundaryFaceValue(
580 fi, _two_term_boundary_expansion, correct_skewness, nullptr, state);
581
582 mooseError("Unknown boundary face type!");
583}
584
585template <typename OutputType>
586const VectorValue<ADReal> &
588 const StateArg & state,
589 const bool correct_skewness) const
590{
591 // We ensure that no caching takes place when we compute skewness-corrected
592 // quantities.
593 if (_cache_cell_gradients && !correct_skewness && state.state == 0)
594 {
595 auto it = _elem_to_grad.find(elem);
596
597 if (it != _elem_to_grad.end())
598 return it->second;
599 }
600
601 auto grad = FV::greenGaussGradient(
602 ElemArg({elem, correct_skewness}), state, *this, _two_term_boundary_expansion, this->_mesh);
603
604 if (_cache_cell_gradients && !correct_skewness && state.state == 0)
605 {
606 auto pr = _elem_to_grad.emplace(elem, std::move(grad));
607 mooseAssert(pr.second, "Insertion should have just happened.");
608 return pr.first->second;
609 }
610 else
611 {
612 _temp_cell_gradient = std::move(grad);
613 return _temp_cell_gradient;
614 }
615}
616
617template <typename OutputType>
618VectorValue<ADReal>
620 const StateArg & state,
621 const bool correct_skewness) const
622{
623 const auto face_type = fi.faceType(std::make_pair(this->number(), this->sys().number()));
624 mooseAssert(face_type != FaceInfo::VarFaceNeighbors::NEITHER,
625 "Gradient requested on a face where the variable is defined on neither side.");
626
627 const bool var_defined_on_elem = (face_type == FaceInfo::VarFaceNeighbors::BOTH) ||
629 const Elem * const elem_one = var_defined_on_elem ? &fi.elem() : fi.neighborPtr();
630 const Elem * const elem_two = var_defined_on_elem ? fi.neighborPtr() : &fi.elem();
631
632 const VectorValue<ADReal> elem_one_grad = adGradSln(elem_one, state, correct_skewness);
633
634 // If we have a neighbor then we interpolate between the two to the face. If we do not, then we
635 // apply a zero Hessian assumption and use the element centroid gradient as the uncorrected face
636 // gradient
637 if (face_type == FaceInfo::VarFaceNeighbors::BOTH)
638 {
639 mooseAssert(elem_two, "Face type indicates BOTH but neighbor information is missing.");
640 const VectorValue<ADReal> & elem_two_grad = adGradSln(elem_two, state, correct_skewness);
641
642 // Uncorrected gradient value
643 return Moose::FV::linearInterpolation(elem_one_grad, elem_two_grad, fi, var_defined_on_elem);
644 }
645 else
646 return elem_one_grad;
647}
648
649template <typename OutputType>
650VectorValue<ADReal>
652 const StateArg & state,
653 const bool correct_skewness) const
654{
655 const bool var_defined_on_elem = this->hasBlocks(fi.elem().subdomain_id());
656 const Elem * const elem = &fi.elem();
657 const Elem * const neighbor = fi.neighborPtr();
658
659 const bool is_internal_face = this->isInternalFace(fi);
660
661 const ADReal side_one_value = (!is_internal_face && !var_defined_on_elem)
662 ? getBoundaryFaceValue(fi, state, correct_skewness)
663 : getElemValue(elem, state);
664 const ADReal side_two_value = (var_defined_on_elem && !is_internal_face)
665 ? getBoundaryFaceValue(fi, state, correct_skewness)
666 : getElemValue(neighbor, state);
667
668 const auto delta =
669 this->isInternalFace(fi)
670 ? fi.dCNMag()
671 : (fi.faceCentroid() - (var_defined_on_elem ? fi.elemCentroid() : fi.neighborCentroid()))
672 .norm();
673
674 // This is the component of the gradient which is parallel to the line connecting
675 // the cell centers. Therefore, we can use our second order, central difference
676 // scheme to approximate it.
677 auto face_grad = ((side_two_value - side_one_value) / delta) * fi.eCN();
678
679 // We only need non-orthogonal correctors in 2+ dimensions
680 if (this->_mesh.dimension() > 1)
682 // We are using an orthogonal approach for the non-orthogonal correction, for more information
683 // see Hrvoje Jasak's PhD Thesis (Imperial College, 1996)
684 const auto & interpolated_gradient = uncorrectedAdGradSln(fi, state, correct_skewness);
685 face_grad += interpolated_gradient - (interpolated_gradient * fi.eCN()) * fi.eCN();
686 }
687
688 return face_grad;
689}
690
691template <typename OutputType>
692void
694{
695 if (!_dirichlet_map_setup)
696 determineBoundaryToDirichletBCMap();
697 if (!_flux_map_setup)
698 determineBoundaryToFluxBCMap();
699
700 clearCaches();
701}
702
703template <typename OutputType>
704void
706{
707 clearCaches();
708}
709
710template <typename OutputType>
711void
713{
714 _elem_to_grad.clear();
715}
716
717template <typename OutputType>
718unsigned int
720{
721 unsigned int state = 0;
722 state = std::max(state, _element_data->oldestSolutionStateRequested());
723 state = std::max(state, _neighbor_data->oldestSolutionStateRequested());
724 return state;
725}
726
727template <typename OutputType>
728void
730{
731 _element_data->clearDofIndices();
732 _neighbor_data->clearDofIndices();
733}
734
735template <typename OutputType>
738{
739 const FaceInfo * const fi = face.fi;
740 mooseAssert(fi, "The face information must be non-null");
741 if (isDirichletBoundaryFace(*fi, face.face_side, state))
742 return getDirichletBoundaryFaceValue(*fi, face.face_side, state);
743 else if (isExtrapolatedBoundaryFace(*fi, face.face_side, state))
744 {
745 bool two_term_boundary_expansion = _two_term_boundary_expansion;
747 if ((face.elem_is_upwind && face.face_side == fi->elemPtr()) ||
748 (!face.elem_is_upwind && face.face_side == fi->neighborPtr()))
749 two_term_boundary_expansion = false;
750 return getExtrapolatedBoundaryFaceValue(
751 *fi, two_term_boundary_expansion, face.correct_skewness, face.face_side, state);
752 }
753 else
754 {
755 mooseAssert(this->isInternalFace(*fi),
756 "We must be either Dirichlet, extrapolated, or internal");
757 return Moose::FV::interpolate(*this, face, state);
758 }
759}
760
761template <typename OutputType>
763MooseVariableFV<OutputType>::evaluate(const NodeArg & node_arg, const StateArg & state) const
764{
765 const auto & node_to_elem_map = this->_mesh.nodeToElemMap();
766 const auto & elem_ids = libmesh_map_find(node_to_elem_map, node_arg.node->id());
767 ValueType sum = 0;
768 Real total_weight = 0;
769 mooseAssert(elem_ids.size(), "There should always be at least one element connected to a node");
770 for (const auto elem_id : elem_ids)
771 {
772 const Elem * const elem = this->_mesh.queryElemPtr(elem_id);
773 mooseAssert(elem, "We should have this element available");
774 if (!this->hasBlocks(elem->subdomain_id()))
775 continue;
776 const ElemPointArg elem_point{
777 elem, *node_arg.node, _face_interp_method == Moose::FV::InterpMethod::SkewCorrectedAverage};
778 const auto weight = 1 / (*node_arg.node - elem->vertex_average()).norm();
779 sum += weight * (*this)(elem_point, state);
780 total_weight += weight;
781 }
782 return sum / total_weight;
783}
784
785template <typename OutputType>
788{
789 mooseError("evaluateDot not implemented for this class of finite volume variables");
790}
791
792template <>
793ADReal
794MooseVariableFV<Real>::evaluateDot(const ElemArg & elem_arg, const StateArg & state) const
795{
796 const Elem * const elem = elem_arg.elem;
797 mooseAssert(state.state == 0,
798 "We dot not currently support any time derivative evaluations other than for the "
799 "current time-step");
800 mooseAssert(_time_integrator && _time_integrator->dt(),
801 "A time derivative is being requested but we do not have a time integrator so we'll "
802 "have no idea how to compute it");
803
804 Moose::initDofIndices(const_cast<MooseVariableFV<Real> &>(*this), *elem);
805
806 mooseAssert(
807 this->_dof_indices.size() == 1,
808 "There should only be one dof-index for a constant monomial variable on any given element");
809
810 const dof_id_type dof_index = this->_dof_indices[0];
811
812 if (_var_kind == Moose::VAR_SOLVER)
813 {
814 ADReal dot = (*_solution)(dof_index);
815 if (ADReal::do_derivatives && state.state == 0 &&
816 _sys.number() == _subproblem.currentNlSysNum())
817 Moose::derivInsert(dot.derivatives(), dof_index, 1.);
818 _time_integrator->computeADTimeDerivatives(dot, dof_index, _ad_real_dummy);
819 return dot;
820 }
821 else
822 return (*_sys.solutionUDot())(dof_index);
823}
824
825template <>
826ADReal
827MooseVariableFV<Real>::evaluateDot(const FaceArg & face, const StateArg & state) const
828{
829 const FaceInfo * const fi = face.fi;
830 mooseAssert(fi, "The face information must be non-null");
831 if (isDirichletBoundaryFace(*fi, face.face_side, state))
832 return ADReal(0.0); // No time derivative if boundary value is set
833 else if (isExtrapolatedBoundaryFace(*fi, face.face_side, state))
834 {
835 mooseAssert(face.face_side && this->hasBlocks(face.face_side->subdomain_id()),
836 "If we are an extrapolated boundary face, then our FunctorBase::checkFace method "
837 "should have assigned a non-null element that we are defined on");
838 const auto elem_arg = ElemArg({face.face_side, face.correct_skewness});
839 // For extrapolated boundary faces, note that we take the value of the time derivative at the
840 // cell in contact with the face
841 return evaluateDot(elem_arg, state);
842 }
843 else
844 {
845 mooseAssert(this->isInternalFace(*fi),
846 "We must be either Dirichlet, extrapolated, or internal");
847 return Moose::FV::interpolate<ADReal, FunctorEvaluationKind::Dot>(*this, face, state);
848 }
849}
850
851template <>
852ADReal
853MooseVariableFV<Real>::evaluateDot(const ElemQpArg & elem_qp, const StateArg & state) const
854{
855 return evaluateDot(ElemArg({elem_qp.elem, /*correct_skewness*/ false}), state);
856}
857
858template <typename OutputType>
859void
861{
862 _element_data->prepareAux();
863 _neighbor_data->prepareAux();
864}
865
866template <typename OutputType>
867void
869{
870 mooseAssert(!Threads::in_threads,
871 "This routine has not been implemented for threads. Please query this routine before "
872 "a threaded region or contact a MOOSE developer to discuss.");
873
874 _boundary_id_to_dirichlet_bc.clear();
875 std::vector<FVDirichletBCBase *> bcs;
876
877 // I believe because query() returns by value but condition returns by reference that binding to a
878 // const lvalue reference results in the query() getting destructed and us holding onto a dangling
879 // reference. I think that condition returned by value we would be able to bind to a const lvalue
880 // reference here. But as it is we'll bind to a regular lvalue
881 const auto base_query = this->_subproblem.getMooseApp()
882 .theWarehouse()
883 .query()
884 .template condition<AttribSystem>("FVDirichletBC")
885 .template condition<AttribThread>(_tid)
886 .template condition<AttribVar>(_var_num)
887 .template condition<AttribSysNum>(this->_sys.number());
888
889 for (const auto bnd_id : this->_mesh.getBoundaryIDs())
890 {
891 auto base_query_copy = base_query;
892 base_query_copy.template condition<AttribBoundaries>(std::set<BoundaryID>({bnd_id}))
893 .queryInto(bcs);
894 mooseAssert(bcs.size() <= 1, "cannot have multiple dirichlet BCs on the same boundary");
895 if (!bcs.empty())
896 _boundary_id_to_dirichlet_bc.emplace(bnd_id, bcs[0]);
897 }
898
899 _dirichlet_map_setup = true;
900}
901
902template <typename OutputType>
903void
905{
906 mooseAssert(!Threads::in_threads,
907 "This routine has not been implemented for threads. Please query this routine before "
908 "a threaded region or contact a MOOSE developer to discuss.");
909
910 _boundary_id_to_flux_bc.clear();
911 std::vector<const FVFluxBC *> bcs;
912
913 // I believe because query() returns by value but condition returns by reference that binding to a
914 // const lvalue reference results in the query() getting destructed and us holding onto a dangling
915 // reference. I think that condition returned by value we would be able to bind to a const lvalue
916 // reference here. But as it is we'll bind to a regular lvalue
917 const auto base_query = this->_subproblem.getMooseApp()
918 .theWarehouse()
919 .query()
920 .template condition<AttribSystem>("FVFluxBC")
921 .template condition<AttribThread>(_tid)
922 .template condition<AttribVar>(_var_num)
923 .template condition<AttribSysNum>(this->_sys.number());
924
925 for (const auto bnd_id : this->_mesh.getBoundaryIDs())
926 {
927 auto base_query_copy = base_query;
928 base_query_copy.template condition<AttribBoundaries>(std::set<BoundaryID>({bnd_id}))
929 .queryInto(bcs);
930 if (!bcs.empty())
931 _boundary_id_to_flux_bc.emplace(bnd_id, bcs);
932 }
933
934 _flux_map_setup = true;
935}
936
937template <typename OutputType>
938void
940{
941 _element_data->sizeMatrixTagData();
942 _neighbor_data->sizeMatrixTagData();
943}
944
945template class MooseVariableFV<Real>;
946// TODO: implement vector fv variable support. This will require some template
947// specializations for various member functions in this and the FV variable
948// classes. And then you will need to uncomment out the line below:
949// 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:405
const Elem *const & neighbor() const
Return the neighbor element.
Definition Assembly.h:461
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 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.
void suppressParameter(const std::string &name)
This method suppresses an inherited parameter so that it isn't required or valid in the derived class...
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 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
virtual void setNodalValue(const OutputType &value) 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:65
@ 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.