28 params.
addParam<std::vector<FunctionName>>(
29 "surfaces", {},
"Level-set or mesh-based functions that define the boundary distances.");
31 "manager",
"SBMInterfaceManager used instead of per-interface surface functions.");
32 params.
addParam<std::vector<std::vector<SubdomainID>>>(
33 "interface_subdomain_pairs",
35 "Ordered subdomain pair for each boundary. If omitted, pairs are inferred from boundary "
36 "names of the form grainX_grainY or blockX_blockY.");
37 params.
addParam<
bool>(
"suppress_distance_warning",
39 "If true, warnings about large distances will be suppressed.");
41 params.
addParam<
bool>(
"debug_output",
false,
"If true, debug output will be enabled.");
44 "Provides, at each quadrature point on a (surrogate) boundary, the vector from that point "
45 "to its projection on the true surface, together with the true surface normal there. The "
46 "true surface may be described by level-set/distance functions or a mesh-based "
54 _suppress_distance_warning(getParam<bool>(
"suppress_distance_warning")),
55 _debug_output(getParam<bool>(
"debug_output"))
57 const auto function_names = getParam<std::vector<FunctionName>>(
"surfaces");
59 if (has_manager == !function_names.empty())
60 paramError(
"surfaces",
"Specify exactly one of 'surfaces' and 'manager'.");
62 paramError(
"interface_subdomain_pairs",
"This parameter is only valid with 'manager'.");
64 const auto boundary_names = getParam<std::vector<BoundaryName>>(
"boundary");
65 for (
const auto i : index_range(boundary_names))
69 paramError(
"boundary",
"Boundary '", boundary_names[i],
"' is configured more than once.");
74 _manager = &getUserObject<SBMInterfaceManager>(
"manager");
76 getParam<std::vector<std::vector<SubdomainID>>>(
"interface_subdomain_pairs");
77 if (!pairs.empty() && pairs.size() != boundary_names.size())
78 paramError(
"interface_subdomain_pairs",
"Provide exactly one subdomain pair per boundary.");
80 const std::regex pair_pattern(
"^(?:grain|block)([0-9]+)_(?:grain|block)([0-9]+)$");
81 for (
const auto i : index_range(boundary_names))
87 if (pairs[i].size() != 2 || pairs[i][0] == pairs[i][1])
89 "Each interface entry must contain two distinct subdomain IDs.");
96 const std::string
name = boundary_names[i];
97 if (!std::regex_match(
name, match, pair_pattern))
99 "Cannot infer a subdomain pair from boundary '",
101 "'. Supply interface_subdomain_pairs.");
102 const auto first_value = std::stoull(match[1].str());
103 const auto second_value = std::stoull(match[2].str());
104 if (first_value > std::numeric_limits<SubdomainID>::max() ||
105 second_value > std::numeric_limits<SubdomainID>::max())
106 paramError(
"boundary",
"Boundary '",
name,
"' contains an out-of-range subdomain ID.");
110 paramError(
"boundary",
"Boundary '",
name,
"' identifies the same subdomain twice.");
113 std::make_pair(first, second));
120 paramError(
"surfaces",
"Number of surfaces must match number of boundaries.");
135 "' maps to an interface not detected by the manager.");
150 const unsigned int n_qp =
_qrule->n_points();
164 mooseAssert(side_id_it !=
_side_id_index.end(),
"Boundary ID not registered in side map");
165 const unsigned int bid_index = side_id_it->second;
166 const unsigned int func_idx =
171 for (
const auto qp : make_range(n_qp))
197 const auto true_normal_dot_surrogate_normal = true_normal *
_normals[qp];
198 const auto nt_tangent =
_normals[qp] - true_normal_dot_surrogate_normal * true_normal;
202 <<
" true_normal=" << true_normal <<
" tangent=" << nt_tangent << std::endl;
211 _distance_vectors.insert(other._distance_vectors.begin(), other._distance_vectors.end());
212 _normal_vectors.insert(other._normal_vectors.begin(), other._normal_vectors.end());
213 _elem_side_to_bid.insert(other._elem_side_to_bid.begin(), other._elem_side_to_bid.end());
225 for (
auto & normal : normals)
229const RealVectorValue &
231 unsigned int qp)
const
235 mooseError(
"BoundaryShortestDistanceToSurface::surrogateDistance missing distance data for "
243 const auto &
distance = distance_it->second.at(qp);
246 const Real h = std::pow(elem->volume(), 1.0 /
dim);
247 const Real element_diagonal = std::sqrt(
dim) * h;
250 mooseWarning(
"Distance exceeds the estimated element scale on element ",
254 ": the distance from the surrogate boundary quadrature point to the true "
257 ") is larger than the estimated element diagonal (",
259 "). This may indicate an incorrect interface selection or distance function. "
260 "Please verify the interface geometry.");
265const RealVectorValue &
270 mooseError(
"BoundaryShortestDistanceToSurface::trueNormal missing normal data for elem_id = ",
275 return normal_it->second.at(qp);
boundary_id_type BoundaryID
BoundaryShortestDistanceToSurface::ElemSide ElemSide
registerMooseObject("ShiftedBoundaryMethodApp", BoundaryShortestDistanceToSurface)
Computes and stores the distance vectors and true surface normals from surrogate boundary quadrature ...
BoundaryShortestDistanceToSurface(const InputParameters ¶meters)
std::pair< dof_id_type, unsigned short int > ElemSide
static InputParameters validParams()
bool _suppress_distance_warning
Whether to suppress warnings about large distances.
virtual void initialize() override
const RealVectorValue & trueNormal(const ElemSide &elem_side, unsigned int qp) const
Provides query interfaces for normal vector.
std::map< BoundaryID, std::pair< SubdomainID, SubdomainID > > _boundary_subdomain_pairs
Ordered subdomain pair associated with each surrogate boundary.
std::map< BoundaryID, unsigned int > _side_id_index
Map from boundary ID to internal distance function index.
bool _debug_output
Whether to output debug information.
std::vector< const Function * > _distance_functions
Local distance functions when no external distance user object is supplied.
const SBMInterfaceManager * _manager
Optional manager supplying geometry for interfaces in a single surface mesh.
const RealVectorValue & surrogateDistance(const ElemSide &elem_side, unsigned int qp) const
Provides query interfaces for distance vector.
virtual void execute() override
virtual void initialSetup() override
std::map< ElemSide, unsigned int > _elem_side_to_bid
Map from ElemSide to boundary ID index.
virtual void finalize() override
std::map< ElemSide, std::vector< RealVectorValue > > _distance_vectors
Distance vectors to the true interface at each quadrature point on an element side.
std::map< ElemSide, std::vector< RealVectorValue > > _normal_vectors
True interface normals at projected quadrature points on an element side.
std::vector< Real > _true_interface_measures
Signed true-interface measure integrated over each surrogate boundary.
virtual void threadJoin(const UserObject &uo) override
const ConsoleStream _console
const std::string & name() const
void paramError(const std::string ¶m, Args... args) const
bool isParamSetByUser(const std::string &name) const
void mooseError(Args &&... args) const
void mooseWarning(Args &&... args) const
bool isParamValid(const std::string &name) const
virtual unsigned int dimension() const
virtual Elem * elemPtr(const dof_id_type i)
const std::string & getBoundaryName(const BoundaryID boundary_id) const
BoundaryID getBoundaryID(const BoundaryName &boundary_name) const
InterfaceQueryResult queryInterface(SubdomainID first, SubdomainID second, const Point &point) const
Return distance and normal data for an interface. The normal points from first to second.
bool hasInterface(SubdomainID first, SubdomainID second) const
Whether an interface was detected between two subdomains.
const unsigned int & _current_side
static InputParameters validParams()
const QBase *const & _qrule
const MooseArray< Real > & _JxW
const MooseArray< Point > & _q_point
const MooseArray< Point > & _normals
const Elem *const & _current_elem
const BoundaryID & _current_boundary_id
const Parallel::Communicator & comm() const
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 distance
Shortest distance vector to the interface.
Real distance(const Point &p)