17 #include "libmesh/distributed_mesh.h" 18 #include "libmesh/elem.h" 19 #include "libmesh/linear_partitioner.h" 20 #include "libmesh/centroid_partitioner.h" 21 #include "libmesh/parmetis_partitioner.h" 22 #include "libmesh/hilbert_sfc_partitioner.h" 23 #include "libmesh/morton_sfc_partitioner.h" 24 #include "libmesh/enum_elem_type.h" 28 #include "libmesh/mesh_tools.h" 37 params.
addRequiredParam<MeshGeneratorName>(
"input",
"The mesh we want to modify");
39 "The boundary that will be divided into patches");
41 "n_patches",
"n_patches>0",
"Number of patches");
44 partitioning +=
"grid";
48 "Specifies a mesh partitioner to use when splitting the mesh for a parallel computation.");
53 "Specifies the sort direction if using the centroid partitioner. " 54 "Available options: x, y, z, radial");
59 "Divides the given sideset into smaller patches of roughly equal size.");
67 _n_patches(getParam<unsigned
int>(
"n_patches")),
68 _sideset_name(getParam<BoundaryName>(
"boundary")),
69 _partitioner_name(getParam<
MooseEnum>(
"partitioner"))
73 std::unique_ptr<MeshBase>
76 std::unique_ptr<MeshBase>
mesh = std::move(
_input);
81 BoundaryInfo & boundary_info =
mesh->get_boundary_info();
87 auto side_list = boundary_info.build_active_side_list();
99 if (
_sideset == BoundaryInfo::invalid_id)
100 paramError(
"sideset_name",
"Not a valid boundary");
104 boundary_mesh->set_mesh_dimension(
mesh->mesh_dimension() - 1);
105 boundary_mesh->set_spatial_dimension(
mesh->mesh_dimension());
108 std::vector<Node *> boundary_nodes;
111 std::map<dof_id_type, dof_id_type> mesh_node_id_to_boundary_node_id;
116 std::map<dof_id_type, std::tuple<dof_id_type, unsigned short int, boundary_id_type>>
117 boundary_elem_to_mesh_elem;
118 for (
auto & side : side_list)
123 const Elem * elem =
mesh->elem_ptr(std::get<0>(side));
126 std::unique_ptr<const Elem> boundary_elem = elem->side_ptr(std::get<1>(side));
129 std::vector<dof_id_type> bnd_elem_node_ids(boundary_elem->n_nodes());
132 for (MooseIndex(boundary_elem->n_nodes())
j = 0;
j < boundary_elem->n_nodes(); ++
j)
134 const Node * node = boundary_elem->node_ptr(
j);
137 if (mesh_node_id_to_boundary_node_id.find(node->id()) ==
138 mesh_node_id_to_boundary_node_id.end())
141 mesh_node_id_to_boundary_node_id.insert(
142 std::pair<dof_id_type, dof_id_type>(node->id(), boundary_node_id));
147 boundary_nodes.push_back(boundary_mesh->add_point(pt, boundary_node_id));
150 bnd_elem_node_ids[
j] = boundary_node_id;
156 bnd_elem_node_ids[
j] = mesh_node_id_to_boundary_node_id.find(node->id())->second;
164 boundary_elem_to_mesh_elem.insert(
165 std::pair<
dof_id_type, std::tuple<dof_id_type, unsigned short int, boundary_id_type>>(
166 new_bnd_elem->id(), side));
171 for (MooseIndex(boundary_elem->n_nodes())
j = 0;
j < boundary_elem->n_nodes(); ++
j)
173 dof_id_type old_node_id = boundary_elem->node_ptr(
j)->id();
174 if (mesh_node_id_to_boundary_node_id.find(old_node_id) ==
175 mesh_node_id_to_boundary_node_id.end())
176 mooseError(
"Node id", old_node_id,
" not linked to new node id.");
177 dof_id_type new_node_id = mesh_node_id_to_boundary_node_id.find(old_node_id)->second;
178 new_bnd_elem->set_node(
j, boundary_nodes[new_node_id]);
184 boundary_mesh->prepare_for_use();
190 auto partitioner_enum = getParam<MooseEnum>(
"partitioner");
199 std::vector<BoundaryName> sideset_names =
202 std::vector<boundary_id_type> boundary_ids =
205 mooseAssert(sideset_names.size() ==
_n_patches,
206 "sideset_names must have as many entries as user-requested number of patches.");
207 mooseAssert(boundary_ids.size() ==
_n_patches,
208 "boundary_ids must have as many entries as user-requested number of patches.");
212 for (
const auto & elem : boundary_mesh->active_element_ptr_range())
214 if (boundary_elem_to_mesh_elem.find(elem->id()) == boundary_elem_to_mesh_elem.end())
215 mooseError(
"Element in the boundary mesh with id ",
217 " not found in boundary_elem_to_mesh_elem.");
219 auto side = boundary_elem_to_mesh_elem.find(elem->id())->second;
221 mooseAssert(elem->processor_id() < boundary_ids.size(),
222 "Processor id larger than number of patches.");
223 boundary_info.add_side(
224 std::get<0>(side), std::get<1>(side), boundary_ids[elem->processor_id()]);
228 for (MooseIndex(boundary_ids.size())
j = 0;
j < boundary_ids.size(); ++
j)
230 boundary_info.sideset_name(boundary_ids[
j]) = sideset_names[
j];
231 boundary_info.nodeset_name(boundary_ids[
j]) = sideset_names[
j];
243 auto bounding_box = MeshTools::create_bounding_box(
mesh);
244 const auto &
min = bounding_box.min();
245 const auto &
max = bounding_box.max();
249 std::vector<unsigned int> nelems(3);
253 unsigned int largest_id = 0;
255 for (
unsigned int j = 1;
j < 3; ++
j)
269 unsigned int smallest_id = 0;
271 for (
unsigned int j = 1;
j < 3; ++
j)
279 unsigned int id1 = 1, id2 = 2;
280 if (smallest_id == 1)
282 else if (smallest_id == 2)
286 nelems[smallest_id] = 1;
289 unsigned int final_n_patches = nelems[id1] * nelems[id2];
295 _console <<
"Note: For creating radiation patches for boundary " <<
_sideset 296 <<
" using grid partitioner number of patches was changed from " <<
_n_patches 297 <<
" to " << final_n_patches << std::endl;
305 for (
auto & elem_ptr :
mesh.active_element_ptr_range())
307 const Point centroid = elem_ptr->vertex_average();
309 const unsigned int ix = std::floor((centroid(0) -
min(0)) / dx);
310 const unsigned int iy = std::floor((centroid(1) -
min(1)) / dy);
311 const unsigned int iz = std::floor((centroid(2) -
min(2)) / dz);
312 proc_id = ix + iy * nelems[0] + iz * nelems[0] * nelems[1];
313 elem_ptr->processor_id() = proc_id;
323 std::set<processor_id_type> processor_ids;
324 for (
auto & elem_ptr :
mesh.active_element_ptr_range())
325 processor_ids.insert(elem_ptr->processor_id());
333 <<
" are empty. Adjusting number of patches from " <<
_n_patches <<
" to " 334 << processor_ids.size() << std::endl;
338 std::vector<processor_id_type> processor_ids_vec;
339 for (
auto & p : processor_ids)
340 processor_ids_vec.push_back(p);
341 std::sort(processor_ids_vec.begin(), processor_ids_vec.end());
344 std::map<processor_id_type, processor_id_type> processor_id_remap;
345 for (MooseIndex(processor_ids_vec.size())
j = 0;
j < processor_ids_vec.size(); ++
j)
346 processor_id_remap[processor_ids_vec[
j]] =
j;
348 for (
auto & elem_ptr :
mesh.active_element_ptr_range())
351 const auto & it = processor_id_remap.find(p);
352 if (it == processor_id_remap.end())
353 mooseError(
"Parition id ", p,
" not in processor_id_remap.");
354 elem_ptr->processor_id() = it->second;
358 std::vector<BoundaryName>
361 std::vector<BoundaryName> rv;
364 std::stringstream ss;
365 ss << base_name <<
"_" <<
j;
366 rv.push_back(ss.str());
376 return mesh.add_elem(std::move(elem));
378 mooseError(
"Unsupported element type (libMesh elem_type enum): ",
type);
unsigned int _dim
dimensionality of the sidesets to partition
std::unique_ptr< ReplicatedMesh > buildReplicatedMesh(unsigned int dim=libMesh::invalid_uint)
T & getMesh(MooseMesh &mesh)
function to cast mesh
static void setPartitioner(MeshBase &mesh_base, MooseEnum &partitioner, bool use_distributed_mesh, const InputParameters ¶ms, MooseObject &context_obj)
std::vector< BoundaryName > sidesetNameHelper(const std::string &base_name) const
returns the name of the _n_patches subdivisions derived from _sideset
Subdivides a sidesets into smaller patches each of which is going to be a new patch.
static InputParameters validParams()
registerMooseObject("HeatTransferApp", PatchSidesetGenerator)
int delta(unsigned int i, unsigned int j)
Delta function, which returns zero if $i j$ and unity if $i=j$.
auto max(const L &left, const R &right)
dof_id_type _n_boundary_mesh_elems
number of elements of the boundary mesh
Elem * boundaryElementHelper(MeshBase &mesh, libMesh::ElemType type) const
void errorIfDistributedMesh(std::string name) const
uint8_t processor_id_type
std::unique_ptr< MeshBase > & _input
MooseEnum _partitioner_name
the name of the partitioner being used
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
const std::string & type() const
PatchSidesetGenerator(const InputParameters ¶meters)
std::vector< BoundaryID > getBoundaryIDs(const libMesh::MeshBase &mesh, const std::vector< BoundaryName > &boundary_name, bool generate_unknown, const std::set< BoundaryID > &mesh_boundary_ids)
void paramError(const std::string ¶m, Args... args) const
static InputParameters validParams()
const BoundaryName & _sideset_name
The sideset that will be subdivided.
subdomain_id_type _sideset
The sideset that will be subdivided.
static MooseEnum partitioning()
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
unsigned int _n_patches
the number of patches that this sideset generator divides _sideset into
void checkPartitionAndCompress(MeshBase &mesh)
Checks partitions and makes sure every partition has at least one elem.
void mooseError(Args &&... args) const
const InputParameters & _pars
void partition(MeshBase &mesh)
a function for implementing custom partitioning
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
const ConsoleStream _console
std::unique_ptr< MeshBase > generate() override
auto min(const L &left, const R &right)
void ErrorVector unsigned int