https://mooseframework.inl.gov
Loading...
Searching...
No Matches
Classes | Functions
SBMUtils Namespace Reference

Classes

struct  ClassificationSubdomains
 The subdomain IDs a (possibly partial) element can be labeled with. More...
 
struct  ElementDomainOccupancy
 Results of testing an element against a domain. More...
 
struct  InterceptedSubdomainPolicy
 Policy for assigning partial elements to a dedicated intercepted subdomain. More...
 
struct  SubdomainOccupancy
 A candidate subdomain and its occupancy of an element. More...
 

Functions

libMesh::Point distanceFrom (const SurfaceElement &surface_elem, const libMesh::Point &pt)
 Returns the vector from pt to the nearest point on the surface element: the normal projection if it falls inside the element, otherwise the nearest edge or vertex.
 
bool checkWatertightnessFromRawElems (const std::vector< const Elem * > &bd_elements)
 
Real activeElementFraction (const Elem &elem, Order qrule_order, const std::function< bool(const libMesh::Point &)> &is_active)
 Compute the fraction of an element's quadrature-weighted measure satisfying a predicate.
 
bool isInactive (Real active_fraction, Real lambda)
 Return whether a partial element is inactive, i.e.
 
ElementDomainOccupancy elementDomainOccupancy (const Elem &elem, Order qrule_order, const std::function< bool(const libMesh::Point &)> &is_in_domain)
 Test an element against the domain defined by is_in_domain.
 
ElementDomainOccupancy elementDomainOccupancy (const Elem &elem, Order qrule_order, const std::function< bool(const libMesh::Point &)> &is_in_domain, const std::function< bool(const libMesh::Point &)> &is_outside_domain)
 As above, but use is_outside_domain to test nodes separately.
 
std::optional< SubdomainID > selectSubdomainFromOccupancies (const std::vector< SubdomainOccupancy > &candidate_occupancies, const InterceptedSubdomainPolicy &intercepted_policy, Real lambda)
 Select a subdomain based on how multiple candidate domains occupy an element.
 
SubdomainID classifySubdomainFromOccupancy (const ElementDomainOccupancy &occupancy, const ClassificationSubdomains &subdomain_id_settings, bool mark_intercepted, Real lambda)
 Classify an element from its retained-domain occupancy measurements.
 
std::vector< const Function * > buildDistanceFunctions (const std::vector< FunctionName > &function_names, const FunctionInterface &function_provider)
 Build a list of distance functions based on names specified in input.
 
RealVectorValue distanceVectorFromFunction (const Function *func, const libMesh::Point &pt, Real t)
 Compute the distance vector induced by a distance function.
 
RealVectorValue trueNormalFromFunction (const Function *func, const libMesh::Point &pt, Real t)
 Compute the true boundary surface normal at the point on the boundary closest to pt.
 
RealVectorValue closestDistanceVector (const std::vector< const Function * > &funcs, const libMesh::Point &pt, Real t)
 Scan all distance functions and return the closest distance vector.
 
RealVectorValue closestTrueNormalVector (const std::vector< const Function * > &funcs, const libMesh::Point &pt, Real t)
 Scan all distance functions and return the corresponding normal vector.
 
Real unionSignedDistance (const std::vector< const Function * > &funcs, Real t, const Point &p)
 Computes the union signed distance by taking the minimum of all signed distance functions.
 
Point distanceFrom (const SurfaceElement &surface_elem, const Point &pt)
 

Function Documentation

◆ activeElementFraction()

Real SBMUtils::activeElementFraction ( const Elem &  elem,
Order  qrule_order,
const std::function< bool(const libMesh::Point &)> &  is_active 
)

Compute the fraction of an element's quadrature-weighted measure satisfying a predicate.

Definition at line 26 of file SBMUtils.C.

