https://mooseframework.inl.gov
XYTriangleBoundaryLayerGenerator.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 
12 #include "CastUniquePointer.h"
13 #include "MooseMeshUtils.h"
14 #include "BoundaryLayerUtils.h"
15 
16 #include "libmesh/mesh_modification.h"
17 #include "libmesh/mesh_serializer.h"
18 #include "libmesh/unstructured_mesh.h"
19 
21 
24 {
26 
27  params.addRequiredParam<MeshGeneratorName>(
28  "input", "The input mesh based on which to create the conformal boundary layer.");
29  params.addRequiredParam<Real>("thickness",
30  "The total thickness of the boundary layer to be created.");
31  params.addRangeCheckedParam<unsigned int>(
32  "num_layers", 1, "num_layers>0", "The total number of boundary layers to be created.");
33  params.addParam<Real>(
34  "layer_bias",
35  1.0,
36  "The bias factor for the thickness of each layer of elements. A value > 1 leads to thicker "
37  "layers away from the input mesh, while a value < 1 leads to thicker layers close to the "
38  "input mesh. The default value of 1 leads to uniform layer thickness.");
39 
40  MooseEnum boundary_layer_direction("OUTWARD INWARD", "OUTWARD");
41  params.addParam<MooseEnum>(
42  "boundary_layer_direction",
43  boundary_layer_direction,
44  "In which direction the boundary layer is created with respect to the side normal of the "
45  "elements along the boundary of the input mesh.");
46 
47  params.addParam<std::vector<BoundaryName>>(
48  "boundary_names",
49  std::vector<BoundaryName>(),
50  "The names of the boundaries around which the boundary layer will be created.");
51 
52  params.addParam<BoundaryName>("interface_name",
53  "The optional boundary name to be assigned to the interface "
54  "between the generated boundary layer and the input mesh.");
55  params.addParam<BoundaryName>(
56  "surface_name",
57  "The optional boundary name to be assigned to the surface of the generated boundary layer.");
58 
59  params.addParam<SubdomainName>("subdomain_name",
60  "Subdomain name to set for the boundary layer mesh.");
61  params.addParam<SubdomainID>("subdomain_id", "Subdomain id to set for the boundary layer mesh.");
62 
63  MooseEnum tri_elem_type("TRI3 TRI6 TRI7", "TRI3");
64  params.addParam<MooseEnum>("tri_elem_type",
65  tri_elem_type,
66  "The type of triangular elements to use for the boundary layer.");
67 
68  params.addParam<bool>("keep_input",
69  false,
70  "Whether to keep the input mesh in the final output. If false, only the "
71  "boundary layers will be included in the output mesh.");
72 
73  params.addClassDescription(
74  "Generate a 2D layered mesh that represents a conformal boundary layer along "
75  "the boundary of an input 2D mesh or a 1D loop mesh.");
76 
77  return params;
78 }
79 
81  const InputParameters & parameters)
82  : MeshGenerator(parameters),
83  _input(getMesh("input")),
84  _thickness(getParam<Real>("thickness")),
85  _num_layers(getParam<unsigned int>("num_layers")),
86  _layer_bias(getParam<Real>("layer_bias")),
87  _boundary_layer_direction(
88  getParam<MooseEnum>("boundary_layer_direction").template getEnum<BoundaryLayerDirection>()),
89  _boundary_names(getParam<std::vector<BoundaryName>>("boundary_names")),
90  _interface_name(isParamValid("interface_name") ? getParam<BoundaryName>("interface_name")
91  : BoundaryName()),
92  _surface_name(isParamValid("surface_name") ? getParam<BoundaryName>("surface_name")
93  : BoundaryName()),
94  _subdomain_name(isParamValid("subdomain_name") ? getParam<SubdomainName>("subdomain_name")
95  : SubdomainName()),
96  _output_subdomain_id(isParamValid("subdomain_id") ? getParam<SubdomainID>("subdomain_id") : 0),
97  _tri_elem_type(parameters.get<MooseEnum>("tri_elem_type")),
98  _keep_input(getParam<bool>("keep_input"))
99 {
100 }
101 
102 std::unique_ptr<MeshBase>
104 {
106 
107  // The MeshGenerator system requires that the input mesh be moved out of its unique_ptr during
108  // generate(). Move it now; when keep_input is false the local unique_ptr is simply dropped at
109  // the end, when keep_input is true we stitch from this local pointer.
110  std::unique_ptr<MeshBase> input_mesh = std::move(_input);
111 
113  *input_mesh,
115  _num_layers,
116  _thickness,
117  _layer_bias,
118  outward,
122 
123  // The ring carries boundary ids 0 ... 2*num_layers - 1; the innermost is bcid 1 and the
124  // outermost is bcid (num_layers - 1) * 2. The "interface" side (touching the input mesh) is the
125  // innermost for outward layers and the outermost for inward layers; the "surface" side (away
126  // from the input mesh) is the opposite.
127  const boundary_id_type ring_innermost = 1;
128  const boundary_id_type ring_outermost = boundary_id_type((_num_layers - 1) * 2);
129  const boundary_id_type interface_bid = outward ? ring_innermost : ring_outermost;
130  const boundary_id_type surface_bid = outward ? ring_outermost : ring_innermost;
131 
132  if (_keep_input)
133  {
134  auto & ring_u = dynamic_cast<libMesh::UnstructuredMesh &>(*ring);
135  auto & inp_u = dynamic_cast<libMesh::UnstructuredMesh &>(*input_mesh);
136  if (!ring_u.is_prepared())
137  ring_u.prepare_for_use();
138  if (!inp_u.is_prepared())
139  inp_u.prepare_for_use();
140  // Avoid bcid overlap between ring and input; renumber input's bcids out of the ring's range.
141  const auto ring_bids = ring_u.get_boundary_info().get_global_boundary_ids();
142  const auto inp_bids = inp_u.get_boundary_info().get_global_boundary_ids();
143  const auto max_bid = std::max(ring_bids.empty() ? boundary_id_type(0) : *ring_bids.rbegin(),
144  inp_bids.empty() ? boundary_id_type(0) : *inp_bids.rbegin());
145  BoundaryID ext_id = 1;
146  bool overlap = false;
147  for (auto b : inp_bids)
148  if (ring_bids.count(b))
149  overlap = true;
150  if (overlap)
151  {
152  BoundaryID idx = 1;
153  for (auto b : inp_bids)
154  inp_u.get_boundary_info().renumber_id(b, max_bid + (idx++));
155  ext_id = max_bid + idx;
156  }
157  else
158  ext_id = max_bid + 1;
159  inp_u.comm().max(ext_id);
160  bool has_ext = false;
161  MooseMeshUtils::addExternalBoundary(inp_u, ext_id, has_ext);
162  mooseAssert(has_ext, "A 2D-XY mesh should have an external boundary.");
163  libMesh::MeshSerializer s1(ring_u), s2(inp_u);
164  // Stitch at the side of the ring that physically touches the input boundary. Keep the
165  // interface_bid tag so the interface boundary survives for downstream naming.
166  ring_u.stitch_meshes(inp_u,
167  interface_bid,
168  ext_id,
169  TOLERANCE,
170  /*clear_stitched_bcids=*/false,
171  /*verbose=*/false,
172  /*use_binary_search=*/true,
173  /*enforce_all_nodes_match_on_boundaries=*/false,
174  /*merge_boundary_nodes_all_or_nothing=*/false,
175  /*remap_subdomain_ids=*/false);
176  }
177 
178  auto & bi = ring->get_boundary_info();
179  // Delete the interface/surface if not requested to retain
180  if (_interface_name.empty())
181  bi.remove_id(interface_bid);
182  if (_surface_name.empty())
183  bi.remove_id(surface_bid);
184 
185  // Apply interface_name / surface_name. The interface and surface bcids may collide with the
186  // user-requested ids; do a two-stage shift to avoid clobbering.
187  bool has_conflict = false;
188  if (!_interface_name.empty())
189  {
190  const auto interface_user_bcid =
191  MooseMeshUtils::getBoundaryIDs(*ring, {_interface_name}, true).front();
192  if (interface_user_bcid == surface_bid && !_surface_name.empty())
193  {
194  libMesh::MeshTools::Modification::change_boundary_id(*ring, surface_bid, 10001);
195  has_conflict = true;
196  }
197  libMesh::MeshTools::Modification::change_boundary_id(*ring, interface_bid, interface_user_bcid);
198  bi.sideset_name(interface_user_bcid) = _interface_name;
199  }
200  if (!_surface_name.empty())
201  {
202  const auto surface_user_bcid =
203  MooseMeshUtils::getBoundaryIDs(*ring, {_surface_name}, true).front();
205  *ring, has_conflict ? boundary_id_type(10001) : surface_bid, surface_user_bcid);
206  bi.sideset_name(surface_user_bcid) = _surface_name;
207  }
208 
209  // Match the parent MooseMesh's remote-element-removal setting so SetupMeshAction's sync check
210  // passes when the user uses the mesh in contexts (e.g. boundary postprocessors) that flip this
211  // flag on MooseMesh before the mesh is set.
212  ring->allow_remote_element_removal(_mesh->allowRemoteElementRemoval());
213  ring->unset_is_prepared();
214  return ring;
215 }
const std::vector< BoundaryName > _boundary_names
Optional subset of boundary names on the input mesh that define the seed boundary.
const Real _layer_bias
Bias factor for the thickness of each layer.
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
registerMooseObject("MooseApp", XYTriangleBoundaryLayerGenerator)
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
const BoundaryName _interface_name
Optional boundary name for the interface between the generated boundary layer and the input mesh...
const unsigned int _num_layers
Number of element layers in the boundary layer.
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...
auto max(const L &left, const R &right)
void allowRemoteElementRemoval(bool allow_removal)
Set whether to allow remote element removal.
Definition: MooseMesh.C:4094
MooseMesh *const _mesh
Pointer to the owning mesh.
enum XYTriangleBoundaryLayerGenerator::BoundaryLayerDirection _boundary_layer_direction
const Real _thickness
The total thickness of the boundary layer to be created.
const MooseEnum _tri_elem_type
Triangular element type for the boundary layer.
int8_t boundary_id_type
BoundaryLayerDirection
Whether the boundary layer is grown outward or inward with respect to the input boundary.
boundary_id_type BoundaryID
const bool _keep_input
Whether to keep the input mesh in the final output (stitched to the boundary layer) ...
void change_boundary_id(MeshBase &mesh, const boundary_id_type old_id, const boundary_id_type new_id)
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition: MooseEnum.h:54
std::vector< BoundaryID > getBoundaryIDs(const libMesh::MeshBase &mesh, const std::vector< BoundaryName > &boundary_name, bool generate_unknown, const std::set< BoundaryID > &mesh_boundary_ids)
Gets the boundary IDs with their names.
static InputParameters validParams()
Definition: MeshGenerator.C:23
std::unique_ptr< MeshBase > & _input
Input mesh defining the boundary on which to grow the boundary layer.
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
const SubdomainName _subdomain_name
Optional subdomain name for the generated boundary layer.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const BoundaryName _surface_name
Optional boundary name for the outer surface of the generated boundary layer.
const SubdomainID _output_subdomain_id
Optional subdomain id for the generated boundary layer.
Generate a 2D layered mesh that represents a conformal boundary layer along the boundary of an input ...
XYTriangleBoundaryLayerGenerator(const InputParameters &parameters)
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...
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
std::unique_ptr< MeshBase > buildBoundaryLayerRing(MeshGenerator &mg, MeshBase &input_mesh, const std::vector< BoundaryName > &boundary_names, unsigned int num_layers, Real thickness, Real layer_bias, bool outward, const MooseEnum &tri_elem_type, SubdomainID output_subdomain_id, const SubdomainName &output_subdomain_name)
Builds a conformal boundary-layer ring of triangulated annuli along a boundary of an input 2D mesh (o...
MeshGenerators are objects that can modify or add to an existing mesh.
Definition: MeshGenerator.h:33
void ErrorVector unsigned int
const Elem & get(const ElemType type_in)
unsigned int idx(const ElemType type, const unsigned int nx, const unsigned int i, const unsigned int j)
void addExternalBoundary(MeshBase &mesh, const BoundaryID extern_bid, bool &has_external_bid)
Adds a sideset for the external boundary of the mesh (e.g.