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 : }