29{
30 const FEType fe_type(elem.default_order(), LAGRANGE);
31 auto fe = FEBase::build(elem.dim(), fe_type);
32 QGauss qrule(elem.dim(), qrule_order);
33 const auto & q_points = fe->get_xyz();
34 const auto & JxW = fe->get_JxW();
35 fe->attach_quadrature_rule(&qrule);
36 fe->reinit(&elem);
37
38 Real active_measure = 0.0;
39 Real total_measure = 0.0;
40 for (const auto i : index_range(q_points))
41 {
42 if (is_active(q_points[i]))
43 active_measure += JxW[i];
44 total_measure += JxW[i];
45 }
46
47 return active_measure / total_measure;
48}

Referenced by elementDomainOccupancy(), and TEST().

◆ buildDistanceFunctions()

std::vector< const Function * > SBMUtils::buildDistanceFunctions ( const std::vector< FunctionName > &  function_names,
const FunctionInterface &  function_provider 
)

Build a list of distance functions based on names specified in input.

Definition at line 172 of file SBMUtils.C.

174{
175 std::vector<const Function *> funcs;
176 funcs.reserve(function_names.size());
177
178 for (const auto & name : function_names)
179 {
180 const Function * func = &function_provider.getFunctionByName(name);
181 if (!dynamic_cast<const MooseParsedFunction *>(func) &&
182 !dynamic_cast<const UnsignedDistanceToSurfaceMesh *>(func) &&
183 !dynamic_cast<const SignedDistanceToSurfaceMesh *>(func))
184 {
185 mooseError("SBM distance helpers only support ParsedFunction, "
186 "UnsignedDistanceToSurfaceMesh, or SignedDistanceToSurfaceMesh types. Offending "
187 "function: ",
188 name);
189 }
190 funcs.emplace_back(func);
191 }
192
193 return funcs;
194}
void mooseError(Args &&... args)
const std::string name
Definition Setup.h:21
const Function & getFunctionByName(const FunctionName &name) const
Computes the signed distance to a surface mesh using k-d tree nearest neighbor lookup from SBMSurface...
Computes the unsigned distance to a surface mesh using geometry supplied by SBMSurfaceMeshBuilder or ...

Referenced by BoundaryShortestDistanceToSurface::BoundaryShortestDistanceToSurface(), and ShortestDistanceToSurface::ShortestDistanceToSurface().

◆ checkWatertightnessFromRawElems()

bool SBMUtils::checkWatertightnessFromRawElems ( const std::vector< const Elem * > &  bd_elements)

Definition at line 161 of file SBMUtils.C.

162{
163 for (const auto * el : bd_elements)
164 for (unsigned int s = 0; s < el->n_sides(); ++s)
165 if (!el->neighbor_ptr(s))
166 return false;
167
168 return true;
169}
for(PetscInt i=0;i< nvars;++i)
void ErrorVector unsigned int

◆ classifySubdomainFromOccupancy()

SubdomainID SBMUtils::classifySubdomainFromOccupancy ( const ElementDomainOccupancy &  occupancy,
const ClassificationSubdomains &  subdomain_id_settings,
bool  mark_intercepted,
Real  lambda 
)

Classify an element from its retained-domain occupancy measurements.

An element whose nodes and measure are entirely in the domain is inside; one whose nodes and measure are entirely outside the domain is outside. A remaining (partial) element is assigned the intercepted subdomain when mark_intercepted is true, and otherwise is resolved by the lambda threshold (see isInactive).

Definition at line 138 of file SBMUtils.C.

142{
143 // Same-side nodes do not rule out a surface crossing the element or enclosing a region
144 // within it. Quadrature sampling detects most such cases, but may miss very small regions.
145 // Exact endpoint comparisons are intentional: activeElementFraction returns exactly zero
146 // or one when no or all quadrature points are in the retained domain, respectively.
147 if (occupancy.all_nodes_in_domain && occupancy.fraction_of_element_in_domain == 1.0)
148 return subdomain_id_settings.inside;
149
150 if (occupancy.all_nodes_outside_domain && occupancy.fraction_of_element_in_domain == 0.0)
151 return subdomain_id_settings.outside;
152
153 if (mark_intercepted)
154 return subdomain_id_settings.intercepted;
155
156 return isInactive(occupancy.fraction_of_element_in_domain, lambda) ? subdomain_id_settings.outside
157 : subdomain_id_settings.inside;
158}
bool isInactive(Real active_fraction, Real lambda)
Return whether a partial element is inactive, i.e.
Definition SBMUtils.C:81
bool all_nodes_in_domain
Whether all element nodes lie in the retained domain.
Definition SBMUtils.h:47
bool all_nodes_outside_domain
Whether all element nodes lie outside the retained domain.
Definition SBMUtils.h:49
Real fraction_of_element_in_domain
Quadrature-based estimate of the fraction of this element inside the domain.
Definition SBMUtils.h:51

