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();
92 ") does not exist in the mesh.");
98 boundary_mesh->set_mesh_dimension(
mesh->mesh_dimension() - 1);
99 boundary_mesh->set_spatial_dimension(
mesh->mesh_dimension());
102 std::vector<Node *> boundary_nodes;
105 std::map<dof_id_type, dof_id_type> mesh_node_id_to_boundary_node_id;
110 std::map<dof_id_type, std::tuple<dof_id_type, unsigned short int, boundary_id_type>>
111 boundary_elem_to_mesh_elem;
112 for (
auto & side : side_list)
117 const Elem * elem =
mesh->elem_ptr(std::get<0>(side));
120 std::unique_ptr<const Elem> boundary_elem = elem->side_ptr(std::get<1>(side));
123 std::vector<dof_id_type> bnd_elem_node_ids(boundary_elem->n_nodes());
126 for (MooseIndex(boundary_elem->n_nodes())
j = 0;
j < boundary_elem->n_nodes(); ++
j)
128 const Node * node = boundary_elem->node_ptr(
j);
131 if (mesh_node_id_to_boundary_node_id.find(node->id()) ==
132 mesh_node_id_to_boundary_node_id.end())
135 mesh_node_id_to_boundary_node_id.insert(
136 std::pair<dof_id_type, dof_id_type>(node->id(), boundary_node_id));
141 boundary_nodes.push_back(boundary_mesh->add_point(pt, boundary_node_id));
144 bnd_elem_node_ids[
j] = boundary_node_id;
150 bnd_elem_node_ids[
j] = mesh_node_id_to_boundary_node_id.find(node->id())->second;
158 boundary_elem_to_mesh_elem.insert(
159 std::pair<
dof_id_type, std::tuple<dof_id_type, unsigned short int, boundary_id_type>>(
160 new_bnd_elem->id(), side));
165 for (MooseIndex(boundary_elem->n_nodes())
j = 0;
j < boundary_elem->n_nodes(); ++
j)
167 dof_id_type old_node_id = boundary_elem->node_ptr(
j)->id();
168 if (mesh_node_id_to_boundary_node_id.find(old_node_id) ==
169 mesh_node_id_to_boundary_node_id.end())
170 mooseError(
"Node id", old_node_id,
" not linked to new node id.");
171 dof_id_type new_node_id = mesh_node_id_to_boundary_node_id.find(old_node_id)->second;
172 new_bnd_elem->set_node(
j, boundary_nodes[new_node_id]);
178 boundary_mesh->prepare_for_use();
184 auto partitioner_enum = getParam<MooseEnum>(
"partitioner");
193 std::vector<BoundaryName> sideset_names =
196 std::vector<boundary_id_type> boundary_ids =
199 mooseAssert(sideset_names.size() ==
_n_patches,
200 "sideset_names must have as many entries as user-requested number of patches.");
201 mooseAssert(boundary_ids.size() ==
_n_patches,
202 "boundary_ids must have as many entries as user-requested number of patches.");
206 for (
const auto & elem : boundary_mesh->active_element_ptr_range())
208 if (boundary_elem_to_mesh_elem.find(elem->id()) == boundary_elem_to_mesh_elem.end())
209 mooseError(
"Element in the boundary mesh with id ",
211 " not found in boundary_elem_to_mesh_elem.");
213 auto side = boundary_elem_to_mesh_elem.find(elem->id())->second;
215 mooseAssert(elem->processor_id() < boundary_ids.size(),
216 "Processor id larger than number of patches.");
217 boundary_info.add_side(
218 std::get<0>(side), std::get<1>(side), boundary_ids[elem->processor_id()]);
222 for (MooseIndex(boundary_ids.size())
j = 0;
j < boundary_ids.size(); ++
j)
224 boundary_info.sideset_name(boundary_ids[
j]) = sideset_names[
j];
225 boundary_info.nodeset_name(boundary_ids[
j]) = sideset_names[
j];
237 auto bounding_box = MeshTools::create_bounding_box(
mesh);
238 const auto &
min = bounding_box.min();
239 const auto &
max = bounding_box.max();
243 std::vector<unsigned int> nelems(3);
247 unsigned int largest_id = 0;
249 for (
unsigned int j = 1;
j < 3; ++
j)
263 unsigned int smallest_id = 0;
265 for (
unsigned int j = 1;
j < 3; ++
j)
273 unsigned int id1 = 1, id2 = 2;
274 if (smallest_id == 1)
276 else if (smallest_id == 2)
280 nelems[smallest_id] = 1;
283 unsigned int final_n_patches = nelems[id1] * nelems[id2];
289 _console <<
"Note: For creating radiation patches for boundary " <<
_sideset 290 <<
" using grid partitioner number of patches was changed from " <<
_n_patches 291 <<
" to " << final_n_patches << std::endl;
299 for (
auto & elem_ptr :
mesh.active_element_ptr_range())
301 const Point centroid = elem_ptr->vertex_average();
303 const unsigned int ix = std::floor((centroid(0) -
min(0)) / dx);
304 const unsigned int iy = std::floor((centroid(1) -
min(1)) / dy);
305 const unsigned int iz = std::floor((centroid(2) -
min(2)) / dz);
306 proc_id = ix + iy * nelems[0] + iz * nelems[0] * nelems[1];
307 elem_ptr->processor_id() = proc_id;
317 std::set<processor_id_type> processor_ids;
318 for (
auto & elem_ptr :
mesh.active_element_ptr_range())
319 processor_ids.insert(elem_ptr->processor_id());
327 <<
" are empty. Adjusting number of patches from " <<
_n_patches <<
" to " 328 << processor_ids.size() << std::endl;
332 std::vector<processor_id_type> processor_ids_vec;
333 for (
auto &
p : processor_ids)
334 processor_ids_vec.push_back(
p);
335 std::sort(processor_ids_vec.begin(), processor_ids_vec.end());
338 std::map<processor_id_type, processor_id_type> processor_id_remap;
339 for (MooseIndex(processor_ids_vec.size())
j = 0;
j < processor_ids_vec.size(); ++
j)
340 processor_id_remap[processor_ids_vec[
j]] =
j;
342 for (
auto & elem_ptr :
mesh.active_element_ptr_range())
345 const auto & it = processor_id_remap.find(
p);
346 if (it == processor_id_remap.end())
347 mooseError(
"Parition id ",
p,
" not in processor_id_remap.");
348 elem_ptr->processor_id() = it->second;
352 std::vector<BoundaryName>
355 std::vector<BoundaryName> rv;
358 std::stringstream ss;
359 ss << base_name <<
"_" <<
j;
360 rv.push_back(ss.str());
370 return mesh.add_elem(std::move(elem));
372 mooseError(
"Unsupported element type (libMesh elem_type enum): ",
type);
unsigned int _dim
dimensionality of the sidesets to partition
const InputParameters & _pars
std::unique_ptr< ReplicatedMesh > buildReplicatedMesh(unsigned int dim=libMesh::invalid_uint)
void paramError(const std::string ¶m, Args... args) const
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$.
BoundaryID _sideset
The sideset that will be subdivided.
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
BoundaryID getBoundaryID(const BoundaryName &boundary_name, const MeshBase &mesh)
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)
bool hasBoundaryNameOrID(const MeshBase &mesh, const BoundaryName &name_or_id)
static InputParameters validParams()
const BoundaryName & _sideset_name
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
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