https://mooseframework.inl.gov
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 
28 using namespace Moose;
29 
31 
32 template <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 
71 template <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")
106  }
107  else
109 }
110 
111 template <typename OutputType>
112 void
114 {
115  _element_data->clearDofIndices();
116 }
117 
118 template <typename OutputType>
120 MooseVariableFV<OutputType>::getElementalValue(const Elem * elem, unsigned int idx) const
121 {
122  return _element_data->getElementalValue(elem, Moose::Current, idx);
123 }
124 
125 template <typename OutputType>
127 MooseVariableFV<OutputType>::getElementalValueOld(const Elem * elem, unsigned int idx) const
128 {
129  return _element_data->getElementalValue(elem, Moose::Old, idx);
130 }
131 
132 template <typename OutputType>
134 MooseVariableFV<OutputType>::getElementalValueOlder(const Elem * elem, unsigned int idx) const
135 {
136  return _element_data->getElementalValue(elem, Moose::Older, idx);
137 }
138 
139 template <typename OutputType>
140 void
142 {
143  _element_data->insert(residual);
144 }
145 
146 template <typename OutputType>
147 void
149 {
150  lowerDError();
151 }
152 
153 template <typename OutputType>
154 void
156 {
157  _element_data->add(residual);
158 }
159 
160 template <typename OutputType>
163 {
164  return _element_data->dofValues();
165 }
166 
167 template <typename OutputType>
170 {
171  return _element_data->dofValuesOld();
172 }
173 
174 template <typename OutputType>
177 {
178  return _element_data->dofValuesOlder();
179 }
180 
181 template <typename OutputType>
184 {
185  return _element_data->dofValuesPreviousNL();
186 }
187 
188 template <typename OutputType>
191 {
192  return _neighbor_data->dofValues();
193 }
194 
195 template <typename OutputType>
198 {
199  return _neighbor_data->dofValuesOld();
200 }
201 
202 template <typename OutputType>
205 {
206  return _neighbor_data->dofValuesOlder();
207 }
208 
209 template <typename OutputType>
212 {
213  return _neighbor_data->dofValuesPreviousNL();
214 }
215 
216 template <typename OutputType>
219 {
220  return _element_data->dofValuesDot();
221 }
222 
223 template <typename OutputType>
226 {
227  return _element_data->dofValuesDotDot();
228 }
229 
230 template <typename OutputType>
233 {
234  return _element_data->dofValuesDotOld();
235 }
236 
237 template <typename OutputType>
240 {
241  return _element_data->dofValuesDotDotOld();
242 }
243 
244 template <typename OutputType>
247 {
248  return _neighbor_data->dofValuesDot();
249 }
250 
251 template <typename OutputType>
254 {
255  return _neighbor_data->dofValuesDotDot();
256 }
257 
258 template <typename OutputType>
261 {
262  return _neighbor_data->dofValuesDotOld();
263 }
264 
265 template <typename OutputType>
268 {
269  return _neighbor_data->dofValuesDotDotOld();
270 }
271 
272 template <typename OutputType>
273 const MooseArray<Number> &
275 {
276  return _element_data->dofValuesDuDotDu();
277 }
278 
279 template <typename OutputType>
280 const MooseArray<Number> &
282 {
283  return _element_data->dofValuesDuDotDotDu();
284 }
285 
286 template <typename OutputType>
287 const MooseArray<Number> &
289 {
290  return _neighbor_data->dofValuesDuDotDu();
291 }
292 
293 template <typename OutputType>
294 const MooseArray<Number> &
296 {
297  return _neighbor_data->dofValuesDuDotDotDu();
298 }
299 
300 template <typename OutputType>
301 void
303 {
304  _element_data->prepareIC();
305 }
306 
307 template <typename OutputType>
308 void
310 {
311  _element_data->setGeometry(Moose::Volume);
312  _element_data->computeValues();
313 }
314 
315 template <typename OutputType>
316 void
318 {
319  _element_data->setGeometry(Moose::Face);
320  _element_data->computeValues();
321 }
322 
323 template <typename OutputType>
324 void
326 {
327  _neighbor_data->setGeometry(Moose::Face);
328  _neighbor_data->computeValues();
329 }
330 
331 template <typename OutputType>
332 void
334 {
335  _neighbor_data->setGeometry(Moose::Volume);
336  _neighbor_data->computeValues();
337 }
338 
339 template <typename OutputType>
340 void
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()));
347  if (facetype == FaceInfo::VarFaceNeighbors::NEITHER)
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 
362 template <typename OutputType>
363 OutputType
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 
372 template <typename OutputType>
374 MooseVariableFV<OutputType>::getGradient(const Elem * /*elem*/) const
375 {
376  return {};
377 }
378 
379 template <typename OutputType>
380 void
381 MooseVariableFV<OutputType>::setNodalValue(const OutputType & /*value*/, unsigned int /*idx*/)
382 {
383  mooseError("FV variables do not support setNodalValue");
384 }
385 
386 template <typename OutputType>
387 void
388 MooseVariableFV<OutputType>::setDofValue(const OutputData & value, unsigned int index)
389 {
390  _element_data->setDofValue(value, index);
391 }
392 
393 template <typename OutputType>
394 void
395 MooseVariableFV<OutputType>::setDofValues(const DenseVector<OutputData> & values)
396 {
397  _element_data->setDofValues(values);
398 }
399 
400 template <typename OutputType>
401 void
402 MooseVariableFV<OutputType>::setLowerDofValues(const DenseVector<OutputData> &)
403 {
404  lowerDError();
405 }
406 
407 template <typename OutputType>
408 std::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};
415 
416  return {false, nullptr};
417 }
418 
419 template <typename OutputType>
420 std::pair<bool, std::vector<const FVFluxBC *>>
422 {
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};
426 
427  return std::make_pair(false, std::vector<const FVFluxBC *>());
428 }
429 
430 template <typename OutputType>
431 ADReal
432 MooseVariableFV<OutputType>::getElemValue(const Elem * const elem, const StateArg & state) const
433 {
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 
445  Moose::initDofIndices(const_cast<MooseVariableFV<OutputType> &>(*this), *elem);
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 
471 template <typename OutputType>
472 bool
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 
483 template <typename OutputType>
484 ADReal
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;
498 
499  return ADReal(bc.boundaryValue(fi, state));
500 }
501 
502 template <typename OutputType>
503 bool
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 
514 template <typename OutputType>
515 ADReal
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)
551  {
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 
564 template <typename OutputType>
565 ADReal
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 
582 template <typename OutputType>
583 const 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 
614 template <typename OutputType>
615 VectorValue<ADReal>
617  const StateArg & state,
618  const bool correct_skewness) const
619 {
620  const bool var_defined_on_elem = this->hasBlocks(fi.elem().subdomain_id());
621  const Elem * const elem_one = var_defined_on_elem ? &fi.elem() : fi.neighborPtr();
622  const Elem * const elem_two = var_defined_on_elem ? fi.neighborPtr() : &fi.elem();
623 
624  const VectorValue<ADReal> elem_one_grad = adGradSln(elem_one, state, correct_skewness);
625 
626  // If we have a neighbor then we interpolate between the two to the face. If we do not, then we
627  // apply a zero Hessian assumption and use the element centroid gradient as the uncorrected face
628  // gradient
629  if (elem_two && this->hasBlocks(elem_two->subdomain_id()))
630  {
631  const VectorValue<ADReal> & elem_two_grad = adGradSln(elem_two, state, correct_skewness);
632 
633  // Uncorrected gradient value
634  return Moose::FV::linearInterpolation(elem_one_grad, elem_two_grad, fi, var_defined_on_elem);
635  }
636  else
637  return elem_one_grad;
638 }
639 
640 template <typename OutputType>
641 VectorValue<ADReal>
643  const StateArg & state,
644  const bool correct_skewness) const
645 {
646  const bool var_defined_on_elem = this->hasBlocks(fi.elem().subdomain_id());
647  const Elem * const elem = &fi.elem();
648  const Elem * const neighbor = fi.neighborPtr();
649 
650  const bool is_internal_face = this->isInternalFace(fi);
651 
652  const ADReal side_one_value = (!is_internal_face && !var_defined_on_elem)
653  ? getBoundaryFaceValue(fi, state, correct_skewness)
654  : getElemValue(elem, state);
655  const ADReal side_two_value = (var_defined_on_elem && !is_internal_face)
656  ? getBoundaryFaceValue(fi, state, correct_skewness)
657  : getElemValue(neighbor, state);
658 
659  const auto delta =
660  this->isInternalFace(fi)
661  ? fi.dCNMag()
662  : (fi.faceCentroid() - (var_defined_on_elem ? fi.elemCentroid() : fi.neighborCentroid()))
663  .norm();
664 
665  // This is the component of the gradient which is parallel to the line connecting
666  // the cell centers. Therefore, we can use our second order, central difference
667  // scheme to approximate it.
668  auto face_grad = ((side_two_value - side_one_value) / delta) * fi.eCN();
669 
670  // We only need non-orthogonal correctors in 2+ dimensions
671  if (this->_mesh.dimension() > 1)
672  {
673  // We are using an orthogonal approach for the non-orthogonal correction, for more information
674  // see Hrvoje Jasak's PhD Thesis (Imperial College, 1996)
675  const auto & interpolated_gradient = uncorrectedAdGradSln(fi, state, correct_skewness);
676  face_grad += interpolated_gradient - (interpolated_gradient * fi.eCN()) * fi.eCN();
677  }
678 
679  return face_grad;
680 }
681 
682 template <typename OutputType>
683 void
685 {
686  if (!_dirichlet_map_setup)
687  determineBoundaryToDirichletBCMap();
688  if (!_flux_map_setup)
689  determineBoundaryToFluxBCMap();
690 
691  clearCaches();
692 }
693 
694 template <typename OutputType>
695 void
697 {
698  clearCaches();
699 }
700 
701 template <typename OutputType>
702 void
704 {
705  _elem_to_grad.clear();
706 }
707 
708 template <typename OutputType>
709 unsigned int
711 {
712  unsigned int state = 0;
713  state = std::max(state, _element_data->oldestSolutionStateRequested());
714  state = std::max(state, _neighbor_data->oldestSolutionStateRequested());
715  return state;
716 }
717 
718 template <typename OutputType>
719 void
721 {
722  _element_data->clearDofIndices();
723  _neighbor_data->clearDofIndices();
724 }
725 
726 template <typename OutputType>
728 MooseVariableFV<OutputType>::evaluate(const FaceArg & face, const StateArg & state) const
729 {
730  const FaceInfo * const fi = face.fi;
731  mooseAssert(fi, "The face information must be non-null");
732  if (isDirichletBoundaryFace(*fi, face.face_side, state))
733  return getDirichletBoundaryFaceValue(*fi, face.face_side, state);
734  else if (isExtrapolatedBoundaryFace(*fi, face.face_side, state))
735  {
736  bool two_term_boundary_expansion = _two_term_boundary_expansion;
738  if ((face.elem_is_upwind && face.face_side == fi->elemPtr()) ||
739  (!face.elem_is_upwind && face.face_side == fi->neighborPtr()))
740  two_term_boundary_expansion = false;
741  return getExtrapolatedBoundaryFaceValue(
742  *fi, two_term_boundary_expansion, face.correct_skewness, face.face_side, state);
743  }
744  else
745  {
746  mooseAssert(this->isInternalFace(*fi),
747  "We must be either Dirichlet, extrapolated, or internal");
748  return Moose::FV::interpolate(*this, face, state);
749  }
750 }
751 
752 template <typename OutputType>
754 MooseVariableFV<OutputType>::evaluate(const NodeArg & node_arg, const StateArg & state) const
755 {
756  const auto & node_to_elem_map = this->_mesh.nodeToElemMap();
757  const auto & elem_ids = libmesh_map_find(node_to_elem_map, node_arg.node->id());
758  ValueType sum = 0;
759  Real total_weight = 0;
760  mooseAssert(elem_ids.size(), "There should always be at least one element connected to a node");
761  for (const auto elem_id : elem_ids)
762  {
763  const Elem * const elem = this->_mesh.queryElemPtr(elem_id);
764  mooseAssert(elem, "We should have this element available");
765  if (!this->hasBlocks(elem->subdomain_id()))
766  continue;
767  const ElemPointArg elem_point{
768  elem, *node_arg.node, _face_interp_method == Moose::FV::InterpMethod::SkewCorrectedAverage};
769  const auto weight = 1 / (*node_arg.node - elem->vertex_average()).norm();
770  sum += weight * (*this)(elem_point, state);
771  total_weight += weight;
772  }
773  return sum / total_weight;
774 }
775 
776 template <typename OutputType>
779 {
780  mooseError("evaluateDot not implemented for this class of finite volume variables");
781 }
782 
783 template <>
784 ADReal
785 MooseVariableFV<Real>::evaluateDot(const ElemArg & elem_arg, const StateArg & state) const
786 {
787  const Elem * const elem = elem_arg.elem;
788  mooseAssert(state.state == 0,
789  "We dot not currently support any time derivative evaluations other than for the "
790  "current time-step");
791  mooseAssert(_time_integrator && _time_integrator->dt(),
792  "A time derivative is being requested but we do not have a time integrator so we'll "
793  "have no idea how to compute it");
794 
795  Moose::initDofIndices(const_cast<MooseVariableFV<Real> &>(*this), *elem);
796 
797  mooseAssert(
798  this->_dof_indices.size() == 1,
799  "There should only be one dof-index for a constant monomial variable on any given element");
800 
801  const dof_id_type dof_index = this->_dof_indices[0];
802 
804  {
805  ADReal dot = (*_solution)(dof_index);
806  if (ADReal::do_derivatives && state.state == 0 &&
808  Moose::derivInsert(dot.derivatives(), dof_index, 1.);
810  return dot;
811  }
812  else
813  return (*_sys.solutionUDot())(dof_index);
814 }
815 
816 template <>
817 ADReal
818 MooseVariableFV<Real>::evaluateDot(const FaceArg & face, const StateArg & state) const
819 {
820  const FaceInfo * const fi = face.fi;
821  mooseAssert(fi, "The face information must be non-null");
822  if (isDirichletBoundaryFace(*fi, face.face_side, state))
823  return ADReal(0.0); // No time derivative if boundary value is set
824  else if (isExtrapolatedBoundaryFace(*fi, face.face_side, state))
825  {
826  mooseAssert(face.face_side && this->hasBlocks(face.face_side->subdomain_id()),
827  "If we are an extrapolated boundary face, then our FunctorBase::checkFace method "
828  "should have assigned a non-null element that we are defined on");
829  const auto elem_arg = ElemArg({face.face_side, face.correct_skewness});
830  // For extrapolated boundary faces, note that we take the value of the time derivative at the
831  // cell in contact with the face
832  return evaluateDot(elem_arg, state);
833  }
834  else
835  {
836  mooseAssert(this->isInternalFace(*fi),
837  "We must be either Dirichlet, extrapolated, or internal");
838  return Moose::FV::interpolate<ADReal, FunctorEvaluationKind::Dot>(*this, face, state);
839  }
840 }
841 
842 template <>
843 ADReal
844 MooseVariableFV<Real>::evaluateDot(const ElemQpArg & elem_qp, const StateArg & state) const
845 {
846  return evaluateDot(ElemArg({elem_qp.elem, /*correct_skewness*/ false}), state);
847 }
848 
849 template <typename OutputType>
850 void
852 {
853  _element_data->prepareAux();
854  _neighbor_data->prepareAux();
855 }
856 
857 template <typename OutputType>
858 void
860 {
861  mooseAssert(!Threads::in_threads,
862  "This routine has not been implemented for threads. Please query this routine before "
863  "a threaded region or contact a MOOSE developer to discuss.");
864 
865  _boundary_id_to_dirichlet_bc.clear();
866  std::vector<FVDirichletBCBase *> bcs;
867 
868  // I believe because query() returns by value but condition returns by reference that binding to a
869  // const lvalue reference results in the query() getting destructed and us holding onto a dangling
870  // reference. I think that condition returned by value we would be able to bind to a const lvalue
871  // reference here. But as it is we'll bind to a regular lvalue
872  const auto base_query = this->_subproblem.getMooseApp()
873  .theWarehouse()
874  .query()
875  .template condition<AttribSystem>("FVDirichletBC")
876  .template condition<AttribThread>(_tid)
877  .template condition<AttribVar>(_var_num)
878  .template condition<AttribSysNum>(this->_sys.number());
879 
880  for (const auto bnd_id : this->_mesh.getBoundaryIDs())
881  {
882  auto base_query_copy = base_query;
883  base_query_copy.template condition<AttribBoundaries>(std::set<BoundaryID>({bnd_id}))
884  .queryInto(bcs);
885  mooseAssert(bcs.size() <= 1, "cannot have multiple dirichlet BCs on the same boundary");
886  if (!bcs.empty())
887  _boundary_id_to_dirichlet_bc.emplace(bnd_id, bcs[0]);
888  }
889 
890  _dirichlet_map_setup = true;
891 }
892 
893 template <typename OutputType>
894 void
896 {
897  mooseAssert(!Threads::in_threads,
898  "This routine has not been implemented for threads. Please query this routine before "
899  "a threaded region or contact a MOOSE developer to discuss.");
900 
901  _boundary_id_to_flux_bc.clear();
902  std::vector<const FVFluxBC *> bcs;
903 
904  // I believe because query() returns by value but condition returns by reference that binding to a
905  // const lvalue reference results in the query() getting destructed and us holding onto a dangling
906  // reference. I think that condition returned by value we would be able to bind to a const lvalue
907  // reference here. But as it is we'll bind to a regular lvalue
908  const auto base_query = this->_subproblem.getMooseApp()
909  .theWarehouse()
910  .query()
911  .template condition<AttribSystem>("FVFluxBC")
912  .template condition<AttribThread>(_tid)
913  .template condition<AttribVar>(_var_num)
914  .template condition<AttribSysNum>(this->_sys.number());
915 
916  for (const auto bnd_id : this->_mesh.getBoundaryIDs())
917  {
918  auto base_query_copy = base_query;
919  base_query_copy.template condition<AttribBoundaries>(std::set<BoundaryID>({bnd_id}))
920  .queryInto(bcs);
921  if (!bcs.empty())
922  _boundary_id_to_flux_bc.emplace(bnd_id, bcs);
923  }
924 
925  _flux_map_setup = true;
926 }
927 
928 template <typename OutputType>
929 void
931 {
932  _element_data->sizeMatrixTagData();
933  _neighbor_data->sizeMatrixTagData();
934 }
935 
936 template class MooseVariableFV<Real>;
937 // TODO: implement vector fv variable support. This will require some template
938 // specializations for various member functions in this and the FV variable
939 // classes. And then you will need to uncomment out the line below:
940 // template class MooseVariableFV<RealVectorValue>;
void initDofIndices(T &data, const Elem &elem)
const Elem *const & elem() const
Return the current element.
Definition: Assembly.h:375
Moose::FV::InterpMethod _face_interp_method
Decides if an average or skewed corrected average is used for the face interpolation.
gc*elem+(1-gc)*neighbor
const DoFValue & dofValues() const override
dof values getters
const DoFValue & dofValuesPreviousNLNeighbor() const override
void determineBoundaryToFluxBCMap()
Setup the boundary to Flux BC map.
const std::set< BoundaryID > & boundaryIDs() const
Const getter for every associated boundary ID.
Definition: FaceInfo.h:120
virtual void computeNeighborValues() override
Compute values at quadrature points for the neighbor.
const DoFValue & dofValuesOld() const override
virtual void prepareAux() override final
void clearDofIndices() override
Clear out the dof indices.
Class for stuff related to variables.
ADReal _ad_real_dummy
A dummy ADReal variable.
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:333
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.
const libMesh::Elem * face_side
A member that can be used to indicate whether there is a sidedness to this face.
virtual unsigned int currentNlSysNum() const =0
std::unique_ptr< MooseVariableDataFV< OutputType > > _neighbor_data
Holder for all the data associated with the neighbor element.
const MooseArray< libMesh::Number > & dofValuesDuDotDu() const override
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
const Elem & elem() const
Definition: FaceInfo.h:81
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.
void determineBoundaryToDirichletBCMap()
Setup the boundary to Dirichlet BC map.
const Point & faceCentroid() const
Returns the coordinates of the face centroid.
Definition: FaceInfo.h:71
T & set(const std::string &name, bool quiet_mode=false)
Returns a writable reference to the named parameters.
Base class for finite volume Dirichlet boundaray conditions.
bool correct_skewness
Whether to perform skew correction.
Moose::ElemArg ElemArg
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
virtual void sizeMatrixTagData() override
Size data structures related to matrix tagging.
OutputTools< OutputType >::OutputGradient getGradient(const Elem *elem) const
Compute the variable gradient value at a point on an element.
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...
ValueType evaluate(const ElemArg &elem, const StateArg &) const override final
Evaluate the functor with a given element.
const DoFValue & dofValuesDotDotOld() const override
const Point & neighborCentroid() const
Definition: FaceInfo.h:243
A structure that is used to evaluate Moose functors at an arbitrary physical point contained within a...
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.
virtual void add(libMesh::NumericVector< libMesh::Number > &vector) override
Add the currently cached degree of freedom values into the provided vector.
virtual void prepareIC() override
Prepare the initial condition.
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.
Definition: MathFVUtils.h:150
const DoFValue & dofValuesDotOld() const override
DualNumber< Real, DNDerivativeType, true > ADReal
Definition: ADRealForward.h:46
const libMesh::Node * node
The node which defines our location in space.
std::pair< bool, std::vector< const FVFluxBC * > > getFluxBCs(const FaceInfo &fi) const
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...
THREAD_ID _tid
Thread ID.
auto max(const L &left, const R &right)
std::vector< dof_id_type > _dof_indices
DOF indices.
Moose::DOFType< Real >::type OutputData
const DoFValue & dofValuesDotDot() 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.
static InputParameters validParams()
OutputData getElementalValueOld(const Elem *elem, unsigned int idx=0) const
Get the old value of this variable on an element.
bool isInternalFace(const FaceInfo &) const
Returns true if the face is an internal face.
Definition: MooseFunctor.h:569
This data structure is used to store geometric and variable related metadata about each cell face in ...
Definition: FaceInfo.h:36
std::pair< bool, const FVDirichletBCBase * > getDirichletBC(const FaceInfo &fi) const
MooseVariableFV(const InputParameters &parameters)
void libmesh_ignore(const Args &...)
CONSTANT
OutputType getValue(const Elem *elem) const
Note: const monomial is always the case - higher order solns are reconstructed - so this is simpler f...
const MooseArray< libMesh::Number > & dofValuesDuDotDotDu() const override
const MooseArray< libMesh::Number > & dofValuesDuDotDuNeighbor() const override
void clearCaches()
clear finite volume caches
const Elem * neighborPtr() const
Definition: FaceInfo.h:84
const Point & elemCentroid() const
Returns the element centroids of the elements on the elem and neighbor sides of the face...
Definition: FaceInfo.h:95
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.
dof_id_type id() const
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
std::unique_ptr< MooseVariableDataFV< OutputType > > _element_data
Holder for all the data associated with the "main" element.
SubProblem & _subproblem
Problem this variable is part of.
A structure defining a "face" evaluation calling argument for Moose functors.
dof_id_type weight(const MeshBase &mesh, const processor_id_type pid)
const FaceInfo * fi
a face information object which defines our location in space
virtual void computeADTimeDerivatives(ADReal &ad_u_dot, const dof_id_type &dof, ADReal &ad_u_dot_dot) const =0
method for computing local automatic differentiation time derivatives
const Real & dt() const
Returns the time step size.
const DoFValue & dofValuesDotNeighbor() const override
SystemBase & _sys
System this variable is part of.
SolutionIterationType iteration_type
The solution iteration type, e.g. time or nonlinear.
virtual NumericVector< Number > * solutionUDot()
Definition: SystemBase.h:261
typename MooseVariableField< OutputType >::OutputData OutputData
const DoFValue & dofValuesOlderNeighbor() const override
registerMooseObject("MooseApp", MooseVariableFVReal)
const libMesh::Elem * elem
virtual void jacobianSetup() override
const MooseArray< libMesh::Number > & dofValuesDuDotDotDuNeighbor() const override
virtual void setLowerDofValues(const DenseVector< OutputData > &values) override
Set local DOF values for a lower dimensional element and evaluate the values on quadrature points...
const DoFValue & dofValuesPreviousNL() const override
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition: MooseEnum.h:33
virtual void computeFaceValues(const FaceInfo &fi) override
Initializes/computes variable values from the solution vectors for the face represented by fi...
bool isExtrapolatedBoundaryFace(const FaceInfo &fi, const Elem *elem, const Moose::StateArg &state) const override
Returns whether this is an extrapolated boundary face.
Moose::FV::LimiterType limiter_type
a limiter which defines how the functor evaluated on either side of the face should be interpolated t...
void clearAllDofIndices() final
A structure that is used to evaluate Moose functors logically at an element/cell center.
Moose::VarKindType _var_kind
Variable type (see MooseTypes.h)
typename MooseVariableField< OutputType >::DoFValue DoFValue
Argument for requesting functor evaluation at a quadrature point location in an element.
const DoFValue & dofValuesOldNeighbor() const override
unsigned int number() const
Gets the number of this system.
Definition: SystemBase.C:1149
virtual void setDofValue(const OutputData &value, unsigned int index) override
Degree of freedom value setters.
auto norm(const T &a) -> decltype(std::abs(a))
std::string stringify(const T &t)
conversion to string
Definition: Conversion.h:64
Real dCNMag() const
Definition: FaceInfo.h:144
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.
dof_id_type total_weight(const MeshBase &mesh)
MONOMIAL
const Elem * elemPtr() const
Definition: FaceInfo.h:82
virtual ADReal boundaryValue(const FaceInfo &fi, const Moose::StateArg &state) const =0
const DoFValue & dofValuesDotOldNeighbor() const override
const DoFValue & dofValuesOlder() const override
(gc*elem+(1-gc)*neighbor)+gradient*(rf-rf&#39;)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const DoFValue & dofValuesDotDotOldNeighbor() const override
DotType dot(const ElemArg &elem, const StateArg &state) const
Same as their evaluateDot overloads with the same arguments but allows for caching implementation...
Definition: MooseFunctor.h:890
const Point & eCN() const
Definition: FaceInfo.h:151
subdomain_id_type subdomain_id() const
virtual void setNodalValue(const OutputType &value, unsigned int idx=0) override
Assembly & _assembly
Assembly data.
virtual void insert(libMesh::NumericVector< libMesh::Number > &vector) override
Insert the currently cached degree of freedom values into the provided vector.
const DoFValue & dofValuesNeighbor() const override
ADReal getBoundaryFaceValue(const FaceInfo &fi, const StateArg &state, bool correct_skewness=false) const
Retrieve the solution value at a boundary face.
const Elem *const & neighbor() const
Return the neighbor element.
Definition: Assembly.h:431
const TimeIntegrator *const _time_integrator
the time integrator used for computing time derivatives
static InputParameters validParams()
virtual ADReal getDirichletBoundaryFaceValue(const FaceInfo &fi, const Elem *elem, const Moose::StateArg &state) const
Retrieves a Dirichlet boundary value for the provided face.
State argument for evaluating functors.
void derivInsert(SemiDynamicSparseNumberArray< Real, libMesh::dof_id_type, NWrapper< N >> &derivs, libMesh::dof_id_type index, Real value)
Definition: ADReal.h:21
virtual const OutputTools< T >::VariableSecond & second()
The second derivative of the variable this object is operating on.
virtual void computeElemValues() override
Initializes/computes variable values from the solution vectors for the current element being operated...
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Definition: MooseBase.h:195
OutputData getElementalValue(const Elem *elem, unsigned int idx=0) const
Get the current value of this variable on an element.
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
virtual void residualSetup() override
virtual void setDofValues(const DenseVector< OutputData > &values) override
Set local DOF values and evaluate the values on quadrature points.
bool elem_is_upwind
a boolean which states whether the face information element is upwind of the face ...
virtual void computeElemValuesFace() override
Compute values at facial quadrature points.
OutputData getElementalValueOlder(const Elem *elem, unsigned int idx=0) const
Get the older value of this variable on an element.
const DoFValue & dofValuesDot() const override
const libMesh::Elem * elem
The element.
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...
Definition: MathFVUtils.h:282
virtual void computeNeighborValuesFace() override
Compute values at facial quadrature points for the neighbor.
DotType evaluateDot(const ElemArg &elem, const StateArg &) const override final
Evaluate the functor time derivative with a given element.
unsigned int oldestSolutionStateRequested() const override final
The oldest solution state that is requested for this variable (0 = current, 1 = old, 2 = older, etc).
Moose::ShapeType< Real >::type OutputShape
unsigned int state
The state.
unsigned int idx(const ElemType type, const unsigned int nx, const unsigned int i, const unsigned int j)
uint8_t dof_id_type
const DoFValue & dofValuesDotDotNeighbor() const override
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:225
const ADTemplateVariableGradient< OutputType > & adGradSln() const override
AD grad solution getter.