Referenced by InterceptedElementModifier::computeSubdomainID(), and SubdomainInterceptedGenerator::generate().

◆ closestDistanceVector()

RealVectorValue SBMUtils::closestDistanceVector ( const std::vector< const Function * > &  funcs,
const libMesh::Point &  pt,
Real  t 
)

Scan all distance functions and return the closest distance vector.

Definition at line 240 of file SBMUtils.C.

243{
244 Real min_dist = std::numeric_limits<Real>::max();
245 RealVectorValue closest_dist_vec;
246
247 for (const auto & func : funcs)
248 {
249 const auto dist_vec = distanceVectorFromFunction(func, pt, t);
250 const auto dist = dist_vec.norm();
251 if (dist < min_dist)
252 {
253 min_dist = dist;
254 closest_dist_vec = dist_vec;
255 }
256 }
257
258 return closest_dist_vec;
259}
RealVectorValue distanceVectorFromFunction(const Function *func, const libMesh::Point &pt, Real t)
Compute the distance vector induced by a distance function.
Definition SBMUtils.C:197

Referenced by ShortestDistanceToSurface::distanceVector(), and TEST_F().

◆ closestTrueNormalVector()

RealVectorValue SBMUtils::closestTrueNormalVector ( const std::vector< const Function * > &  funcs,
const libMesh::Point &  pt,
Real  t 
)

Scan all distance functions and return the corresponding normal vector.

Definition at line 262 of file SBMUtils.C.

265{
266 Real min_dist = std::numeric_limits<Real>::max();
267 RealVectorValue closest_normal_vec;
268
269 for (const auto & func : funcs)
270 {
271 const auto dist_vec = distanceVectorFromFunction(func, pt, t);
272 const auto dist = dist_vec.norm();
273 if (dist < min_dist)
274 {
275 min_dist = dist;
276 closest_normal_vec = trueNormalFromFunction(func, pt, t);
277 }
278 }
279
280 return closest_normal_vec;
281}
RealVectorValue trueNormalFromFunction(const Function *func, const libMesh::Point &pt, Real t)
Compute the true boundary surface normal at the point on the boundary closest to pt.
Definition SBMUtils.C:217

Referenced by TEST_F(), and ShortestDistanceToSurface::trueNormal().

◆ distanceFrom() [1/2]

libMesh::Point SBMUtils::distanceFrom ( const SurfaceElement &  surface_elem,
const libMesh::Point &  pt 
)

Returns the vector from pt to the nearest point on the surface element: the normal projection if it falls inside the element, otherwise the nearest edge or vertex.

Precondition (mooseAssert in debug builds): the element's sides are EDGE2 or NODEELEM (the only side types this routine handles).

Referenced by UnsignedDistanceToSurfaceMesh::distanceVectorToSurface(), SBMInterfaceManager::queryInterface(), TEST(), TEST(), TEST(), TEST(), and TEST().

◆ distanceFrom() [2/2]

Point SBMUtils::distanceFrom ( const SurfaceElement &  surface_elem,
const Point &  pt 
)

Definition at line 23 of file SBMSurfaceDistance.C.

