236DistributedRectilinearMeshGenerator::addElement<Edge2>(
const dof_id_type nx,
242 const dof_id_type elem_id,
243 const processor_id_type pid,
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);
450DistributedRectilinearMeshGenerator::addElement<Quad4>(
const dof_id_type nx,
451 const dof_id_type ny,
456 const dof_id_type elem_id,
457 const processor_id_type pid,
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);
621DistributedRectilinearMeshGenerator::getNeighbors<Hex8>(
const dof_id_type nx,
622 const dof_id_type ny,
623 const dof_id_type nz,
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);
714DistributedRectilinearMeshGenerator::addElement<Hex8>(
const dof_id_type nx,
715 const dof_id_type ny,
716 const dof_id_type nz,
720 const dof_id_type elem_id,
721 const processor_id_type pid,
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);
1006 const unsigned int nx,
1015 const ElemType type)
1028 dof_id_type num_elems = nx * ny * nz;
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();
1050 dof_id_type num_local_elems;
1051 dof_id_type local_elems_begin;
1052 dof_id_type local_elems_end;
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++)
1077 dof_id_type i, j, k = 0;
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::sort(row.begin(), row.end());
1096 std::vector<dof_id_type> partition_vec;
1099 mooseWarning(
" LinearPartitioner is mainly used for setting up regression tests. For the "
1100 "production run, please do not use it.");
1102 partition_vec.resize(num_local_elems);
1104 std::fill(partition_vec.begin(), partition_vec.end(), pid);
1109 std::vector<dof_id_type> istarts;
1111 std::vector<dof_id_type> jstarts;
1113 std::vector<dof_id_type> kstarts;
1114 partition_vec.resize(num_local_elems);
1117 paritionSquarely<T>(nx, ny, nz, num_procs, istarts, jstarts, kstarts);
1119 mooseAssert(istarts.size() > 1,
"At least there is one processor along x direction");
1120 processor_id_type px = istarts.size() - 1;
1122 mooseAssert(jstarts.size() > 1,
"At least there is one processor along y direction");
1123 processor_id_type py = jstarts.size() - 1;
1125 mooseAssert(kstarts.size() > 1,
"At least there is one processor along z direction");
1127 for (dof_id_type e_id = local_elems_begin; e_id < local_elems_end; e_id++)
1129 dof_id_type i = 0, j = 0, k = 0;
1130 getIndices<T>(nx, ny, e_id, i, j, k);
1131 processor_id_type pi = 0, pj = 0, pk = 0;
1133 pi = (std::upper_bound(istarts.begin(), istarts.end(), i) - istarts.begin()) - 1;
1134 pj = (std::upper_bound(jstarts.begin(), jstarts.end(), j) - jstarts.begin()) - 1;
1135 pk = (std::upper_bound(kstarts.begin(), kstarts.end(), k) - kstarts.begin()) - 1;
1137 partition_vec[e_id - local_elems_begin] = pk * px * py + pj * px + pi;
1139 mooseAssert((pk * px * py + pj * px + pi) < num_procs,
"processor id is too large");
1148 mooseAssert(partition_vec.size() == num_local_elems,
" Invalid partition was generateed ");
1151 std::map<processor_id_type, std::vector<dof_id_type>> pushed_elements_vecs;
1153 for (dof_id_type e_id = local_elems_begin; e_id < local_elems_end; e_id++)
1154 pushed_elements_vecs[partition_vec[e_id - local_elems_begin]].push_back(e_id);
1157 std::vector<dof_id_type> my_new_elems;
1159 auto elements_action_functor =
1160 [&my_new_elems](processor_id_type ,
const std::vector<dof_id_type> & data)
1161 { std::copy(data.begin(), data.end(), std::back_inserter(my_new_elems)); };
1163 Parallel::push_parallel_vector_data(
comm, pushed_elements_vecs, elements_action_functor);
1166 for (
auto e_id : my_new_elems)
1168 dof_id_type i = 0, j = 0, k = 0;
1170 getIndices<T>(nx, ny, e_id, i, j, k);
1172 addElement<T>(nx, ny, nz, i, j, k, e_id, pid,
type,
mesh);
1176 mesh.find_neighbors();
1179 std::set<dof_id_type> ghost_elems;
1181 std::set<dof_id_type> current_elems;
1185 for (
auto & elem_ptr :
mesh.element_ptr_range())
1186 current_elems.insert(elem_ptr->id());
1192 getGhostNeighbors<T>(nx, ny, nz,
mesh, current_elems, ghost_elems);
1194 current_elems.insert(ghost_elems.begin(), ghost_elems.end());
1197 current_elems.clear();
1200 std::map<processor_id_type, std::vector<dof_id_type>> ghost_elems_to_request;
1202 for (
auto & ghost_id : ghost_elems)
1208 ghost_elems_to_request[proc_id].push_back(ghost_id);
1212 auto gather_functor =
1213 [local_elems_begin, partition_vec](processor_id_type ,
1214 const std::vector<dof_id_type> & coming_ghost_elems,
1215 std::vector<dof_id_type> & pid_for_ghost_elems)
1217 auto num_ghost_elems = coming_ghost_elems.size();
1218 pid_for_ghost_elems.resize(num_ghost_elems);
1220 dof_id_type num_local_elems = 0;
1222 for (
auto elem : coming_ghost_elems)
1223 pid_for_ghost_elems[num_local_elems++] = partition_vec[elem - local_elems_begin];
1226 std::unordered_map<dof_id_type, processor_id_type> ghost_elem_to_pid;
1228 auto action_functor =
1229 [&ghost_elem_to_pid](processor_id_type ,
1230 const std::vector<dof_id_type> & my_ghost_elems,
1231 const std::vector<dof_id_type> & pid_for_my_ghost_elems)
1233 dof_id_type num_local_elems = 0;
1235 for (
auto elem : my_ghost_elems)
1236 ghost_elem_to_pid[elem] = pid_for_my_ghost_elems[num_local_elems++];
1239 const dof_id_type * ex =
nullptr;
1240 libMesh::Parallel::pull_parallel_vector_data(
1241 comm, ghost_elems_to_request, gather_functor, action_functor, ex);
1244 for (
auto gtop : ghost_elem_to_pid)
1246 auto ghost_id = gtop.first;
1247 auto proc_id = gtop.second;
1249 dof_id_type i = 0, j = 0, k = 0;
1251 getIndices<T>(nx, ny, ghost_id, i, j, k);
1253 addElement<T>(nx, ny, nz, i, j, k, ghost_id, proc_id,
type,
mesh);
1256 mesh.find_neighbors(
true);
1259 for (
auto & elem_ptr :
mesh.element_ptr_range())
1260 for (
unsigned int s = 0; s < elem_ptr->n_sides(); s++)
1261 if (!elem_ptr->neighbor_ptr(s) && !boundary_info.n_boundary_ids(elem_ptr, s))
1262 elem_ptr->set_neighbor(s,
const_cast<RemoteElem *
>(remote_elem));
1264 setBoundaryNames<T>(boundary_info);
1266 Partitioner::set_node_processor_ids(
mesh);
1269 mesh.skip_partitioning(
true);
1272 scaleNodalPositions<T>(nx, ny, nz, xmin, xmax, ymin, ymax, zmin, zmax,
mesh);