16 #include "libmesh/mesh_generation.h" 17 #include "libmesh/string_to_enum.h" 18 #include "libmesh/periodic_boundaries.h" 19 #include "libmesh/periodic_boundary_base.h" 20 #include "libmesh/unstructured_mesh.h" 21 #include "libmesh/mesh_communication.h" 22 #include "libmesh/remote_elem.h" 23 #include "libmesh/partitioner.h" 42 "dim", dims,
"The dimension of the mesh to be generated");
47 params.
addParam<
Real>(
"xmin", 0.0,
"Lower X Coordinate of the generated mesh");
48 params.
addParam<
Real>(
"ymin", 0.0,
"Lower Y Coordinate of the generated mesh");
49 params.
addParam<
Real>(
"zmin", 0.0,
"Lower Z Coordinate of the generated mesh");
50 params.
addParam<
Real>(
"xmax", 1.0,
"Upper X Coordinate of the generated mesh");
51 params.
addParam<
Real>(
"ymax", 1.0,
"Upper Y Coordinate of the generated mesh");
52 params.
addParam<
Real>(
"zmax", 1.0,
"Upper Z Coordinate of the generated mesh");
55 "num_cores_for_partition", 0,
"Number of cores for partitioning the graph");
60 "num_side_layers>=1 & num_side_layers<5",
61 "Number of layers of off-processor side neighbors is reserved during mesh generation");
68 rm_params.
set<
unsigned short>(
"layers") =
69 obj_params.
get<
unsigned>(
"num_side_layers");
78 rm_params.
set<
bool>(
"attach_geometric_early") =
false;
81 MooseEnum partition(
"graph linear square",
"graph",
false);
83 "partition", partition,
"Which method (graph linear square) use to partition mesh");
88 "The type of element from libMesh to " 89 "generate (default: linear element for " 90 "requested dimension)");
95 "bias_x>=0.5 & bias_x<=2",
96 "The amount by which to grow (or shrink) the cells in the x-direction.");
100 "bias_y>=0.5 & bias_y<=2",
101 "The amount by which to grow (or shrink) the cells in the y-direction.");
105 "bias_z>=0.5 & bias_z<=2",
106 "The amount by which to grow (or shrink) the cells in the z-direction.");
109 "Create a line, square, or cube mesh with uniformly spaced or biased elements.");
118 _nx(declareMeshProperty(
"num_elements_x", getParam<
dof_id_type>(
"nx"))),
119 _ny(declareMeshProperty(
"num_elements_y", getParam<
dof_id_type>(
"ny"))),
120 _nz(declareMeshProperty(
"num_elements_z", getParam<
dof_id_type>(
"nz"))),
121 _xmin(declareMeshProperty(
"xmin", getParam<
Real>(
"xmin"))),
122 _xmax(declareMeshProperty(
"xmax", getParam<
Real>(
"xmax"))),
123 _ymin(declareMeshProperty(
"ymin", getParam<
Real>(
"ymin"))),
124 _ymax(declareMeshProperty(
"ymax", getParam<
Real>(
"ymax"))),
125 _zmin(declareMeshProperty(
"zmin", getParam<
Real>(
"zmin"))),
126 _zmax(declareMeshProperty(
"zmax", getParam<
Real>(
"zmax"))),
127 _num_cores_for_partition(getParam<
processor_id_type>(
"num_cores_for_partition")),
128 _bias_x(getParam<
Real>(
"bias_x")),
129 _bias_y(getParam<
Real>(
"bias_y")),
130 _bias_z(getParam<
Real>(
"bias_z")),
131 _part_package(getParam<
MooseEnum>(
"part_package")),
132 _num_parts_per_compute_node(getParam<
processor_id_type>(
"num_cores_per_compute_node")),
133 _partition_method(getParam<
MooseEnum>(
"partition")),
134 _num_side_layers(getParam<unsigned>(
"num_side_layers"))
141 DistributedRectilinearMeshGenerator::numNeighbors<Edge2>(
const dof_id_type nx,
149 if (i == 0 || i == nx - 1)
157 DistributedRectilinearMeshGenerator::getNeighbors<Edge2>(
const dof_id_type nx,
163 std::vector<dof_id_type> & neighbors,
171 neighbors[0] = (i - 1 + nx) % nx;
172 neighbors[1] = (i + 1 + nx) % nx;
177 neighbors[0] = i - 1;
178 neighbors[1] = i + 1;
182 neighbors[0] = Elem::invalid_id;
186 neighbors[1] = Elem::invalid_id;
191 DistributedRectilinearMeshGenerator::getIndices<Edge2>(
const dof_id_type ,
203 DistributedRectilinearMeshGenerator::getGhostNeighbors<Edge2>(
207 const MeshBase &
mesh,
208 const std::set<dof_id_type> & current_elems,
209 std::set<dof_id_type> & ghost_elems)
211 std::vector<dof_id_type> neighbors(2);
213 for (
auto elem_id : current_elems)
215 getNeighbors<Edge2>(nx, 0, 0, elem_id, 0, 0, neighbors,
true);
217 for (
auto neighbor : neighbors)
218 if (neighbor != Elem::invalid_id && !
mesh.query_elem_ptr(neighbor))
219 ghost_elems.insert(neighbor);
225 DistributedRectilinearMeshGenerator::elemId<Edge2>(
const dof_id_type ,
236 DistributedRectilinearMeshGenerator::addElement<Edge2>(
const dof_id_type nx,
247 BoundaryInfo & boundary_info =
mesh.get_boundary_info();
249 auto node_offset = elem_id;
251 Node * node0_ptr =
mesh.query_node_ptr(node_offset);
254 std::unique_ptr<Node> new_node =
255 Node::build(Point(static_cast<Real>(node_offset) / nx, 0, 0), node_offset);
257 new_node->set_unique_id(nx + node_offset);
258 new_node->processor_id() = pid;
260 node0_ptr =
mesh.add_node(std::move(new_node));
263 Node * node1_ptr =
mesh.query_node_ptr(node_offset + 1);
266 std::unique_ptr<Node> new_node =
267 Node::build(Point(static_cast<Real>(node_offset + 1) / nx, 0, 0), node_offset + 1);
269 new_node->set_unique_id(nx + node_offset + 1);
270 new_node->processor_id() = pid;
272 node1_ptr =
mesh.add_node(std::move(new_node));
275 Elem * elem =
new Edge2;
276 elem->set_id(elem_id);
277 elem->processor_id() = pid;
278 elem->set_unique_id(elem_id);
279 elem =
mesh.add_elem(elem);
280 elem->set_node(0, node0_ptr);
281 elem->set_node(1, node1_ptr);
284 boundary_info.add_side(elem, 0, 0);
286 if (elem_id == nx - 1)
287 boundary_info.add_side(elem, 1, 1);
292 DistributedRectilinearMeshGenerator::setBoundaryNames<Edge2>(BoundaryInfo & boundary_info)
294 boundary_info.sideset_name(0) =
"left";
295 boundary_info.sideset_name(1) =
"right";
300 DistributedRectilinearMeshGenerator::scaleNodalPositions<Edge2>(
dof_id_type ,
311 for (
auto & node_ptr :
mesh.node_ptr_range())
312 (*node_ptr)(0) = (*node_ptr)(0) * (xmax - xmin) + xmin;
317 DistributedRectilinearMeshGenerator::numNeighbors<Quad4>(
const dof_id_type nx,
343 DistributedRectilinearMeshGenerator::elemId<Quad4>(
const dof_id_type nx,
354 DistributedRectilinearMeshGenerator::getNeighbors<Quad4>(
const dof_id_type nx,
360 std::vector<dof_id_type> & neighbors,
363 std::fill(neighbors.begin(), neighbors.end(), Elem::invalid_id);
372 unsigned int nnb = 0;
373 for (
unsigned int ii = 0; ii <= 2; ii++)
374 for (
unsigned int jj = 0; jj <= 2; jj++)
375 neighbors[nnb++] = elemId<Quad4>(nx, 0, (i + ii - 1 + nx) % nx, (j + jj - 1 + ny) % ny, 0);
381 neighbors[0] = elemId<Quad4>(nx, 0, i, j - 1, 0);
385 neighbors[1] = elemId<Quad4>(nx, 0, i + 1, j, 0);
389 neighbors[2] = elemId<Quad4>(nx, 0, i, j + 1, 0);
393 neighbors[3] = elemId<Quad4>(nx, 0, i - 1, j, 0);
398 DistributedRectilinearMeshGenerator::getIndices<Quad4>(
const dof_id_type nx,
406 j = (elem_id - i) / nx;
411 DistributedRectilinearMeshGenerator::getGhostNeighbors<Quad4>(
415 const MeshBase &
mesh,
416 const std::set<dof_id_type> & current_elems,
417 std::set<dof_id_type> & ghost_elems)
421 std::vector<dof_id_type> neighbors(9);
423 for (
auto elem_id : current_elems)
425 getIndices<Quad4>(nx, 0, elem_id, i, j, k);
427 getNeighbors<Quad4>(nx, ny, 0, i, j, 0, neighbors,
true);
429 for (
auto neighbor : neighbors)
430 if (neighbor != Elem::invalid_id && !
mesh.query_elem_ptr(neighbor))
431 ghost_elems.insert(neighbor);
437 DistributedRectilinearMeshGenerator::nodeId<Quad4>(
const ElemType ,
445 return i + j * (nx + 1);
450 DistributedRectilinearMeshGenerator::addElement<Quad4>(
const dof_id_type nx,
461 BoundaryInfo & boundary_info =
mesh.get_boundary_info();
464 const dof_id_type node0_id = nodeId<Quad4>(type, nx, 0, i, j, 0);
465 Node * node0_ptr =
mesh.query_node_ptr(node0_id);
468 std::unique_ptr<Node> new_node =
469 Node::build(Point(static_cast<Real>(i) / nx, static_cast<Real>(j) / ny, 0), node0_id);
471 new_node->set_unique_id(nx * ny + node0_id);
472 new_node->processor_id() = pid;
474 node0_ptr =
mesh.add_node(std::move(new_node));
478 const dof_id_type node1_id = nodeId<Quad4>(type, nx, 0, i + 1, j, 0);
479 Node * node1_ptr =
mesh.query_node_ptr(node1_id);
482 std::unique_ptr<Node> new_node =
483 Node::build(Point(static_cast<Real>(i + 1) / nx, static_cast<Real>(j) / ny, 0), node1_id);
485 new_node->set_unique_id(nx * ny + node1_id);
486 new_node->processor_id() = pid;
488 node1_ptr =
mesh.add_node(std::move(new_node));
492 const dof_id_type node2_id = nodeId<Quad4>(type, nx, 0, i + 1, j + 1, 0);
493 Node * node2_ptr =
mesh.query_node_ptr(node2_id);
496 std::unique_ptr<Node> new_node = Node::build(
497 Point(static_cast<Real>(i + 1) / nx, static_cast<Real>(j + 1) / ny, 0), node2_id);
499 new_node->set_unique_id(nx * ny + node2_id);
500 new_node->processor_id() = pid;
502 node2_ptr =
mesh.add_node(std::move(new_node));
506 const dof_id_type node3_id = nodeId<Quad4>(type, nx, 0, i, j + 1, 0);
507 Node * node3_ptr =
mesh.query_node_ptr(node3_id);
510 std::unique_ptr<Node> new_node =
511 Node::build(Point(static_cast<Real>(i) / nx, static_cast<Real>(j + 1) / ny, 0), node3_id);
513 new_node->set_unique_id(nx * ny + node3_id);
514 new_node->processor_id() = pid;
516 node3_ptr =
mesh.add_node(std::move(new_node));
519 Elem * elem =
new Quad4;
520 elem->set_id(elem_id);
521 elem->processor_id() = pid;
522 elem->set_unique_id(elem_id);
523 elem =
mesh.add_elem(elem);
524 elem->set_node(0, node0_ptr);
525 elem->set_node(1, node1_ptr);
526 elem->set_node(2, node2_ptr);
527 elem->set_node(3, node3_ptr);
531 boundary_info.add_side(elem, 0, 0);
535 boundary_info.add_side(elem, 1, 1);
539 boundary_info.add_side(elem, 2, 2);
543 boundary_info.add_side(elem, 3, 3);
548 DistributedRectilinearMeshGenerator::setBoundaryNames<Quad4>(BoundaryInfo & boundary_info)
550 boundary_info.sideset_name(0) =
"bottom";
551 boundary_info.sideset_name(1) =
"right";
552 boundary_info.sideset_name(2) =
"top";
553 boundary_info.sideset_name(3) =
"left";
558 DistributedRectilinearMeshGenerator::scaleNodalPositions<Quad4>(
dof_id_type ,
569 for (
auto & node_ptr :
mesh.node_ptr_range())
571 (*node_ptr)(0) = (*node_ptr)(0) * (xmax - xmin) + xmin;
572 (*node_ptr)(1) = (*node_ptr)(1) * (ymax - ymin) + ymin;
578 DistributedRectilinearMeshGenerator::elemId<Hex8>(
const dof_id_type nx,
584 return i + (j * nx) + (k * nx * ny);
589 DistributedRectilinearMeshGenerator::numNeighbors<Hex8>(
const dof_id_type nx,
621 DistributedRectilinearMeshGenerator::getNeighbors<Hex8>(
const dof_id_type nx,
627 std::vector<dof_id_type> & neighbors,
630 std::fill(neighbors.begin(), neighbors.end(), Elem::invalid_id);
639 unsigned int nnb = 0;
640 for (
unsigned int ii = 0; ii <= 2; ii++)
641 for (
unsigned int jj = 0; jj <= 2; jj++)
642 for (
unsigned int kk = 0; kk <= 2; kk++)
643 neighbors[nnb++] = elemId<Hex8>(
644 nx, ny, (i + ii - 1 + nx) % nx, (j + jj - 1 + ny) % ny, (k + kk - 1 + nz) % nz);
651 neighbors[0] = elemId<Hex8>(nx, ny, i, j, k - 1);
655 neighbors[1] = elemId<Hex8>(nx, ny, i, j - 1, k);
659 neighbors[2] = elemId<Hex8>(nx, ny, i + 1, j, k);
663 neighbors[3] = elemId<Hex8>(nx, ny, i, j + 1, k);
667 neighbors[4] = elemId<Hex8>(nx, ny, i - 1, j, k);
671 neighbors[5] = elemId<Hex8>(nx, ny, i, j, k + 1);
676 DistributedRectilinearMeshGenerator::nodeId<Hex8>(
const ElemType ,
683 return i + (nx + 1) * (j + k * (ny + 1));
688 DistributedRectilinearMeshGenerator::addPoint<Hex8>(
const dof_id_type nx,
697 auto id = nodeId<Hex8>(type, nx, ny, i, j, k);
698 Node * node_ptr =
mesh.query_node_ptr(
id);
701 std::unique_ptr<Node> new_node = Node::build(
702 Point(static_cast<Real>(i) / nx, static_cast<Real>(j) / ny, static_cast<Real>(k) / nz),
id);
704 new_node->set_unique_id(nx * ny * nz +
id);
706 node_ptr =
mesh.add_node(std::move(new_node));
714 DistributedRectilinearMeshGenerator::addElement<Hex8>(
const dof_id_type nx,
725 BoundaryInfo & boundary_info =
mesh.get_boundary_info();
728 auto node0_ptr = addPoint<Hex8>(nx, ny, nz, i, j, k, type,
mesh);
729 node0_ptr->processor_id() = pid;
730 auto node1_ptr = addPoint<Hex8>(nx, ny, nz, i + 1, j, k, type,
mesh);
731 node1_ptr->processor_id() = pid;
732 auto node2_ptr = addPoint<Hex8>(nx, ny, nz, i + 1, j + 1, k, type,
mesh);
733 node2_ptr->processor_id() = pid;
734 auto node3_ptr = addPoint<Hex8>(nx, ny, nz, i, j + 1, k, type,
mesh);
735 node3_ptr->processor_id() = pid;
736 auto node4_ptr = addPoint<Hex8>(nx, ny, nz, i, j, k + 1, type,
mesh);
737 node4_ptr->processor_id() = pid;
738 auto node5_ptr = addPoint<Hex8>(nx, ny, nz, i + 1, j, k + 1, type,
mesh);
739 node5_ptr->processor_id() = pid;
740 auto node6_ptr = addPoint<Hex8>(nx, ny, nz, i + 1, j + 1, k + 1, type,
mesh);
741 node6_ptr->processor_id() = pid;
742 auto node7_ptr = addPoint<Hex8>(nx, ny, nz, i, j + 1, k + 1, type,
mesh);
743 node7_ptr->processor_id() = pid;
745 Elem * elem =
new Hex8;
746 elem->set_id(elem_id);
747 elem->processor_id() = pid;
748 elem->set_unique_id(elem_id);
749 elem =
mesh.add_elem(elem);
750 elem->set_node(0, node0_ptr);
751 elem->set_node(1, node1_ptr);
752 elem->set_node(2, node2_ptr);
753 elem->set_node(3, node3_ptr);
754 elem->set_node(4, node4_ptr);
755 elem->set_node(5, node5_ptr);
756 elem->set_node(6, node6_ptr);
757 elem->set_node(7, node7_ptr);
760 boundary_info.add_side(elem, 0, 0);
763 boundary_info.add_side(elem, 5, 5);
766 boundary_info.add_side(elem, 1, 1);
769 boundary_info.add_side(elem, 3, 3);
772 boundary_info.add_side(elem, 4, 4);
775 boundary_info.add_side(elem, 2, 2);
780 DistributedRectilinearMeshGenerator::getIndices<Hex8>(
const dof_id_type nx,
788 j = (((elem_id - i) / nx) % ny);
789 k = ((elem_id - i) - (j * nx)) / (nx * ny);
794 DistributedRectilinearMeshGenerator::getGhostNeighbors<Hex8>(
798 const MeshBase &
mesh,
799 const std::set<dof_id_type> & current_elems,
800 std::set<dof_id_type> & ghost_elems)
804 std::vector<dof_id_type> neighbors(27);
806 for (
auto elem_id : current_elems)
808 getIndices<Hex8>(nx, ny, elem_id, i, j, k);
810 getNeighbors<Hex8>(nx, ny, nz, i, j, k, neighbors,
true);
812 for (
auto neighbor : neighbors)
813 if (neighbor != Elem::invalid_id && !
mesh.query_elem_ptr(neighbor))
814 ghost_elems.insert(neighbor);
820 DistributedRectilinearMeshGenerator::setBoundaryNames<Hex8>(BoundaryInfo & boundary_info)
822 boundary_info.sideset_name(0) =
"back";
823 boundary_info.sideset_name(1) =
"bottom";
824 boundary_info.sideset_name(2) =
"right";
825 boundary_info.sideset_name(3) =
"top";
826 boundary_info.sideset_name(4) =
"left";
827 boundary_info.sideset_name(5) =
"front";
832 DistributedRectilinearMeshGenerator::scaleNodalPositions<Hex8>(
dof_id_type ,
843 for (
auto & node_ptr :
mesh.node_ptr_range())
845 (*node_ptr)(0) = (*node_ptr)(0) * (xmax - xmin) + xmin;
846 (*node_ptr)(1) = (*node_ptr)(1) * (ymax - ymin) + ymin;
847 (*node_ptr)(2) = (*node_ptr)(2) * (zmax - zmin) + zmin;
853 DistributedRectilinearMeshGenerator::paritionSquarely<Edge2>(
const dof_id_type nx,
857 std::vector<dof_id_type> & istarts,
858 std::vector<dof_id_type> & jstarts,
859 std::vector<dof_id_type> & kstarts)
862 istarts.resize(num_procs + 1);
877 istarts[pid + 1] = istarts[pid] + (nx / num_procs + ((nx % num_procs) > pid));
882 DistributedRectilinearMeshGenerator::paritionSquarely<Quad4>(
const dof_id_type nx,
886 std::vector<dof_id_type> & istarts,
887 std::vector<dof_id_type> & jstarts,
888 std::vector<dof_id_type> & kstarts)
904 if (py * px == num_procs)
909 if (nx > ny && py < px)
913 istarts.resize(px + 1);
915 jstarts.resize(py + 1);
925 istarts[pxid + 1] = istarts[pxid] + nx / px + ((nx % px) > pxid);
930 jstarts[pyid + 1] = jstarts[pyid] + (ny / py + ((ny % py) > pyid));
935 DistributedRectilinearMeshGenerator::paritionSquarely<Hex8>(
const dof_id_type nx,
939 std::vector<dof_id_type> & istarts,
940 std::vector<dof_id_type> & jstarts,
941 std::vector<dof_id_type> & kstarts)
955 pxpz = num_procs / py;
956 if (py * pxpz == num_procs)
974 pz = num_procs / (px * py);
975 if (px * py * pz == num_procs)
980 if (nx > nz && px < pz)
983 istarts.resize(px + 1);
984 jstarts.resize(py + 1);
985 kstarts.resize(pz + 1);
990 istarts[pxid + 1] = istarts[pxid] + nx / px + ((nx % px) > pxid);
995 jstarts[pyid + 1] = jstarts[pyid] + (ny / py + ((ny % py) > pyid));
1000 kstarts[pzid + 1] = kstarts[pzid] + (nz / pz + ((nz % pz) > pzid));
1003 template <
typename T>
1006 const unsigned int nx,
1030 const auto num_procs =
comm.
size();
1040 auto & boundary_info =
mesh.get_boundary_info();
1042 std::unique_ptr<Elem> canonical_elem = std::make_unique<T>();
1045 std::vector<dof_id_type> neighbors(canonical_elem->n_neighbors());
1047 dof_id_type n_neighbors = canonical_elem->n_neighbors();
1062 num_local_elems = 0;
1063 local_elems_begin = 0;
1064 local_elems_end = 0;
1067 std::vector<std::vector<dof_id_type>> graph;
1072 graph.resize(num_local_elems);
1074 num_local_elems = 0;
1075 for (
dof_id_type e_id = local_elems_begin; e_id < local_elems_end; e_id++)
1079 getIndices<T>(nx, ny, e_id, i, j, k);
1081 getNeighbors<T>(nx, ny, nz, i, j, k, neighbors,
false);
1083 std::vector<dof_id_type> & row = graph[num_local_elems++];
1084 row.reserve(n_neighbors);
1086 for (
auto neighbor : neighbors)
1087 if (neighbor != Elem::invalid_id)
1088 row.push_back(neighbor);
1092 std::vector<dof_id_type> partition_vec;
1095 mooseWarning(
" LinearPartitioner is mainly used for setting up regression tests. For the " 1096 "production run, please do not use it.");
1098 partition_vec.resize(num_local_elems);
1100 std::fill(partition_vec.begin(), partition_vec.end(), pid);
1105 std::vector<dof_id_type> istarts;
1107 std::vector<dof_id_type> jstarts;
1109 std::vector<dof_id_type> kstarts;
1110 partition_vec.resize(num_local_elems);
1113 paritionSquarely<T>(nx, ny, nz, num_procs, istarts, jstarts, kstarts);
1115 mooseAssert(istarts.size() > 1,
"At least there is one processor along x direction");
1118 mooseAssert(jstarts.size() > 1,
"At least there is one processor along y direction");
1121 mooseAssert(kstarts.size() > 1,
"At least there is one processor along z direction");
1123 for (
dof_id_type e_id = local_elems_begin; e_id < local_elems_end; e_id++)
1126 getIndices<T>(nx, ny, e_id, i, j, k);
1129 pi = (std::upper_bound(istarts.begin(), istarts.end(), i) - istarts.begin()) - 1;
1130 pj = (std::upper_bound(jstarts.begin(), jstarts.end(), j) - jstarts.begin()) - 1;
1131 pk = (std::upper_bound(kstarts.begin(), kstarts.end(), k) - kstarts.begin()) - 1;
1133 partition_vec[e_id - local_elems_begin] = pk * px * py + pj * px +
pi;
1135 mooseAssert((pk * px * py + pj * px +
pi) < num_procs,
"processor id is too large");
1144 mooseAssert(partition_vec.size() == num_local_elems,
" Invalid partition was generateed ");
1147 std::map<processor_id_type, std::vector<dof_id_type>> pushed_elements_vecs;
1149 for (
dof_id_type e_id = local_elems_begin; e_id < local_elems_end; e_id++)
1150 pushed_elements_vecs[partition_vec[e_id - local_elems_begin]].push_back(e_id);
1153 std::vector<dof_id_type> my_new_elems;
1155 auto elements_action_functor =
1157 { std::copy(data.begin(), data.end(), std::back_inserter(my_new_elems)); };
1159 Parallel::push_parallel_vector_data(
comm, pushed_elements_vecs, elements_action_functor);
1162 for (
auto e_id : my_new_elems)
1166 getIndices<T>(nx, ny, e_id, i, j, k);
1168 addElement<T>(nx, ny, nz, i, j, k, e_id, pid,
type,
mesh);
1172 mesh.find_neighbors();
1175 std::set<dof_id_type> ghost_elems;
1177 std::set<dof_id_type> current_elems;
1181 for (
auto & elem_ptr :
mesh.element_ptr_range())
1182 current_elems.insert(elem_ptr->id());
1188 getGhostNeighbors<T>(nx, ny, nz,
mesh, current_elems, ghost_elems);
1190 current_elems.insert(ghost_elems.begin(), ghost_elems.end());
1193 current_elems.clear();
1196 std::map<processor_id_type, std::vector<dof_id_type>> ghost_elems_to_request;
1198 for (
auto & ghost_id : ghost_elems)
1204 ghost_elems_to_request[proc_id].push_back(ghost_id);
1208 auto gather_functor =
1210 const std::vector<dof_id_type> & coming_ghost_elems,
1211 std::vector<dof_id_type> & pid_for_ghost_elems)
1213 auto num_ghost_elems = coming_ghost_elems.size();
1214 pid_for_ghost_elems.resize(num_ghost_elems);
1218 for (
auto elem : coming_ghost_elems)
1219 pid_for_ghost_elems[num_local_elems++] = partition_vec[elem - local_elems_begin];
1222 std::unordered_map<dof_id_type, processor_id_type> ghost_elem_to_pid;
1224 auto action_functor =
1226 const std::vector<dof_id_type> & my_ghost_elems,
1227 const std::vector<dof_id_type> & pid_for_my_ghost_elems)
1231 for (
auto elem : my_ghost_elems)
1232 ghost_elem_to_pid[elem] = pid_for_my_ghost_elems[num_local_elems++];
1236 libMesh::Parallel::pull_parallel_vector_data(
1237 comm, ghost_elems_to_request, gather_functor, action_functor, ex);
1240 for (
auto gtop : ghost_elem_to_pid)
1242 auto ghost_id = gtop.first;
1243 auto proc_id = gtop.second;
1247 getIndices<T>(nx, ny, ghost_id, i, j, k);
1249 addElement<T>(nx, ny, nz, i, j, k, ghost_id, proc_id,
type,
mesh);
1252 mesh.find_neighbors(
true);
1255 for (
auto & elem_ptr :
mesh.element_ptr_range())
1256 for (
unsigned int s = 0; s < elem_ptr->n_sides(); s++)
1257 if (!elem_ptr->neighbor_ptr(s) && !boundary_info.n_boundary_ids(elem_ptr, s))
1258 elem_ptr->set_neighbor(s, const_cast<RemoteElem *>(
remote_elem));
1260 setBoundaryNames<T>(boundary_info);
1262 Partitioner::set_node_processor_ids(
mesh);
1265 mesh.skip_partitioning(
true);
1268 scaleNodalPositions<T>(nx, ny, nz, xmin, xmax, ymin, ymax, zmin, zmax,
mesh);
1271 std::unique_ptr<MeshBase>
1282 MooseEnum elem_type_enum = getParam<MooseEnum>(
"elem_type");
1290 elem_type_enum =
"EDGE2";
1293 elem_type_enum =
"QUAD4";
1296 elem_type_enum =
"HEX8";
1301 _elem_type = Utility::string_to_enum<ElemType>(elem_type_enum);
1306 mesh->set_distributed();
1315 dynamic_cast<UnstructuredMesh &
>(*mesh),
_nx, 1, 1,
_xmin,
_xmax, 0, 0, 0, 0,
_elem_type);
1318 buildCube<Quad4>(
dynamic_cast<UnstructuredMesh &
>(*mesh),
1331 buildCube<Hex8>(
dynamic_cast<UnstructuredMesh &
>(*mesh),
1345 getParam<MooseEnum>(
"elem_type"),
1346 " is not a currently supported element type for DistributedRectilinearMeshGenerator");
1366 std::vector<std::vector<Real>> pows(LIBMESH_DIM);
1367 for (
dof_id_type dir = 0; dir < LIBMESH_DIM; ++dir)
1369 pows[dir].resize(nelem[dir] + 1);
1370 for (
dof_id_type i = 0; i < pows[dir].size(); ++i)
1371 pows[dir][i] =
std::pow(bias[dir], static_cast<int>(i));
1375 for (
auto & node_ptr :
mesh->node_ptr_range())
1377 Node & node = *node_ptr;
1379 for (
dof_id_type dir = 0; dir < LIBMESH_DIM; ++dir)
1381 if (width[dir] != 0. && bias[dir] != 1.)
1386 Real float_index = (node(dir) - mins[dir]) * nelem[dir] / width[dir];
1388 Real integer_part = 0;
1389 Real fractional_part = std::modf(float_index, &integer_part);
1392 if (
std::abs(fractional_part) < TOLERANCE ||
std::abs(fractional_part - 1.0) < TOLERANCE)
1401 int index =
round(float_index);
1405 mins[dir] + width[dir] * (1. - pows[dir][index]) / (1. - pows[dir][nelem[dir]]);
1407 else if (
std::abs(fractional_part - 0.5) < TOLERANCE)
1418 node(dir) = mins[dir] +
1420 (1. - 0.5 * (pows[dir][integer_part] + pows[dir][integer_part + 1])) /
1421 (1. - pows[dir][nelem[dir]]);
1426 mooseError(
"Unable to bias node at node(", dir,
")=", node(dir));
1439 mesh->allow_renumbering(
true);
1440 mesh->prepare_for_use();
std::unique_ptr< DistributedMesh > buildDistributedMesh(unsigned int dim=libMesh::invalid_uint)
Build a distributed mesh that has correct remote element removal behavior and geometric ghosting func...
processor_id_type _num_parts_per_compute_node
Number of cores per compute node if hierarch partitioning is used.
MetaPhysicL::DualNumber< V, D, asd > abs(const MetaPhysicL::DualNumber< V, D, asd > &a)
const std::string LIST_GEOM_ELEM
std::string _part_package
External partitioner.
registerMooseObject("MooseApp", DistributedRectilinearMeshGenerator)
void swap(std::vector< T > &data, const std::size_t idx0, const std::size_t idx1, const libMesh::Parallel::Communicator &comm)
Swap function for serial or distributed vector of data.
dof_id_type & _nx
Number of elements in x, y, z direction.
processor_id_type _num_cores_for_partition
Number of cores for partitioning the graph The number of cores for the graph partition can be differe...
static InputParameters validParams()
processor_id_type rank() const
static void partitionGraph(const Parallel::Communicator &comm, const std::vector< std::vector< dof_id_type >> &graph, const std::vector< dof_id_type > &elem_weights, const std::vector< dof_id_type > &side_weights, const dof_id_type num_parts, const dof_id_type num_parts_per_compute_node, const std::string &part_package, std::vector< dof_id_type > &partition)
const Parallel::Communicator & comm() const
std::unique_ptr< T_DEST, T_DELETER > dynamic_pointer_cast(std::unique_ptr< T_SRC, T_DELETER > &src)
These are reworked from https://stackoverflow.com/a/11003103.
ElemType _elem_type
The type of element to build.
void linearPartitionItems(dof_id_type num_items, dof_id_type num_chunks, dof_id_type chunk_id, dof_id_type &num_local_items, dof_id_type &local_items_begin, dof_id_type &local_items_end)
Linearly partition a number of items.
DistributedRectilinearMeshGenerator(const InputParameters ¶meters)
This class works by first creating a "distributed dual graph" of the element connectivity based on a ...
MooseMesh *const _mesh
Pointer to the owning mesh.
processor_id_type size() const
uint8_t processor_id_type
const std::string & type() const
Get the type of this class.
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
static InputParameters validParams()
Real & _xmin
The min/max values for x,y,z component.
void buildCube(UnstructuredMesh &, const unsigned int, unsigned int, unsigned int, const Real, const Real, const Real, const Real, const Real, const Real, const ElemType)
Build a cube mesh.
processor_id_type linearPartitionChunk(dof_id_type num_items, dof_id_type num_chunks, dof_id_type item_id)
Return the chunk_id that is assigned to handle item_id.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sqrt(_arg)) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tanh
void mooseWarning(Args &&... args) const
Emits a warning prefixed with object name and type.
MooseEnum _dim
The dimension of the mesh.
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
void needGhostGhostedBoundaries(bool needghost)
Whether or not we want to ghost ghosted boundaries.
T & declareMeshProperty(const std::string &data_name, Args &&... args)
Methods for writing out attributes to the mesh meta-data store, which can be retrieved from most othe...
Real _bias_x
The amount by which to bias the cells in the x,y,z directions.
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
unsigned _num_side_layers
Number of element side neighbor layers While most of applications in moose require one layer of side ...
MooseUnits pow(const MooseUnits &, int)
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
MeshGenerators are objects that can modify or add to an existing mesh.
static InputParameters validParams()
std::string _partition_method
Which method is used to partition the mesh that is not built yet.
const RemoteElem * remote_elem