24{
25 const Elem & element = surface_elem.elem();
26 const Point & normal = surface_elem.normal();
27
28 // Precondition: this routine only handles EDGE2 and NODEELEM element sides.
29 // libMesh standard elements have uniform side types, so probing side(0) is
30 // sufficient. Validated once here as a debug assert; callers build these from
31 // supported surface meshes.
32 mooseAssert(
33 [&element]()
34 {
35 if (element.n_sides() == 0)
36 return true;
37 const auto t = element.build_side_ptr(0)->type();
38 return t == EDGE2 || t == NODEELEM;
39 }(),
40 "SBMUtils::distanceFrom only handles EDGE2 and NODEELEM element sides.");
41
42 // (a) Project pt onto the normal direction
43 const auto vec_to_first = element.point(0) - pt;
44 const auto scale = vec_to_first * normal;
45 const auto projection = normal * scale;
46
47 // Check if projection point lands inside the geometry
48 if (element.contains_point(pt + projection))
49 return projection;
50
51 // (b) Point to closest edge or node
52 Real min_dist = std::numeric_limits<Real>::max();
53 Point closest_vec;
54
55 const unsigned int n_edges = element.n_sides();
56 for (unsigned int j = 0; j < n_edges; ++j)
57 {
58 std::unique_ptr<const Elem> curr_edge = element.build_side_ptr(j);
59
60 switch (curr_edge->type())
61 {
62 case EDGE2:
63 {
64 const Point & p1 = *curr_edge->node_ptr(0);
65 const Point & p2 = *curr_edge->node_ptr(1);
66
67 const Point edge = p2 - p1;
68 Real t = ((pt - p1) * edge) / (edge * edge);
69 t = std::clamp(t, 0.0, 1.0);
70 const Point proj = p1 + t * edge;
71 const Real dist = (pt - proj).norm();
72
73 if (dist < min_dist)
74 {
75 min_dist = dist;
76 closest_vec = proj - pt;
77 }
78 break;
79 }
80
81 case NODEELEM:
82 {
83 const Point & p = *curr_edge->node_ptr(0);
84 const Real dist = (pt - p).norm();
85 if (dist < min_dist)
86 {
87 min_dist = dist;
88 closest_vec = p - pt;
89 }
90 break;
91 }
92
93 default:
94 mooseAssert(false, "unreachable: side type validated by the precondition above");
95 }
96 }
97
98 return closest_vec;
99}
const Real p
Real scale
const Point & normal() const
const Elem & elem() const
LIBMESH_DEVICE_INLINE auto norm(const T &a)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

◆ distanceVectorFromFunction()

RealVectorValue SBMUtils::distanceVectorFromFunction ( const Function *  func,
const libMesh::Point &  pt,
Real  t 
)

Compute the distance vector induced by a distance function.

The provided function must represent a distance to the true boundary: either a signed distance function (ParsedFunction) or an unsigned distance function provided by UnsignedDistanceToSurfaceMesh.

Definition at line 197 of file SBMUtils.C.

198{
199 mooseAssert(dynamic_cast<const MooseParsedFunction *>(func) ||
200 dynamic_cast<const UnsignedDistanceToSurfaceMesh *>(func) ||
201 dynamic_cast<const SignedDistanceToSurfaceMesh *>(func),
202 "Function was not a valid distance strategy, the only "
203 "supported types are ParsedFunction, UnsignedDistanceToSurfaceMesh, or "
204 "SignedDistanceToSurfaceMesh.");
205
206 const Real phi = func->value(t, pt);
207 const RealVectorValue grad_phi = func->gradient(t, pt);
208 const Real grad_norm = grad_phi.norm();
209
210 if (grad_norm <= libMesh::TOLERANCE)
211 return RealVectorValue(0.0, 0.0, 0.0);
212
213 return -(phi / grad_norm) * grad_phi;
214}
virtual RealGradient gradient(Real t, const Point &p) const
virtual Real value(Real t, const Point &p) const
static constexpr Real TOLERANCE

Referenced by closestDistanceVector(), closestTrueNormalVector(), ShortestDistanceToSurface::distanceVectorByFunc(), ShortestDistanceToSurface::distanceVectorByIndex(), BoundaryShortestDistanceToSurface::execute(), TEST_F(), TEST_F(), and trueNormalFromFunction().

◆ elementDomainOccupancy() [1/2]

ElementDomainOccupancy SBMUtils::elementDomainOccupancy ( const Elem &  elem,
Order  qrule_order,
const std::function< bool(const libMesh::Point &)> &  is_in_domain 
)

Test an element against the domain defined by is_in_domain.

