- builderSBMSurfaceMeshBuilder that provides KDTree, elem_id_map, and boundary elements.
C++ Type:UserObjectName
Controllable:No
Description:SBMSurfaceMeshBuilder that provides KDTree, elem_id_map, and boundary elements.
UnsignedDistanceToSurfaceMesh
UnsignedDistanceToSurfaceMesh is a Function that queries the KDTree and boundary element database produced by SBMSurfaceMeshBuilder to provide distance information relative to an arbitrary surface mesh. The function locates the nearest boundary element via a nearest-neighbor search in the KDTree, computes the distance vector using the element-specific distanceFrom method, and returns the vector norm as the function value. The gradient evaluates to the normalized direction from the boundary element toward the query point.
Usage
Set the builder parameter to the name of an SBMSurfaceMeshBuilder user object that was configured to store the relevant surface mesh. Because the function caches pointers to the KDTree, element ID map, and boundary element wrappers during initialSetup, the builder object must be declared in the same execution block (for example inside [UserObjects]) and be executed before any kernels request the function values.
Returns unsigned distance to a surface mesh using KDTree nearest neighbor search. The gradient returns the unit vector pointing from boundary to query point.
Input Parameters
- control_tagsAdds user-defined labels for accessing object parameters via control logic.
C++ Type:std::vector<std::string>
Controllable:No
Description:Adds user-defined labels for accessing object parameters via control logic.
- enableTrueSet the enabled status of the MooseObject.
Default:True
C++ Type:bool
Controllable:No
Description:Set the enabled status of the MooseObject.
Advanced Parameters
Input Files
- (modules/shifted_boundary_method/test/tests/distance_calc/2D_signed_distance.i)
- (modules/shifted_boundary_method/test/tests/coverage/gradient_on_surface.i)
- (modules/shifted_boundary_method/test/tests/distance_calc/3D_multiple_distances_refine.i)
- (modules/shifted_boundary_method/test/tests/distance_calc/2D_distance_refine.i)
- (modules/shifted_boundary_method/test/tests/distance_calc/2D_multiple_distances_refine_test.i)
- (modules/shifted_boundary_method/test/tests/distance_calc/3D_distance_refine.i)
- (modules/shifted_boundary_method/test/tests/coverage/coverage_omnibus.i)
Child Objects
(modules/shifted_boundary_method/test/tests/distance_calc/2D_signed_distance.i)
nx = 16
# Asymmetric immersed geometry: a non-circular closed curve. A circle is maximally
# symmetric (every diameter is a symmetry axis), so an element centroid can sit
# exactly on a symmetry axis and become equidistant to two surface segments. That
# KDTree nearest-segment tie is broken only by floating-point round-off, which
# differs across platforms and flips the gradient direction. Deforming the boundary
# with a radial modulation removes all symmetry, so every centroid has a unique
# nearest segment and the in-out sign / gradient stay reproducible across platforms.
R = 1.3
cx = 2.03
cy = 1.97
# Control the boundary asymmetry (radial modulation amplitudes).
a = 0.18
b = 0.10
n_seg = 64
[Problem]
solve = false
[]
[Mesh]
[shift_boundary_mesh]
type = ParsedCurveGenerator
x_formula = '${cx} + ${R} * (1 + ${a} * cos(t) + ${b} * sin(2*t)) * cos(t)'
y_formula = '${cy} + ${R} * (1 + ${a} * cos(t) + ${b} * sin(2*t)) * sin(t)'
section_bounding_t_values = '0 ${fparse 2*pi}'
nums_segments = '${n_seg}'
is_closed_loop = true
save_with_name = 'shift_boundary_mesh'
[]
[gen]
type = CartesianMeshGenerator
dim = 2
dx = '4'
dy = '4'
ix = '${nx}'
iy = '${nx}'
subdomain_id = '1'
[]
add_subdomain_ids = 2 # outside block
add_sideset_names = 'SBMinterface'
final_generator = 'gen'
[]
[UserObjects]
[TreeBuilder]
type = SBMSurfaceMeshBuilder
surface_mesh = shift_boundary_mesh
[]
[signed_distance_to_surface]
type = ShortestDistanceToSurface
surfaces = 'sign_dist_square'
signed_distance = true
[]
[distance_to_surface]
type = ShortestDistanceToSurface
surfaces = 'dist_square'
[]
[InOutTest]
type = PointInPolyhedronCheckUO
builder = TreeBuilder
# A user-selected axis-aligned ray avoids the PCA/SVD direction ambiguity of
# an isotropic shape (circle), which is not reproducible across platforms.
point_containment_method = user_selected_ray
ray_direction = '1 0 0'
[]
[SignedFunctionTest]
type = PointInSignedFunctionCheckUO
function = level_set
[]
[]
[Functions]
[level_set]
# Const level set that is > 0, so if we union with this, it does not change any behavior
# (IN/OUT/ON still remain).
type = ConstantFunction
value = 1
[]
[dist_square]
type = UnsignedDistanceToSurfaceMesh
builder = TreeBuilder
[]
[sign_dist_square]
type = SignedDistanceToSurfaceMesh
builder = TreeBuilder
in_out_test = InOutTest
[]
[]
[Variables]
[u]
initial_condition = 1
block = 1
[]
[]
[AuxVariables]
[signed_distance]
order = CONSTANT
family = MONOMIAL
[]
[unsigned_distance]
order = CONSTANT
family = MONOMIAL
[]
# Vector field capturing the signed-distance gradient direction. Sampling the
# gradient at every element centroid exercises points both inside and outside
# the circle, so the gold pins down the outward-pointing direction on both sides.
[signed_distance_grad]
order = CONSTANT
family = MONOMIAL_VEC
[]
[]
[AuxKernels]
[signed_dist]
type = ElementCentroidToSurfaceDistanceAux
distance_to_surface = signed_distance_to_surface
variable = signed_distance
execute_on = 'INITIAL timestep_begin'
[]
[unsigned_dist]
type = ElementCentroidToSurfaceDistanceAux
distance_to_surface = distance_to_surface
variable = unsigned_distance
execute_on = 'INITIAL timestep_begin'
[]
[signed_dist_grad]
type = FunctorElementalGradientAux
functor = sign_dist_square
variable = signed_distance_grad
execute_on = 'INITIAL timestep_begin'
[]
[]
[Executioner]
type = Steady
[]
[Outputs]
exodus = true
[]
(modules/shifted_boundary_method/test/tests/coverage/gradient_on_surface.i)
# Covers the zero-distance early-return in UnsignedDistanceToSurfaceMesh::gradient
# by querying the function at a point that lies exactly on the surface mesh.
[Problem]
solve = false
[]
[Mesh]
[boundary_mesh]
type = GeneratedMeshGenerator
dim = 1
xmin = 0.0
xmax = 1.0
nx = 1
save_with_name = 'boundary_mesh'
[]
[gen]
type = GeneratedMeshGenerator
dim = 2
xmin = -1.0
xmax = 2.0
ymin = -1.0
ymax = 1.0
nx = 6
ny = 4
subdomain_ids = '1'
[]
add_subdomain_ids = 2
final_generator = 'gen'
[]
[UserObjects]
[TreeBuilder]
type = SBMSurfaceMeshBuilder
surface_mesh = boundary_mesh
[]
[distance_to_surface]
type = ShortestDistanceToSurface
surfaces = 'dist_edge'
[]
[]
[Functions]
[dist_edge]
type = UnsignedDistanceToSurfaceMesh
builder = TreeBuilder
[]
[]
[AuxVariables]
# Distance evaluated via the mesh function at a point exactly on the edge.
# Forces UnsignedDistanceToSurfaceMesh::gradient's dist<=TOLERANCE branch
# (SBMUtils::distanceVectorFromFunction calls func->gradient internally).
[dist_on_surface]
order = CONSTANT
family = MONOMIAL
[]
[]
[AuxKernels]
[dist_on_surface]
type = ShortestDistanceToSurfaceTestAux
distance_to_surface = distance_to_surface
method = distance_by_func
function = dist_edge
at_point = '0.5 0.0 0.0' # midpoint of the lone edge: on surface
variable = dist_on_surface
execute_on = 'INITIAL'
[]
[]
[Executioner]
type = Steady
[]
[Outputs]
exodus = true
[]
(modules/shifted_boundary_method/test/tests/distance_calc/3D_multiple_distances_refine.i)
nx = 10
[Problem]
solve = false
[]
[Mesh]
[boundary_mesh]
type = FileMeshGenerator
file = 'cube_surface.msh'
[]
[shift_boundary_mesh]
type = TransformGenerator
transform = TRANSLATE
vector_value = '2.0 2.0 1.5'
input = boundary_mesh
save_with_name = 'shift_boundary_mesh'
[]
[gen]
type = CartesianMeshGenerator
dim = 3
dx = '3'
dy = '3'
dz = '3'
ix = '${nx}'
iy = '${nx}'
iz = '${nx}'
subdomain_id = '1'
[]
add_subdomain_ids = 2
add_sideset_names = 'SBMinterface'
final_generator = 'gen'
[]
[UserObjects]
[TreeBuilder]
type = SBMSurfaceMeshBuilder
surface_mesh = shift_boundary_mesh
[]
[distance_to_surface]
type = ShortestDistanceToSurface
surfaces = 'dist_bunny sphere1'
[]
[]
[Functions]
[dist_bunny]
type = UnsignedDistanceToSurfaceMesh
builder = TreeBuilder
[]
[sphere1]
type = ParsedFunction
expression = "sqrt((x-1.0)^2 + (y-1.0)^2 + (z-1.0)^2) - 0.5"
[]
[]
[Variables]
[u]
initial_condition = 1
block = 1
[]
[]
[AuxVariables]
[distance]
order = CONSTANT
family = MONOMIAL
[]
[]
[AuxKernels]
[dist]
type = ElementCentroidToSurfaceDistanceAux
distance_to_surface = distance_to_surface
variable = distance
execute_on = 'INITIAL timestep_begin'
[]
[]
[Adaptivity]
marker = refine_based_on_aux
max_h_level = 3
steps = 2
[Markers]
[refine_based_on_aux]
type = ValueThresholdMarker
variable = distance
refine = 0.05
coarsen = 0.5
invert = true
[]
[]
[]
[Executioner]
type = Steady
[]
[Outputs]
exodus = true
[]
(modules/shifted_boundary_method/test/tests/distance_calc/2D_distance_refine.i)
nx = 64
[Problem]
solve = false
[]
[Mesh]
[boundary_mesh]
type = FileMeshGenerator
file = 'square_boundary.msh'
[]
[shift_boundary_mesh]
type = TransformGenerator
transform = TRANSLATE
vector_value = '2.0 2.0 0.0' # translation in x, y, z directions
input = boundary_mesh
save_with_name = 'shift_boundary_mesh'
[]
[gen]
type = CartesianMeshGenerator
dim = 2
dx = '4'
dy = '4'
ix = '${nx}'
iy = '${nx}'
subdomain_id = '1'
[]
add_subdomain_ids = 2 # outside block
add_sideset_names = 'SBMinterface'
final_generator = 'gen'
[]
[UserObjects]
[TreeBuilder]
type = SBMSurfaceMeshBuilder
surface_mesh = shift_boundary_mesh
[]
[distance_to_surface]
type = ShortestDistanceToSurface
surfaces = 'dist_star'
[]
[]
[Functions]
[dist_star]
type = UnsignedDistanceToSurfaceMesh
builder = TreeBuilder
[]
[]
[Variables]
[u]
initial_condition = 1
block = 1
[]
[]
[AuxVariables]
[distance]
order = CONSTANT
family = MONOMIAL
[]
[]
[AuxKernels]
[dist]
type = ElementCentroidToSurfaceDistanceAux
distance_to_surface = distance_to_surface
variable = distance
execute_on = 'INITIAL timestep_begin'
[]
[]
[Adaptivity]
marker = refine_based_on_aux
max_h_level = 5
steps = 3
[Markers]
[refine_based_on_aux]
type = ValueThresholdMarker
variable = distance
refine = 0.05
coarsen = 0.5
invert = true
[]
[]
[]
[Executioner]
type = Steady
[]
[Outputs]
exodus = true
[]
(modules/shifted_boundary_method/test/tests/distance_calc/2D_multiple_distances_refine_test.i)
nx = 64
[Problem]
solve = false
[]
[Mesh]
[boundary_mesh]
type = FileMeshGenerator
file = 'square_boundary.msh'
[]
[shift_boundary_mesh]
type = TransformGenerator
transform = TRANSLATE
vector_value = '2.0 2.0 0.0' # translation in x, y, z directions
input = boundary_mesh
save_with_name = 'shift_boundary_mesh'
[]
[gen]
type = CartesianMeshGenerator
dim = 2
dx = '4'
dy = '4'
ix = '${nx}'
iy = '${nx}'
subdomain_id = '1'
[]
add_subdomain_ids = 2 # outside block
add_sideset_names = 'SBMinterface'
final_generator = 'gen'
[]
[UserObjects]
[TreeBuilder]
type = SBMSurfaceMeshBuilder
surface_mesh = shift_boundary_mesh
[]
[distance_to_surface]
type = ShortestDistanceToSurface
surfaces = 'dist_star circle1 ellipse_rot'
[]
[]
[Variables]
[u]
initial_condition = 1
block = 1
[]
[]
[Functions]
[dist_star]
type = UnsignedDistanceToSurfaceMesh
builder = TreeBuilder
[]
[circle1]
type = ParsedFunction
expression = "sqrt((x-1.0)^2 + (y-1.0)^2) - 0.5"
[]
[ellipse_rot]
type = ParsedFunction
symbol_names = 'a b theta cx cy'
symbol_values = '0.8 0.4 0.785398 3.0 1.0'
expression = "
(
(
((x-cx)*cos(theta) + (y-cy)*sin(theta)) / a
)^2
+
(
(-(x-cx)*sin(theta) + (y-cy)*cos(theta)) / b
)^2
)^(0.5) - 1
"
[]
[]
[AuxVariables]
[distance]
order = CONSTANT
family = MONOMIAL
[]
[]
[AuxKernels]
[dist]
type = ElementCentroidToSurfaceDistanceAux
distance_to_surface = distance_to_surface
variable = distance
execute_on = 'INITIAL timestep_begin'
[]
[]
[Adaptivity]
marker = refine_based_on_aux
max_h_level = 5
steps = 3
[Markers]
[refine_based_on_aux]
type = ValueThresholdMarker
variable = distance
refine = 0.05
coarsen = 0.5
invert = true
[]
[]
[]
[Executioner]
type = Steady
[]
[Outputs]
exodus = true
[]
(modules/shifted_boundary_method/test/tests/distance_calc/3D_distance_refine.i)
nx = 10
[Problem]
solve = false
[]
[Mesh]
[boundary_mesh]
type = FileMeshGenerator
file = 'cube_surface.msh'
[]
[shift_boundary_mesh]
type = TransformGenerator
transform = TRANSLATE
vector_value = '1.07 1.13 1.19'
input = boundary_mesh
save_with_name = 'shift_boundary_mesh'
[]
[gen]
type = CartesianMeshGenerator
dim = 3
dx = '4'
dy = '4'
dz = '4'
ix = '${nx}'
iy = '${nx}'
iz = '${nx}'
subdomain_id = '1'
[]
add_subdomain_ids = 2
add_sideset_names = 'SBMinterface'
final_generator = 'gen'
[]
[UserObjects]
[TreeBuilder]
type = SBMSurfaceMeshBuilder
surface_mesh = shift_boundary_mesh
[]
[distance_to_surface]
type = ShortestDistanceToSurface
surfaces = 'dist_bunny'
[]
[]
[Functions]
[dist_bunny]
type = UnsignedDistanceToSurfaceMesh
builder = TreeBuilder
[]
[]
[Variables]
[u]
initial_condition = 1
block = 1
[]
[]
[AuxVariables]
[distance]
order = CONSTANT
family = MONOMIAL
[]
[]
[AuxKernels]
[dist]
type = ElementCentroidToSurfaceDistanceAux
distance_to_surface = distance_to_surface
variable = distance
execute_on = 'INITIAL timestep_begin'
[]
[]
[Adaptivity]
marker = refine_based_on_aux
max_h_level = 5
steps = 3
[Markers]
[refine_based_on_aux]
type = ValueThresholdMarker
variable = distance
refine = 0.15
coarsen = 0.5
invert = true
[]
[]
[]
[Executioner]
type = Steady
[]
[Outputs]
exodus = true
[]
(modules/shifted_boundary_method/test/tests/coverage/coverage_omnibus.i)
# Coverage driver for ShortestDistanceToSurface's trueNormal / *ByIndex / *ByFunc
# accessors (via the test-only ShortestDistanceToSurfaceTestAux), the
# zero-gradient short-circuits in SBMUtils (via a constant ParsedFunction), and
# the watertight-mesh log branch in SBMSurfaceMeshBuilder.
nx = 16
[Problem]
solve = false
[]
[Mesh]
[boundary_mesh]
type = FileMeshGenerator
file = '../distance_calc/square_boundary.msh'
[]
[shift_boundary_mesh]
type = TransformGenerator
transform = TRANSLATE
vector_value = '2.0 2.0 0.0'
input = boundary_mesh
save_with_name = 'shift_boundary_mesh'
[]
[gen]
type = CartesianMeshGenerator
dim = 2
dx = '4'
dy = '4'
ix = '${nx}'
iy = '${nx}'
subdomain_id = '1'
[]
add_subdomain_ids = 2
add_sideset_names = 'SBMinterface'
final_generator = 'gen'
[]
[UserObjects]
[TreeBuilder]
type = SBMSurfaceMeshBuilder
surface_mesh = shift_boundary_mesh
check_watertightness = true # exercises watertight=true log branch
[]
[distance_to_surface]
type = ShortestDistanceToSurface
surfaces = 'dist_star circle1 const_one'
[]
[]
[Functions]
[dist_star]
type = UnsignedDistanceToSurfaceMesh
builder = TreeBuilder
[]
[circle1]
type = ParsedFunction
expression = "sqrt((x-1.0)^2 + (y-1.0)^2) - 0.5"
[]
# Constant function: value()=1, gradient()=0. Triggers the
# zero-gradient short-circuits in SBMUtils.
[const_one]
type = ParsedFunction
expression = "1.0"
[]
[]
[AuxVariables]
[dist_centroid]
order = CONSTANT
family = MONOMIAL
[]
[true_normal_x]
order = CONSTANT
family = MONOMIAL
[]
[dist_by_index]
order = CONSTANT
family = MONOMIAL
[]
[true_normal_by_index]
order = CONSTANT
family = MONOMIAL
[]
# Distance/normal via *ByFunc using the mesh-based UnsignedDistance function.
[dist_by_func_mesh]
order = CONSTANT
family = MONOMIAL
[]
[normal_by_func_mesh]
order = CONSTANT
family = MONOMIAL
[]
# Distance/normal via *ByFunc using the zero-gradient constant function.
# Forces the zero-gradient branches in SBMUtils to fire.
[dist_by_func_const]
order = CONSTANT
family = MONOMIAL
[]
[normal_by_func_const]
order = CONSTANT
family = MONOMIAL
[]
[]
[AuxKernels]
[dist_centroid]
type = ElementCentroidToSurfaceDistanceAux
distance_to_surface = distance_to_surface
variable = dist_centroid
execute_on = 'INITIAL'
[]
[true_normal_x]
type = ShortestDistanceToSurfaceTestAux
distance_to_surface = distance_to_surface
method = true_normal
component = x
variable = true_normal_x
# Exercises SBMSurfaceMeshBuilder::surfaceElementSet().centroids().
builder = TreeBuilder
execute_on = 'INITIAL'
[]
[dist_by_index]
type = ShortestDistanceToSurfaceTestAux
distance_to_surface = distance_to_surface
method = distance_by_index
index = 1 # circle1
variable = dist_by_index
execute_on = 'INITIAL'
[]
[true_normal_by_index]
type = ShortestDistanceToSurfaceTestAux
distance_to_surface = distance_to_surface
method = true_normal_by_index
index = 1 # circle1 (ParsedFunction branch of trueNormalFromFunction)
component = x
variable = true_normal_by_index
execute_on = 'INITIAL'
[]
[dist_by_func_mesh]
type = ShortestDistanceToSurfaceTestAux
distance_to_surface = distance_to_surface
method = distance_by_func
function = dist_star # exercises UnsignedDistanceToSurfaceMesh branch
variable = dist_by_func_mesh
execute_on = 'INITIAL'
[]
[normal_by_func_mesh]
type = ShortestDistanceToSurfaceTestAux
distance_to_surface = distance_to_surface
method = true_normal_by_func
function = dist_star # mesh-function branch of trueNormalFromFunction
component = x
variable = normal_by_func_mesh
execute_on = 'INITIAL'
[]
[dist_by_func_const]
type = ShortestDistanceToSurfaceTestAux
distance_to_surface = distance_to_surface
method = distance_by_func
function = const_one # zero-gradient ParsedFunction branch
variable = dist_by_func_const
execute_on = 'INITIAL'
[]
[normal_by_func_const]
type = ShortestDistanceToSurfaceTestAux
distance_to_surface = distance_to_surface
method = true_normal_by_func
function = const_one # zero-gradient parsed branch in trueNormalFromFunction
component = x
variable = normal_by_func_const
execute_on = 'INITIAL'
[]
[]
[Executioner]
type = Steady
[]
[Outputs]
exodus = true
[]
(modules/shifted_boundary_method/include/functions/SignedDistanceToSurfaceMesh.h)
// This file is part of the MOOSE framework
// https://mooseframework.inl.gov
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#pragma once
#include "UnsignedDistanceToSurfaceMesh.h"
class PointInSurfaceCheckInterface;
/**
* Computes the signed distance to a surface mesh using KDTree nearest
* neighbor lookup from SBMSurfaceMeshBuilder. The gradient returns the
* unit vector pointing from the boundary element to the query point.
*/
class SignedDistanceToSurfaceMesh : public UnsignedDistanceToSurfaceMesh
{
public:
SignedDistanceToSurfaceMesh(const InputParameters & parameters);
static InputParameters validParams();
void initialSetup() override;
/// Return signed distance value
using UnsignedDistanceToSurfaceMesh::value;
Real value(Real t, const Point & p) const override;
/// Return the spatial gradient of the signed distance function. The signed
/// distance gradient points in the direction of increasing signed value
/// (outward across the surface) on both sides, so the inherited unsigned
/// gradient must be negated for interior points.
RealGradient gradient(Real t, const Point & p) const override;
private:
/// user object for in-out test
const PointInSurfaceCheckInterface * _in_out_test;
};