Line data Source code
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 "MeshExtruderGenerator.h"
11 : #include "MooseMeshUtils.h"
12 : #include "CastUniquePointer.h"
13 :
14 : #include "libmesh/replicated_mesh.h"
15 : #include "libmesh/boundary_info.h"
16 : #include "libmesh/elem.h"
17 :
18 : registerMooseObjectDeprecated("MooseApp", MeshExtruderGenerator, "12/31/2025 24:00");
19 :
20 : InputParameters
21 14839 : MeshExtruderGenerator::validParams()
22 : {
23 14839 : InputParameters params = MeshGenerator::validParams();
24 :
25 14839 : params.addRequiredParam<MeshGeneratorName>("input", "the mesh we want to extrude");
26 14839 : params.addClassDescription("Takes a 1D or 2D mesh and extrudes the entire structure along the "
27 : "specified axis increasing the dimensionality of the mesh.");
28 14839 : params.addRequiredParam<RealVectorValue>("extrusion_vector",
29 : "The direction and length of the extrusion");
30 14839 : params.addParam<unsigned int>("num_layers", 1, "The number of layers in the extruded mesh");
31 14839 : params.addParam<std::vector<BoundaryName>>(
32 : "bottom_sideset", "The boundary that will be applied to the bottom of the extruded mesh");
33 14839 : params.addParam<std::vector<BoundaryName>>(
34 : "top_sideset", "The boundary that will be to the top of the extruded mesh");
35 :
36 44517 : params.addParam<std::vector<SubdomainID>>(
37 : "existing_subdomains",
38 29678 : std::vector<SubdomainID>(),
39 : "The subdomains that will be remapped for specific layers");
40 44517 : params.addParam<std::vector<unsigned int>>(
41 : "layers",
42 29678 : std::vector<unsigned int>(),
43 : "The layers where the \"existing_subdomain\" will be remapped to new ids");
44 44517 : params.addParam<std::vector<unsigned int>>(
45 : "new_ids",
46 29678 : std::vector<unsigned int>(),
47 : "The list of new ids, This list should be either length \"existing_subdomains\" or "
48 : "\"existing_subdomains\" * layers");
49 :
50 14839 : return params;
51 0 : }
52 :
53 287 : MeshExtruderGenerator::MeshExtruderGenerator(const InputParameters & parameters)
54 : : MeshGenerator(parameters),
55 287 : _input(getMesh("input")),
56 287 : _extrusion_vector(getParam<RealVectorValue>("extrusion_vector")),
57 287 : _num_layers(getParam<unsigned int>("num_layers")),
58 287 : _existing_subdomains(getParam<std::vector<SubdomainID>>("existing_subdomains")),
59 287 : _layers(getParam<std::vector<unsigned int>>("layers")),
60 574 : _new_ids(getParam<std::vector<unsigned int>>("new_ids"))
61 : {
62 : // Check the length of the vectors
63 301 : if (_existing_subdomains.size() != _new_ids.size() &&
64 14 : _existing_subdomains.size() * _layers.size() != _new_ids.size())
65 0 : mooseError(
66 : "The length of the \"existing_subdomains\", \"layers\", and \"new_ids\" are not valid");
67 287 : }
68 :
69 : std::unique_ptr<MeshBase>
70 274 : MeshExtruderGenerator::generate()
71 : {
72 274 : std::unique_ptr<MeshBase> source_mesh = std::move(_input);
73 :
74 274 : auto dest_mesh = buildMeshBaseObject();
75 :
76 : // check that the existing_subdomains exist in the mesh
77 342 : for (const auto & id : _existing_subdomains)
78 72 : if (!MooseMeshUtils::hasSubdomainID(*source_mesh, id))
79 4 : paramError("existing_subdomains", "The block ID '", id, "' was not found in the mesh");
80 :
81 270 : if (source_mesh->mesh_dimension() == 3)
82 0 : mooseError("You cannot extrude a 3D mesh !");
83 :
84 270 : std::unique_ptr<QueryElemSubdomainID> elem_subdomain_id;
85 270 : if (_existing_subdomains.size() > 0)
86 20 : elem_subdomain_id = std::make_unique<QueryElemSubdomainID>(
87 20 : _existing_subdomains, _layers, _new_ids, _num_layers);
88 :
89 270 : MeshTools::Generation::build_extrusion(dynamic_cast<libMesh::UnstructuredMesh &>(*dest_mesh),
90 270 : *source_mesh,
91 : _num_layers,
92 : _extrusion_vector,
93 270 : elem_subdomain_id.get());
94 :
95 : // See if the user has requested specific sides for the top and bottom
96 270 : std::set<boundary_id_type> side_ids = dest_mesh->get_boundary_info().get_side_boundary_ids();
97 :
98 : // Handle distributed meshes: processors may not know all side ids
99 270 : _communicator.set_union(side_ids);
100 :
101 270 : std::set<boundary_id_type>::reverse_iterator last_side_it = side_ids.rbegin();
102 :
103 270 : const boundary_id_type old_top = *last_side_it;
104 : mooseAssert(last_side_it != side_ids.rend(), "Error in generating sidesets for extruded mesh");
105 270 : const boundary_id_type old_bottom = *++last_side_it;
106 :
107 : // Update the IDs
108 270 : if (isParamValid("bottom_sideset"))
109 175 : changeID(*dest_mesh, getParam<std::vector<BoundaryName>>("bottom_sideset"), old_bottom);
110 270 : if (isParamValid("top_sideset"))
111 151 : changeID(*dest_mesh, getParam<std::vector<BoundaryName>>("top_sideset"), old_top);
112 :
113 270 : dest_mesh->set_isnt_prepared();
114 540 : return dynamic_pointer_cast<MeshBase>(dest_mesh);
115 270 : }
116 :
117 : void
118 326 : MeshExtruderGenerator::changeID(MeshBase & mesh,
119 : const std::vector<BoundaryName> & names,
120 : BoundaryID old_id)
121 : {
122 326 : std::vector<boundary_id_type> boundary_ids = MooseMeshUtils::getBoundaryIDs(mesh, names, true);
123 :
124 326 : if (std::find(boundary_ids.begin(), boundary_ids.end(), old_id) == boundary_ids.end())
125 315 : MooseMeshUtils::changeBoundaryId(mesh, old_id, boundary_ids[0], true);
126 :
127 652 : for (unsigned int i = 0; i < boundary_ids.size(); ++i)
128 : {
129 326 : mesh.get_boundary_info().sideset_name(boundary_ids[i]) = names[i];
130 326 : mesh.get_boundary_info().nodeset_name(boundary_ids[i]) = names[i];
131 : }
132 326 : }
133 :
134 20 : MeshExtruderGenerator::QueryElemSubdomainID::QueryElemSubdomainID(
135 : const std::vector<SubdomainID> & existing_subdomains,
136 : std::vector<unsigned int> layers,
137 : const std::vector<unsigned int> & new_ids,
138 20 : unsigned int num_layers)
139 20 : : QueryElemSubdomainIDBase(), _num_layers(num_layers)
140 : {
141 : // Setup our stride depending on whether the user passed unique sets in new ids or just a single
142 : // set of new ids
143 : const unsigned int stride =
144 20 : existing_subdomains.size() == new_ids.size() ? 0 : existing_subdomains.size();
145 :
146 20 : if (layers.size() == 0)
147 0 : for (unsigned int i = 0; i < _num_layers; i++)
148 0 : layers.push_back(i);
149 :
150 : // Populate the data structure
151 80 : for (unsigned int i = 0; i < layers.size(); ++i)
152 240 : for (unsigned int j = 0; j < existing_subdomains.size(); ++j)
153 180 : _layer_data[layers[i]][existing_subdomains[j]] = new_ids[i * stride + j];
154 20 : }
155 :
156 : subdomain_id_type
157 1824 : MeshExtruderGenerator::QueryElemSubdomainID::get_subdomain_for_layer(const Elem * old_elem,
158 : unsigned int layer)
159 : {
160 : mooseAssert(layer < _num_layers, "Access out of bounds: " << layer);
161 :
162 : // First locate the layer if it exists
163 : std::map<unsigned int, std::map<SubdomainID, unsigned int>>::const_iterator layer_it =
164 1824 : _layer_data.find(layer);
165 :
166 1824 : if (layer_it == _layer_data.end())
167 : // If the layer wasn't found, there is no mapping so just return the original subdomain id
168 912 : return old_elem->subdomain_id();
169 : else
170 : {
171 : std::map<SubdomainID, unsigned int>::const_iterator sub_id_it =
172 912 : layer_it->second.find(old_elem->subdomain_id());
173 :
174 912 : if (sub_id_it == layer_it->second.end())
175 : // If the subdomain wasn't found, it won't be remapped, so just return the original subdomain
176 : // id
177 456 : return old_elem->subdomain_id();
178 :
179 : // Return the remapped id
180 456 : return sub_id_it->second;
181 : }
182 : }
|