The result says whether all nodes are in or out of the domain and estimates the fraction of the element inside it using quadrature points. is_in_domain decides if a point belongs to the domain.

Definition at line 51 of file SBMUtils.C.

54{
55 const auto is_outside_domain = [&is_in_domain](const Point & point)
56 { return !is_in_domain(point); };
57 return elementDomainOccupancy(elem, qrule_order, is_in_domain, is_outside_domain);
58}

Referenced by InterceptedElementModifier::computeSubdomainID(), SubdomainElementModifier::computeSubdomainID(), elementDomainOccupancy(), SubdomainGrainIDGenerator::generate(), SubdomainInterceptedGenerator::generate(), TEST(), and TEST().

◆ elementDomainOccupancy() [2/2]

ElementDomainOccupancy SBMUtils::elementDomainOccupancy ( const Elem &  elem,
Order  qrule_order,
const std::function< bool(const libMesh::Point &)> &  is_in_domain,
const std::function< bool(const libMesh::Point &)> &  is_outside_domain 
)

As above, but use is_outside_domain to test nodes separately.

This allows boundary nodes to be neither inside nor outside the domain.

Definition at line 61 of file SBMUtils.C.

65{
66 bool all_nodes_in_domain = true;
67 bool all_nodes_outside_domain = true;
68 for (const auto node : make_range(elem.n_nodes()))
69 {
70 const auto & point = elem.point(node);
71 all_nodes_in_domain = all_nodes_in_domain && is_in_domain(point);
72 all_nodes_outside_domain = all_nodes_outside_domain && is_outside_domain(point);
73 }
74
75 return {all_nodes_in_domain,
76 all_nodes_outside_domain,
77 activeElementFraction(elem, qrule_order, is_in_domain)};
78}
const dof_id_type n_nodes

◆ isInactive()

bool SBMUtils::isInactive ( Real  active_fraction,
Real  lambda 
)

Return whether a partial element is inactive, i.e.

its inactive fraction exceeds lambda.

The endpoint handling preserves the convention that lambda zero rejects and lambda one accepts a partially active element.

Definition at line 81 of file SBMUtils.C.

82{
83 if (MooseUtils::absoluteFuzzyEqual(lambda, 0))
84 return true;
85 if (MooseUtils::absoluteFuzzyEqual(lambda, 1))
86 return false;
87
88 return MooseUtils::absoluteFuzzyGreaterThan(1.0 - active_fraction, lambda);
89}

Referenced by classifySubdomainFromOccupancy(), selectSubdomainFromOccupancies(), and TEST().

◆ selectSubdomainFromOccupancies()

std::optional< SubdomainID > SBMUtils::selectSubdomainFromOccupancies ( const std::vector< SubdomainOccupancy > &  candidate_occupancies,
const InterceptedSubdomainPolicy &  intercepted_policy,
Real  lambda 
)

Select a subdomain based on how multiple candidate domains occupy an element.

A fully occupied candidate takes precedence. Otherwise, the candidate with the largest domain fraction is selected, with fuzzy ties resolved by the lowest subdomain ID. A partial candidate is accepted according to the intercepted-subdomain policy and lambda.

Parameters
candidate_occupanciesCandidate subdomain IDs and their measured element occupancies
intercepted_policyWhether partial elements receive a dedicated subdomain ID, and that ID
lambdaMaximum fraction outside the selected domain for accepting a partial element
Returns
The selected subdomain ID, or std::nullopt if no candidate subdomain is selected

Definition at line 92 of file SBMUtils.C.

