https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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
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
102std::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,
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 {
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}
boundary_id_type BoundaryID
registerMooseObject("MooseApp", XYTriangleBoundaryLayerGenerator)
void ErrorVector unsigned int
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
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 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...
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 addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
MeshGenerators are objects that can modify or add to an existing mesh.
MooseMesh *const _mesh
Pointer to the owning mesh.
static InputParameters validParams()
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition MooseEnum.h:55
void allowRemoteElementRemoval(bool allow_removal)
Set whether to allow remote element removal.
Definition MooseMesh.C:4046
Generate a 2D layered mesh that represents a conformal boundary layer along the boundary of an input ...
BoundaryLayerDirection
Whether the boundary layer is grown outward or inward with respect to the input boundary.
const bool _keep_input
Whether to keep the input mesh in the final output (stitched to the boundary layer)
const std::vector< BoundaryName > _boundary_names
Optional subset of boundary names on the input mesh that define the seed boundary.
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
const BoundaryName _interface_name
Optional boundary name for the interface between the generated boundary layer and the input mesh.
std::unique_ptr< MeshBase > & _input
Input mesh defining the boundary on which to grow the boundary layer.
const unsigned int _num_layers
Number of element layers in the boundary layer.
const SubdomainID _output_subdomain_id
Optional subdomain id for the generated boundary layer.
const MooseEnum _tri_elem_type
Triangular element type for the boundary layer.
const BoundaryName _surface_name
Optional boundary name for the outer surface of the generated boundary layer.
const Real _thickness
The total thickness of the boundary layer to be created.
enum XYTriangleBoundaryLayerGenerator::BoundaryLayerDirection _boundary_layer_direction
const Real _layer_bias
Bias factor for the thickness of each layer.
const SubdomainName _subdomain_name
Optional subdomain name for the generated boundary layer.
XYTriangleBoundaryLayerGenerator(const InputParameters &parameters)
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
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...
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.
void addExternalBoundary(MeshBase &mesh, const BoundaryID extern_bid, bool &has_external_bid)
Adds a sideset for the external boundary of the mesh (e.g.
void change_boundary_id(MeshBase &mesh, const boundary_id_type old_id, const boundary_id_type new_id)