15 #include "libmesh/mesh_generation.h" 16 #include "libmesh/mesh.h" 17 #include "libmesh/string_to_enum.h" 18 #include "libmesh/elem.h" 29 params.
renameParam(
"max_paint_size_centroids",
"max_subdomain_size_centroids",
"");
31 "contiguous_assignments_only",
33 "Whether to only group elements in a subdomain using the 'flooding' algorithm. " 34 "Note: this also sets 'flood_elements_once' to true if the user did not explicitly pass " 38 params.
addParam<
bool>(
"select_max_neighbor_element_subdomains",
40 "Whether to perform a final subdomain assignment phase where each element " 41 "is assigned to the subdomain " 42 "that holds the most neighbors of the element with a similar normal.");
44 "separate_elements_connected_by_a_single_node",
46 "Whether to perform a final subdomain assignment phase where any element that is not " 47 "connected to other elements from the same subdomain is re-assigned to either the subdomain " 48 "that all side neighbor elements belong to, or a new subdomain if there is no such subdomain " 49 "including all its side neighbors. Note that normals are not checked in this phase, and the " 50 "subdomain size criterion is assumed to be already met.");
56 "separate_elements_connected_by_a_single_node select_max_neighbor_element_subdomains",
57 "Post flooding subdomain re-assignments");
65 "Adds subdomains to surface (2D) elements in the (3D) mesh based on unique normals.");
72 _contiguous_assignments_only(getParam<bool>(
"contiguous_assignments_only"))
78 std::unique_ptr<MeshBase>
81 std::unique_ptr<MeshBase>
mesh = std::move(
_input);
82 if (!
mesh->is_serial())
84 "SurfaceSubdomainsFromAllNormalsGenerator is not implemented for non serialized meshes");
87 unsigned int num_neighborless = 0;
91 if (!
mesh->preparation().has_neighbor_ptrs)
92 mesh->find_neighbors();
98 for (
auto & elem :
mesh->element_ptr_range())
101 if (elem->dim() != 2)
107 mooseWarning(
"Element '" + std::to_string(elem->id()) +
"' has no neighbors");
124 const std::map<SubdomainID, RealVectorValue>::value_type * item =
nullptr;
125 bool sub_id_found =
false;
142 std::map<SubdomainID, unsigned int> sub_id_neighbors;
145 for (
const auto neighbor :
make_range(elem->n_sides()))
146 if (elem->neighbor_ptr(neighbor) &&
150 *elem->neighbor_ptr(neighbor),
154 sub_id_neighbors[elem->neighbor_ptr(neighbor)->subdomain_id()]++;
157 unsigned int max_of_subid = 0;
158 for (
const auto & [key, item] : sub_id_neighbors)
159 if (item >= max_of_subid)
162 neighbor_majority_sub_id = key;
176 Elem * starting_element = elem;
178 Point flooding_normal = elem_normal;
182 flooding_sub_id = item->first;
183 flooding_normal = item->second;
185 else if (sub_id_found)
188 flooding_sub_id = neighbor_majority_sub_id;
197 if (user_specified_normal)
204 flood(elem, flooding_normal, *starting_element, flooding_sub_id, *
mesh);
208 if (getParam<bool>(
"select_max_neighbor_element_subdomains"))
209 for (
auto & elem :
mesh->element_ptr_range())
212 if (elem->dim() != 2)
218 bool sub_id_found =
false;
220 std::map<SubdomainID, unsigned int> sub_id_neighbors;
229 for (
const auto neighbor_i :
make_range(elem->n_sides()))
231 const auto neighbor = elem->neighbor_ptr(neighbor_i);
241 sub_id_neighbors[neighbor->subdomain_id()]++;
245 unsigned int max_of_subid = 0;
246 for (
const auto & [key, item] : sub_id_neighbors)
247 if (item >= max_of_subid)
253 elem->subdomain_id() = sub_id;
256 if (getParam<bool>(
"separate_elements_connected_by_a_single_node"))
257 for (
auto & elem :
mesh->element_ptr_range())
260 if (elem->dim() != 2)
263 bool connected_to_a_neighbor =
false;
264 for (
const auto neighbor :
make_range(elem->n_sides()))
265 if (elem->neighbor_ptr(neighbor) &&
266 elem->subdomain_id() == elem->neighbor_ptr(neighbor)->subdomain_id())
267 connected_to_a_neighbor =
true;
269 if (!connected_to_a_neighbor)
271 bool same_subdomain =
true;
276 for (
const auto neighbor :
make_range(elem->n_sides()))
277 if (elem->neighbor_ptr(neighbor))
280 common_sub = elem->neighbor_ptr(neighbor)->subdomain_id();
281 else if (common_sub != elem->neighbor_ptr(neighbor)->subdomain_id())
282 same_subdomain =
false;
286 elem->subdomain_id() = common_sub;
293 mooseWarning(
"Several subdomains were created for neighborless elements: " +
294 std::to_string(num_neighborless));
297 mesh->unset_is_prepared();
307 elem->subdomain_id() = sub_id;
registerMooseObject("MooseApp", SurfaceSubdomainsFromAllNormalsGenerator)
KOKKOS_INLINE_FUNCTION const T * find(const T &target, const T *const begin, const T *const end)
Find a value in an array.
void setup(MeshBase &mesh)
Sets up various data structures.
void flood(Elem *const elem, const Point &normal, const Elem &starting_elem, const subdomain_id_type &sub_id, MeshBase &mesh)
This method implements a recursive flood routine to paint (applying an operation) to elements on mesh...
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
std::unique_ptr< T_DEST, T_DELETER > dynamic_pointer_cast(std::unique_ptr< T_SRC, T_DELETER > &src)
These are reworked from https://stackoverflow.com/a/11003103.
Point get2DElemNormal(const Elem *const elem) const
Get the normal of the 2D element.
static InputParameters validParams()
auto max(const L &left, const R &right)
void mooseWarning(Args &&... args) const
const bool _check_painted_neighor_normals
Additional heuristic: check the element neighbors and if they have already been painted with the subd...
SurfaceSubdomainsFromAllNormalsGenerator(const InputParameters ¶meters)
std::map< SubdomainID, Elem * > _subdomain_to_starting_elem
Map from subdomain IDs to a pointer to the element where the subdomain-paiting started.
void actOnElem(Elem *const elem, const Point &normal, const subdomain_id_type &sub_id, MeshBase &mesh) override
Action to perform when flooding.
Point _normal
if specified, then surface elements are only considered if their normal is close to this ...
static InputParameters validParams()
IntRange< T > make_range(T beg, T end)
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
bool _flood_only_once
Only act on each element once.
std::unordered_set< Elem * > _acted_upon_once
Set used when flooding each element once. If the element pointer is in the set, it has been visited a...
SubdomainID getNextFreeSubdomainID(MeshBase &input_mesh)
Checks input mesh and returns max(block ID) + 1, which represents a block ID that is not currently in...
std::map< SubdomainID, RealVectorValue > _subdomain_to_normal_map
Map from subdomain IDs to the normals of the corresponding boundaries.
bool isParamSetByUser(const std::string &name) const
Test if the supplied parameter is set by a user, as opposed to not set or set to default.
This class will add subdomains to the entire mesh based on unique normals.
const bool _contiguous_assignments_only
Whether to only use the flood algorithm to group elements, without looking for the previously created...
std::unique_ptr< MeshBase > & _input
the mesh to add the subdomains to
std::vector< subdomain_id_type > _included_subdomain_ids
A list of included subdomain ids that the element has to be priorly a part of, extracted from the 'in...
bool elementSatisfiesRequirements(const Elem *const elem, const Point &desired_normal, const Elem &base_elem, const Point &face_normal) const
Determines whether the given element satisfies a set of criteria that are defined in this base class...