https://mooseframework.inl.gov
Loading...
Searching...
No Matches
SubdomainElementModifier.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
11#include "SBMUtils.h"
12
13#include <algorithm>
14#include <optional>
15#include <utility>
16#include <vector>
17
18registerMooseObject("ShiftedBoundaryMethodApp", SubdomainElementModifier);
19
22{
24 params.addClassDescription("Assign subdomain ID based on geometric inclusion using per-subdomain "
25 "in-out checks provided by a subdomain_id_tester.");
26
27 params.addRequiredParam<UserObjectName>(
28 "subdomain_id_tester",
29 "The UserObject (PointInSubdomainCheckUO) for subdomain in/out tests.");
30
31 return params;
32}
33
36 _subdomain_id_tester(getUserObject<PointInSubdomainCheckUO>("subdomain_id_tester"))
37{
38}
39
42{
43 const Elem * elem = this->_current_elem;
44 if (!elem)
45 mooseError("SubdomainElementModifier: _current_elem is null!");
46
47 const auto & all_checkers = _subdomain_id_tester.subdomainCheckers();
48 if (all_checkers.empty())
49 mooseError("SubdomainElementModifier: subdomain checker collection is empty!");
50
51 std::optional<SubdomainID> fully_inside_subdomain;
52 std::optional<SubdomainID> best_intercepted_subdomain;
53 std::vector<std::pair<SubdomainID, Real>> intercepted_candidates;
54 Real max_ratio = 0.0;
55
56 for (const auto & [sub_id, checker_ptr] : all_checkers)
57 {
58 unsigned int num_inside_nodes = 0;
59 for (const auto i : make_range(elem->n_nodes()))
60 if (checker_ptr->sideness(elem->point(i)) != SurfaceGeometry::SurfaceSide::OUTSIDE)
61 ++num_inside_nodes;
62
63 const auto * const checker = checker_ptr.get();
64 const Real ratio_active = SBMUtils::activeElementFraction(
65 *elem,
67 [checker](const Point & point)
68 { return checker->sideness(point) != SurfaceGeometry::SurfaceSide::OUTSIDE; });
69
70 if (num_inside_nodes == elem->n_nodes() && ratio_active == 1.0)
71 {
72 if (!fully_inside_subdomain || sub_id < *fully_inside_subdomain)
73 fully_inside_subdomain = sub_id;
74 continue;
75 }
76 // All nodes may be outside even when a closed geometry lies within the element or its surface
77 // crosses the element. Retain the checker if either nodes or quadrature points find activity.
78 const bool has_active_region = num_inside_nodes != 0 || ratio_active > 0.0;
79 if (!has_active_region)
80 continue;
81
82 intercepted_candidates.emplace_back(sub_id, ratio_active);
83 max_ratio = std::max(max_ratio, ratio_active);
84 }
85
86 if (fully_inside_subdomain)
87 return *fully_inside_subdomain;
88
89 // Iteration order is deterministic (subdomainCheckers() is id-ordered), but fuzzy-equal ratios
90 // can still tie. Compare every candidate against the fixed exact maximum, then resolve fuzzy
91 // ties by the lowest subdomain ID.
92 for (const auto & [sub_id, ratio_active] : intercepted_candidates)
93 if (MooseUtils::absoluteFuzzyEqual(ratio_active, max_ratio) &&
94 (!best_intercepted_subdomain || sub_id < *best_intercepted_subdomain))
95 best_intercepted_subdomain = sub_id;
96
97 // If the element is outside all checked subdomains, leave its current subdomain unchanged by
98 // returning Moose::INVALID_BLOCK_ID.
99 if (!best_intercepted_subdomain)
101
104
106 : *best_intercepted_subdomain;
107}
subdomain_id_type SubdomainID
registerMooseObject("ShiftedBoundaryMethodApp", SubdomainElementModifier)
const Elem *const & _current_elem
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
void mooseError(Args &&... args) const
Performs in-out testing and identifies the subdomain containing a point.
const std::map< subdomain_id_type, std::unique_ptr< const PointContainmentClassifier > > & subdomainCheckers() const
Read-only view of the per-subdomain checkers (subdomain id -> checker).
Common partial-element classification parameters for shifted boundary element modifiers.
const Order _qrule_order
Quadrature order used to estimate the active fraction.
const Real _lambda
Threshold applied to the inactive fraction of a partially active element.
const SubdomainID _subdomain_id_intercepted
Subdomain ID assigned to intercepted elements.
const bool _mark_intercepted
Whether to assign a dedicated subdomain ID to intercepted elements.
SubdomainElementModifier(const InputParameters &parameters)
const PointInSubdomainCheckUO & _subdomain_id_tester
The user object containing subdomain-wise in/out checkers.
virtual SubdomainID computeSubdomainID() override
static InputParameters validParams()
const SubdomainID INVALID_BLOCK_ID
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.
Definition SBMUtils.C:26
bool isInactive(Real active_fraction, Real lambda)
Return whether a partial element is inactive, i.e.
Definition SBMUtils.C:51