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::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");
1116 processor_id_type px = istarts.size() - 1;
1118 mooseAssert(jstarts.size() > 1,
"At least there is one processor along y direction");
1119 processor_id_type py = jstarts.size() - 1;
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++)
1125 dof_id_type i = 0, j = 0, k = 0;
1126 getIndices<T>(nx, ny, e_id, i, j, k);
1127 processor_id_type pi = 0, pj = 0, pk = 0;
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 =
1156 [&my_new_elems](processor_id_type ,
const std::vector<dof_id_type> & data)
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)
1164 dof_id_type i = 0, j = 0, k = 0;
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 =
1209 [local_elems_begin, partition_vec](processor_id_type ,
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);
1216 dof_id_type num_local_elems = 0;
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 =
1225 [&ghost_elem_to_pid](processor_id_type ,
1226 const std::vector<dof_id_type> & my_ghost_elems,
1227 const std::vector<dof_id_type> & pid_for_my_ghost_elems)
1229 dof_id_type num_local_elems = 0;
1231 for (
auto elem : my_ghost_elems)
1232 ghost_elem_to_pid[elem] = pid_for_my_ghost_elems[num_local_elems++];
1235 const dof_id_type * ex =
nullptr;
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;
1245 dof_id_type i = 0, j = 0, k = 0;
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);