95{
96 std::optional<SubdomainID> fully_inside_subdomain;
97 std::optional<SubdomainID> best_partial_subdomain;
98 Real max_fraction = 0.0;
99
100 for (const auto & candidate : candidate_occupancies)
101 {
102 const auto & occupancy = candidate.occupancy;
103 if (occupancy.all_nodes_in_domain && occupancy.fraction_of_element_in_domain == 1.0)
104 {
105 if (!fully_inside_subdomain || candidate.subdomain_id < *fully_inside_subdomain)
106 fully_inside_subdomain = candidate.subdomain_id;
107 }
108 else if ((!occupancy.all_nodes_outside_domain ||
109 occupancy.fraction_of_element_in_domain > 0.0) &&
110 occupancy.fraction_of_element_in_domain >= max_fraction)
111 max_fraction = occupancy.fraction_of_element_in_domain;
112 }
113
114 if (fully_inside_subdomain)
115 return fully_inside_subdomain;
116
117 for (const auto & candidate : candidate_occupancies)
118 if ((!candidate.occupancy.all_nodes_outside_domain ||
119 candidate.occupancy.fraction_of_element_in_domain > 0.0) &&
120 MooseUtils::absoluteFuzzyEqual(candidate.occupancy.fraction_of_element_in_domain,
121 max_fraction) &&
122 (!best_partial_subdomain || candidate.subdomain_id < *best_partial_subdomain))
123 best_partial_subdomain = candidate.subdomain_id;
124
125 if (!best_partial_subdomain)
126 return std::nullopt;
127
128 if (intercepted_policy.mark_intercepted)
129 return intercepted_policy.subdomain_id;
130
131 if (isInactive(max_fraction, lambda))
132 return std::nullopt;
133
134 return best_partial_subdomain;
135}
if(subdm)

Referenced by SubdomainElementModifier::computeSubdomainID(), SubdomainGrainIDGenerator::generate(), TEST(), TEST(), and TEST().

◆ trueNormalFromFunction()

RealVectorValue SBMUtils::trueNormalFromFunction ( const Function *  func,
const libMesh::Point &  pt,
Real  t 
)

Compute the true boundary surface normal at the point on the boundary closest to pt.

Definition at line 217 of file SBMUtils.C.

218{
219 if (const auto * parsed = dynamic_cast<const MooseParsedFunction *>(func))
220 {
221 const auto proj_pt = pt + distanceVectorFromFunction(func, pt, t);
222 const RealVectorValue grad_phi = parsed->gradient(t, proj_pt);
223 const Real grad_norm = grad_phi.norm();
224 if (grad_norm <= libMesh::TOLERANCE)
225 return RealVectorValue(0.0, 0.0, 0.0);
226 return grad_phi / grad_norm;
227 }
228 else
229 {
230 const auto * mesh_func = dynamic_cast<const UnsignedDistanceToSurfaceMesh *>(func);
231 if (!mesh_func)
232 mesh_func = dynamic_cast<const SignedDistanceToSurfaceMesh *>(func);
233
234 mooseAssert(mesh_func, "Function was not a valid distance strategy");
235 return mesh_func->surfaceNormal(pt);
236 }
237}

Referenced by closestTrueNormalVector(), BoundaryShortestDistanceToSurface::execute(), TEST_F(), ShortestDistanceToSurface::trueNormalByFunc(), and ShortestDistanceToSurface::trueNormalByIndex().

◆ unionSignedDistance()

Real SBMUtils::unionSignedDistance ( const std::vector< const Function * > &  funcs,
Real  t,
const Point &  p 
)

Computes the union signed distance by taking the minimum of all signed distance functions.

This definition is valid for overlapping geometries and preserves the correct union boundary.

Definition at line 284 of file SBMUtils.C.

285{
286 // Ensure all distance functions are valid signed distance strategies
287 for (const auto * func : funcs)
288 {
289 if (!dynamic_cast<const MooseParsedFunction *>(func) &&
290 !dynamic_cast<const SignedDistanceToSurfaceMesh *>(func))
291 mooseError("Signed distance requested but function was not a valid signed distance strategy. "
292 "Valid types are MooseParsedFunction or SignedDistanceToSurfaceMesh. "
293 "Offending function: ",
294 func->name());
295 }
296
297 mooseAssert(!funcs.empty(), "unionSignedDistance requires at least one function.");
298
299 // Union signed distance: min of all signed distances
300 Real min_value = funcs[0]->value(t, p);
301 for (const auto i : make_range(std::size_t(1), funcs.size()))
302 {
303 const Real val = funcs[i]->value(t, p);
304 if (val < min_value)
305 min_value = val;
306 }
307
308 return min_value;
309}

Referenced by TEST_F(), TEST_F(), and ShortestDistanceToSurface::value().