https://mooseframework.inl.gov
MeshRepairGenerator.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 
10 #include "MeshRepairGenerator.h"
11 #include "CastUniquePointer.h"
12 #include "MooseMeshUtils.h"
13 
14 #include "libmesh/mesh_tools.h"
15 #include "libmesh/mesh_modification.h"
16 
18 
21 {
22 
24  params.addClassDescription(
25  "Mesh generator to perform various improvement / fixing operations on an input mesh");
26  params.addRequiredParam<MeshGeneratorName>("input",
27  "Name of the mesh generator providing the mesh");
28 
29  params.addParam<bool>("fix_node_overlap", false, "Whether to merge overlapping nodes");
30  params.addParam<Real>(
31  "node_overlap_tol", 1e-8, "Absolute tolerance for merging overlapping nodes");
32 
33  params.addParam<bool>(
34  "fix_elements_orientation", false, "Whether to flip elements with negative volumes");
35 
36  params.addParam<bool>("separate_blocks_by_element_types",
37  false,
38  "Create new blocks if multiple element types are present in a block");
39 
40  params.addParam<bool>("merge_boundary_ids_with_same_name",
41  false,
42  "Merge boundaries if they have the same name but different boundary IDs");
43 
44  return params;
45 }
46 
48  : MeshGenerator(parameters),
49  _input(getMesh("input")),
50  _fix_overlapping_nodes(getParam<bool>("fix_node_overlap")),
51  _node_overlap_tol(getParam<Real>("node_overlap_tol")),
52  _fix_element_orientation(getParam<bool>("fix_elements_orientation")),
53  _elem_type_separation(getParam<bool>("separate_blocks_by_element_types")),
54  _boundary_id_merge(getParam<bool>("merge_boundary_ids_with_same_name"))
55 {
58  mooseError("No specific item to fix. Are any of the parameters misspelled?");
59 }
60 
61 std::unique_ptr<MeshBase>
63 {
64  std::unique_ptr<MeshBase> mesh = std::move(_input);
65  mesh->prepare_for_use();
66 
67  // Blanket ban on distributed. This can be relaxed for some operations if needed
68  if (!mesh->is_serial())
69  mooseError("MeshRepairGenerator requires a serial mesh. The mesh should not be distributed.");
70 
73 
74  // Flip orientation of elements to keep positive volumes
76  MeshTools::Modification::orient_elements(*mesh);
77 
78  // Disambiguate any block that has elements of multiple types
81 
82  // Assign a single boundary ID to boundaries that have the same name
85 
86  mesh->set_isnt_prepared();
87  return mesh;
88 }
89 
90 void
91 MeshRepairGenerator::fixOverlappingNodes(std::unique_ptr<MeshBase> & mesh) const
92 {
93  unsigned int num_fixed_nodes = 0;
94  auto pl = mesh->sub_point_locator();
95  pl->set_close_to_point_tol(_node_overlap_tol);
96 
97  std::unordered_set<dof_id_type> nodes_removed;
98  // loop on nodes
99  for (auto & node : mesh->node_ptr_range())
100  {
101  // this node has already been removed
102  if (nodes_removed.count(node->id()))
103  continue;
104 
105  // find all the elements around this node
106  std::set<const Elem *> elements;
107  (*pl)(*node, elements);
108 
109  for (auto & elem : elements)
110  {
111  bool found = false;
112  for (auto & elem_node : elem->node_ref_range())
113  {
114  if (node->id() == elem_node.id())
115  {
116  found = true;
117  break;
118  }
119  }
120  if (!found)
121  {
122  for (auto & elem_node : elem->node_ref_range())
123  {
124  if (elem_node.id() == node->id())
125  continue;
126  const Real tol = _node_overlap_tol;
127  // Compares the coordinates
128  const auto x_node = (*node)(0);
129  const auto x_elem_node = elem_node(0);
130  const auto y_node = (*node)(1);
131  const auto y_elem_node = elem_node(1);
132  const auto z_node = (*node)(2);
133  const auto z_elem_node = elem_node(2);
134 
135  if (MooseUtils::absoluteFuzzyEqual(x_node, x_elem_node, tol) &&
136  MooseUtils::absoluteFuzzyEqual(y_node, y_elem_node, tol) &&
137  MooseUtils::absoluteFuzzyEqual(z_node, z_elem_node, tol))
138  {
139  // Merging two nodes from the same element is almost never a good idea
140  if (elem->get_node_index(node) != libMesh::invalid_uint)
141  {
142  _console << "Two overlapping nodes in element " << elem->id() << " right by "
143  << elem->vertex_average() << ".\n They will not be stitched" << std::endl;
144  continue;
145  }
146 
147  // Coordinates are the same but it's not the same node
148  // Replace the node in the element
149  const_cast<Elem *>(elem)->set_node(elem->get_node_index(&elem_node), node);
150  nodes_removed.insert(elem_node.id());
151 
152  num_fixed_nodes++;
153  if (num_fixed_nodes < 10)
154  _console << "Stitching nodes " << *node << " and " << elem_node
155  << std::endl;
156  else if (num_fixed_nodes == 10)
157  _console << "Node stitching will now proceed silently." << std::endl;
158  }
159  }
160  }
161  }
162  }
163  _console << "Number of overlapping nodes which got merged: " << num_fixed_nodes << std::endl;
164  if (mesh->allow_renumbering())
165  mesh->renumber_nodes_and_elements();
166  else
167  {
168  mesh->remove_orphaned_nodes();
169  mesh->update_parallel_id_counts();
170  }
171 }
172 
173 void
174 MeshRepairGenerator::separateSubdomainsByElementType(std::unique_ptr<MeshBase> & mesh) const
175 {
176  std::set<subdomain_id_type> ids;
177  mesh->subdomain_ids(ids);
178  // loop on sub-domain
179  for (const auto id : ids)
180  {
181  // Gather all the element types and blocks
182  // ElemType defines an enum for geometric element types
183  std::set<ElemType> types;
184  // loop on elements within this sub-domain
185  for (auto & elem : mesh->active_subdomain_elements_ptr_range(id))
186  types.insert(elem->type());
187 
188  // This call must be performed on all processes
189  auto next_block_id = MooseMeshUtils::getNextFreeSubdomainID(*mesh);
190 
191  if (types.size() > 1)
192  {
193  subdomain_id_type i = 0;
194  for (const auto type : types)
195  {
196  auto new_id = next_block_id + i++;
197  // Create blocks when a block has multiple element types
198  mesh->subdomain_name(new_id) = mesh->subdomain_name(id) + "_" + Moose::stringify(type);
199 
200  // Re-assign elements to the new blocks
201  for (auto elem : mesh->active_subdomain_elements_ptr_range(id))
202  if (elem->type() == type)
203  elem->subdomain_id() = new_id;
204  }
205  }
206  }
207 }
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
bool absoluteFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
Function to check whether two variables are equal within an absolute tolerance.
Definition: MooseUtils.h:380
const unsigned int invalid_uint
Mesh generator to perform various improvement / fixing operations on an input mesh.
MeshBase & mesh
registerMooseObject("MooseApp", MeshRepairGenerator)
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
void fixOverlappingNodes(std::unique_ptr< MeshBase > &mesh) const
Removes nodes that overlap.
const bool _boundary_id_merge
Whether to merge boundaries with the same name but different ID.
void addRequiredParam(const std::string &name, const std::string &doc_string)
This method adds a parameter and documentation string to the InputParameters object that will be extr...
const bool _elem_type_separation
whether to split subdomains using each element&#39;s type
const bool _fix_overlapping_nodes
fixing mesh by deleting overlapping nodes
const std::string & type() const
Get the type of this class.
Definition: MooseBase.h:51
void separateSubdomainsByElementType(std::unique_ptr< MeshBase > &mesh) const
Separate subdomain by element type because some output format (Exodus) do not support mixed element t...
static InputParameters validParams()
Definition: MeshGenerator.C:23
std::string stringify(const T &t)
conversion to string
Definition: Conversion.h:64
const bool _fix_element_orientation
whether to flip element orientation such that they no longer have a negative volume ...
std::unique_ptr< MeshBase > & _input
the input mesh
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const Real _node_overlap_tol
tolerance for merging overlapping nodes
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type.
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump...
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object...
const ConsoleStream _console
An instance of helper class to write streams to the Console objects.
void mergeBoundaryIDsWithSameName(MeshBase &mesh)
Merges the boundary IDs of boundaries that have the same names but different IDs. ...
SubdomainID getNextFreeSubdomainID(MeshBase &input_mesh)
Checks input mesh and returns max(block ID) + 1, which represents a block ID that is not currently in...
MeshGenerators are objects that can modify or add to an existing mesh.
Definition: MeshGenerator.h:32
MeshRepairGenerator(const InputParameters &parameters)
static InputParameters validParams()