LCOV - code coverage report
Current view: top level - include/utils - FVUtils.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 30 30 100.0 %
Date: 2025-07-17 01:28:37 Functions: 6 7 85.7 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #pragma once
      11             : 
      12             : #include "MooseMesh.h"
      13             : #include "MooseError.h"
      14             : #include "MooseMeshUtils.h"
      15             : #include "FaceInfo.h"
      16             : #include "libmesh/elem.h"
      17             : 
      18             : #include <tuple>
      19             : 
      20             : template <typename>
      21             : class MooseVariableFV;
      22             : 
      23             : template <typename>
      24             : class MooseLinearVariableFV;
      25             : 
      26             : namespace Moose
      27             : {
      28             : namespace FV
      29             : {
      30             : 
      31             : /**
      32             :  * This function infers based on elements if the faceinfo between them
      33             :  * belongs to the element or not.
      34             :  * @param elem Reference to an element
      35             :  * @param neighbor Pointer to the neighbor of the element
      36             :  * @return If the element (first argument) is the owner of the faceinfo between the two elements
      37             :  */
      38             : bool elemHasFaceInfo(const Elem & elem, const Elem * const neighbor);
      39             : 
      40             : template <typename ActionFunctor>
      41             : void
      42    21011348 : loopOverElemFaceInfo(const Elem & elem,
      43             :                      const MooseMesh & mesh,
      44             :                      ActionFunctor & act,
      45             :                      const Moose::CoordinateSystemType coord_type,
      46             :                      const unsigned int rz_radial_coord = libMesh::invalid_uint)
      47             : {
      48             :   mooseAssert(elem.active(), "We should never call this method with an inactive element");
      49             : 
      50    98840612 :   for (const auto side : elem.side_index_range())
      51             :   {
      52    77829264 :     const Elem * const candidate_neighbor = elem.neighbor_ptr(side);
      53             : 
      54    77829264 :     bool elem_has_info = elemHasFaceInfo(elem, candidate_neighbor);
      55             : 
      56    77829264 :     std::set<const Elem *> neighbors;
      57             : 
      58    77829264 :     const bool inactive_neighbor_detected =
      59    77829264 :         candidate_neighbor ? !candidate_neighbor->active() : false;
      60             : 
      61             :     // See MooseMesh::buildFaceInfo for corresponding checks/additions of FaceInfo
      62    77829264 :     if (inactive_neighbor_detected)
      63             :     {
      64             :       // We must be next to an element that has been refined
      65             :       mooseAssert(candidate_neighbor->has_children(), "We should have children");
      66             : 
      67        9917 :       const auto candidate_neighbor_side = candidate_neighbor->which_neighbor_am_i(&elem);
      68             : 
      69       48843 :       for (const auto child_num : make_range(candidate_neighbor->n_children()))
      70       38926 :         if (candidate_neighbor->is_child_on_side(child_num, candidate_neighbor_side))
      71             :         {
      72       19463 :           const Elem * const child = candidate_neighbor->child_ptr(child_num);
      73             :           mooseAssert(child->level() - elem.level() == 1, "The math doesn't work out here.");
      74             :           mooseAssert(child->has_neighbor(&elem), "Elem should be a neighbor of this child.");
      75             :           mooseAssert(child->active(),
      76             :                       "We shouldn't have greater than a face mismatch level of one");
      77       19463 :           neighbors.insert(child);
      78             :         }
      79             :     }
      80             :     else
      81    77819347 :       neighbors.insert(candidate_neighbor);
      82             : 
      83   155668074 :     for (const Elem * const neighbor : neighbors)
      84             :     {
      85    77838810 :       const FaceInfo * const fi =
      86    77838810 :           elem_has_info ? mesh.faceInfo(&elem, side)
      87    36587419 :                         : mesh.faceInfo(neighbor, neighbor->which_neighbor_am_i(&elem));
      88             : 
      89             :       mooseAssert(fi, "We should have found a FaceInfo");
      90             :       mooseAssert(elem_has_info ? &elem == &fi->elem() : &elem == fi->neighborPtr(),
      91             :                   "Doesn't seem like we understand how this FaceInfo thing is working");
      92             :       if (neighbor)
      93             :       {
      94             :         mooseAssert(neighbor != libMesh::remote_elem,
      95             :                     "Remote element detected. This indicates that you have insufficient geometric "
      96             :                     "ghosting. Please contact your application developers.");
      97             :         mooseAssert(elem_has_info ? neighbor == fi->neighborPtr() : neighbor == &fi->elem(),
      98             :                     "Doesn't seem like we understand how this FaceInfo thing is working");
      99             :       }
     100             : 
     101    77838810 :       const Point elem_normal = elem_has_info ? fi->normal() : Point(-fi->normal());
     102             : 
     103             :       Real coord;
     104    77838810 :       MooseMeshUtils::coordTransformFactor(fi->faceCentroid(), coord, coord_type, rz_radial_coord);
     105             : 
     106    77838810 :       const Point surface_vector = elem_normal * fi->faceArea() * coord;
     107             : 
     108    77838810 :       act(elem, neighbor, fi, surface_vector, coord, elem_has_info);
     109             :     }
     110             :   }
     111    21011348 : }
     112             : 
     113             : /**
     114             :  * This utility determines element one and element two given a \p FaceInfo \p fi and variable \p
     115             :  * var. You may ask what in the world "element one" and "element two" means, and that would be a
     116             :  * very good question. What it means is: a variable will *always* have degrees of freedom on
     117             :  * element one. A variable may or may not have degrees of freedom on element two. So we are
     118             :  * introducing a second terminology here. FaceInfo geometric objects have element-neighbor pairs.
     119             :  * These element-neighbor pairs are purely geometric and have no relation to the algebraic system
     120             :  * of variables. The elem1-elem2 notation introduced here is based on dof/algebraic information
     121             :  * and may very well be different from variable to variable, e.g. elem1 may correspond to the
     122             :  * FaceInfo elem for one variable (and correspondingly elem2 will be the FaceInfo neighbor), but
     123             :  * elem1 may correspond to the FaceInfo neighbor for another variable (and correspondingly for
     124             :  * *that* variable elem2 will be the FaceInfo elem).
     125             :  * @return A tuple, where the first item is elem1, the second item is elem2, and the third item is
     126             :  * a boolean indicating whether elem1 corresponds to the FaceInfo elem
     127             :  */
     128             : template <typename FVVar>
     129             : std::tuple<const Elem *, const Elem *, bool>
     130        4118 : determineElemOneAndTwo(const FaceInfo & fi, const FVVar & var)
     131             : {
     132        4118 :   auto ft = fi.faceType(std::make_pair(var.number(), var.sys().number()));
     133             :   mooseAssert(ft == FaceInfo::VarFaceNeighbors::BOTH
     134             :                   ? var.hasBlocks(fi.elem().subdomain_id()) && fi.neighborPtr() &&
     135             :                         var.hasBlocks(fi.neighborPtr()->subdomain_id())
     136             :                   : true,
     137             :               "Finite volume variable " << var.name()
     138             :                                         << " does not exist on both sides of the face despite "
     139             :                                            "what the FaceInfo is telling us.");
     140             :   mooseAssert(ft == FaceInfo::VarFaceNeighbors::ELEM
     141             :                   ? var.hasBlocks(fi.elem().subdomain_id()) &&
     142             :                         (!fi.neighborPtr() || !var.hasBlocks(fi.neighborPtr()->subdomain_id()))
     143             :                   : true,
     144             :               "Finite volume variable " << var.name()
     145             :                                         << " does not exist on or only on the elem side of the "
     146             :                                            "face despite what the FaceInfo is telling us.");
     147             :   mooseAssert(ft == FaceInfo::VarFaceNeighbors::NEIGHBOR
     148             :                   ? fi.neighborPtr() && var.hasBlocks(fi.neighborPtr()->subdomain_id()) &&
     149             :                         !var.hasBlocks(fi.elem().subdomain_id())
     150             :                   : true,
     151             :               "Finite volume variable " << var.name()
     152             :                                         << " does not exist on or only on the neighbor side of the "
     153             :                                            "face despite what the FaceInfo is telling us.");
     154             : 
     155        4118 :   const bool one_is_elem =
     156        4118 :       ft == FaceInfo::VarFaceNeighbors::BOTH || ft == FaceInfo::VarFaceNeighbors::ELEM;
     157        4118 :   const Elem * const elem_one = one_is_elem ? &fi.elem() : fi.neighborPtr();
     158             :   mooseAssert(elem_one, "This elem should be non-null!");
     159        4118 :   const Elem * const elem_two = one_is_elem ? fi.neighborPtr() : &fi.elem();
     160             : 
     161        8236 :   return std::make_tuple(elem_one, elem_two, one_is_elem);
     162             : }
     163             : }
     164             : }

Generated by: LCOV version 1.14