12 #include "CastUniquePointer.h"
14 #include "libmesh/edge_edge2.h"
15 #include "libmesh/face_tri3.h"
16 #include "libmesh/cell_tet4.h"
24 InputParameters params = validParams<MeshGenerator>();
25 params.addClassDescription(
"Mesh generator class to convert FE mesh to Peridynamics mesh");
27 params.addRequiredParam<MeshGeneratorName>(
"input",
28 "The mesh based on which PD mesh will be created");
29 params.addParam<std::vector<SubdomainID>>(
"convert_block_ids",
30 "IDs of the FE mesh blocks to be converted to PD mesh");
31 params.addParam<std::vector<SubdomainID>>(
32 "non_convert_block_ids",
33 "IDs of the FE mesh blocks to not be converted to PD mesh. This should only be used when the "
34 "number of to-be-converted FE blocks is considerable.");
35 params.addRequiredParam<
bool>(
36 "retain_fe_mesh",
"Whether to retain the FE mesh or not after conversion into PD mesh");
37 params.addParam<
bool>(
"single_converted_block",
39 "Whether to combine converted PD mesh blocks into a single block. This is "
40 "used when all PD blocks have the same properties");
41 params.addParam<
bool>(
42 "construct_peridynamics_sideset",
44 "Whether to construct peridynamics sidesets based on the sidesets in original FE mesh");
45 params.addParam<std::vector<SubdomainID>>(
46 "connect_block_id_pairs",
47 "List of block id pairs between which will be connected via interfacial bonds");
48 params.addParam<std::vector<SubdomainID>>(
49 "non_connect_block_id_pairs",
"List of block pairs between which will not be connected");
50 params.addParam<
bool>(
"single_interface_block",
52 "Whether to combine interface blocks into a single block. This is used "
53 "when all interface blocks have the same properties");
59 : MeshGenerator(parameters),
60 _input(getMesh(
"input")),
61 _has_conv_blk_ids(isParamValid(
"convert_block_ids")),
62 _has_non_conv_blk_ids(isParamValid(
"non_convert_block_ids")),
63 _retain_fe_mesh(getParam<bool>(
"retain_fe_mesh")),
64 _single_converted_blk(getParam<bool>(
"single_converted_block")),
65 _construct_pd_sideset(getParam<bool>(
"construct_peridynamics_sideset")),
66 _has_connect_blk_id_pairs(isParamValid(
"connect_block_id_pairs")),
67 _has_non_connect_blk_id_pairs(isParamValid(
"non_connect_block_id_pairs")),
68 _single_interface_blk(getParam<bool>(
"single_interface_block"))
71 mooseError(
"Please specifiy either 'convert_block_ids' or 'non_convert_block_ids'!");
75 std::vector<SubdomainID> ids = getParam<std::vector<SubdomainID>>(
"non_convert_block_ids");
76 for (
unsigned int i = 0; i < ids.size(); ++i)
82 std::vector<SubdomainID> ids = getParam<std::vector<SubdomainID>>(
"convert_block_ids");
83 for (
unsigned int i = 0; i < ids.size(); ++i)
88 mooseError(
"Please specifiy either 'connect_block_id_pairs' or 'non_connect_block_id_pairs'!");
93 std::vector<SubdomainID> ids = getParam<std::vector<SubdomainID>>(
"connect_block_id_pairs");
95 if (ids.size() % 2 != 0)
96 mooseError(
"Input parameter 'connect_block_id_pairs' must contain even number of entries!");
98 const unsigned int pairs = ids.size() / 2;
99 for (
unsigned int i = 0; i < pairs; ++i)
106 std::vector<SubdomainID> ids = getParam<std::vector<SubdomainID>>(
"non_connect_block_id_pairs");
108 if (ids.size() % 2 != 0)
110 "Input parameter 'non_connect_block_id_pairs' must contain even number of entries!");
112 const unsigned int pairs = ids.size() / 2;
113 for (
unsigned int i = 0; i < pairs; ++i)
118 std::unique_ptr<MeshBase>
122 std::unique_ptr<MeshBase> old_mesh = std::move(
_input);
127 std::set<SubdomainID> all_blk_ids;
128 for (
const auto & old_elem : old_mesh->element_ptr_range())
129 all_blk_ids.insert(old_elem->subdomain_id());
133 const unsigned int max_fe_blk_id = *all_blk_ids.rbegin();
137 std::set_difference(all_blk_ids.begin(),
143 std::set_difference(all_blk_ids.begin(),
153 const unsigned int min_converted_fe_blk_id = *
_conv_blk_ids.begin();
156 std::set<dof_id_type> conv_elem_ids;
158 std::set<dof_id_type> fe_nodes_ids;
159 std::set<dof_id_type> fe_elems_ids;
160 for (
const auto & old_elem : old_mesh->element_ptr_range())
163 conv_elem_ids.insert(old_elem->id());
166 fe_elems_ids.insert(old_elem->id());
167 for (
unsigned int i = 0; i < old_elem->n_nodes(); ++i)
168 fe_nodes_ids.insert(old_elem->node_id(i));
173 fe_elems_ids.insert(old_elem->id());
174 for (
unsigned int i = 0; i < old_elem->n_nodes(); ++i)
175 fe_nodes_ids.insert(old_elem->node_id(i));
179 dof_id_type n_fe_nodes = fe_nodes_ids.size();
180 dof_id_type n_fe_elems = fe_elems_ids.size();
181 dof_id_type n_phantom_elems = 0;
185 BoundaryInfo & old_boundary_info = old_mesh->get_boundary_info();
188 std::set<boundary_id_type> fe_sbnd_ids = old_boundary_info.get_side_boundary_ids();
192 std::map<boundary_id_type, std::set<dof_id_type>> fe_sbnd_elem_ids;
193 auto fe_sbc_tuples = old_boundary_info.build_side_list();
195 for (
const auto & sbct : fe_sbc_tuples)
197 fe_sbnd_elem_ids[std::get<2>(sbct)].insert(std::get<0>(sbct));
209 dof_id_type n_pd_nodes = pd_mesh.
nPDNodes();
210 dof_id_type n_pd_bonds = pd_mesh.
nPDBonds();
213 std::unique_ptr<MeshBase> new_mesh = _mesh->buildMeshBaseObject();
216 new_mesh->set_mesh_dimension(old_mesh->mesh_dimension());
217 new_mesh->set_spatial_dimension(old_mesh->spatial_dimension());
219 new_mesh->reserve_nodes(n_pd_nodes + n_fe_nodes);
220 new_mesh->reserve_elem(n_pd_bonds + n_fe_elems + n_phantom_elems);
222 BoundaryInfo & new_boundary_info = new_mesh->get_boundary_info();
227 unsigned int new_node_id = 0;
229 std::map<dof_id_type, dof_id_type> fe_elem_pd_node_map;
230 for (
const auto & eid : conv_elem_ids)
232 new_mesh->add_point(old_mesh->elem_ptr(eid)->centroid(), new_node_id);
233 fe_elem_pd_node_map.insert(std::make_pair(eid, new_node_id));
239 std::map<dof_id_type, dof_id_type> fe_nodes_map;
240 for (
const auto & nid : fe_nodes_ids)
242 new_mesh->add_point(*old_mesh->node_ptr(nid), new_node_id);
243 fe_nodes_map.insert(std::make_pair(old_mesh->node_ptr(nid)->id(), new_node_id));
251 unsigned int new_elem_id = 0;
252 for (
unsigned int i = 0; i < n_pd_nodes; ++i)
254 std::vector<dof_id_type> pd_node_neighbors = pd_mesh.
getNeighbors(i);
255 for (
unsigned int j = 0; j < pd_node_neighbors.size(); ++j)
256 if (pd_node_neighbors[j] > i)
260 Elem * new_elem =
new Edge2;
261 new_elem->set_id(new_elem_id);
264 new_elem->subdomain_id() = min_converted_fe_blk_id + 1000;
266 new_elem->subdomain_id() = bid_i;
269 new_elem->subdomain_id() = max_fe_blk_id + 1 + 1000;
271 new_elem->subdomain_id() = bid_i + bid_j;
273 new_elem = new_mesh->add_elem(new_elem);
274 new_elem->set_node(0) = new_mesh->node_ptr(i);
275 new_elem->set_node(1) = new_mesh->node_ptr(pd_node_neighbors[j]);
285 std::map<std::pair<dof_id_type, dof_id_type>, std::set<dof_id_type>> elem_edge_node;
287 for (
const auto & bidit : fe_sbnd_ids)
288 for (
const auto & eidit : fe_sbnd_elem_ids[bidit])
290 bool should_add =
false;
291 Elem * old_elem = old_mesh->elem_ptr(eidit);
294 std::vector<dof_id_type> node_ids;
295 if (new_mesh->mesh_dimension() == 2)
298 node_ids[0] = fe_elem_pd_node_map.at(eidit);
299 Point p0 = *new_mesh->node_ptr(node_ids[0]);
301 if (old_elem->n_nodes() == 3 ||
302 old_elem->n_nodes() == 6)
305 for (
unsigned int i = 0; i < old_elem->n_neighbors(); ++i)
307 Elem * nb = old_elem->neighbor_ptr(i);
310 for (
unsigned int j = 0; j < nb->n_neighbors(); ++j)
312 Elem * nb_nb = nb->neighbor_ptr(j);
313 if (nb_nb !=
nullptr && fe_sbnd_elem_ids[bidit].count(nb_nb->id()) &&
314 nb_nb->id() != eidit)
316 Point p1 = *new_mesh->node_ptr(fe_elem_pd_node_map.at(nb_nb->id()));
317 Point p2 = *new_mesh->node_ptr(fe_elem_pd_node_map.at(nb->id()));
319 (p1(1) - p0(1)) * (p2(0) - p1(0)) - (p1(0) - p0(0)) * (p2(1) - p1(1));
322 node_ids[1] = fe_elem_pd_node_map.at(nb_nb->id());
323 node_ids[2] = fe_elem_pd_node_map.at(nb->id());
334 std::vector<dof_id_type> boundary_node_ids;
335 for (
unsigned int i = 0; i < old_elem->n_neighbors(); ++i)
337 Elem * nb = old_elem->neighbor_ptr(i);
340 if (fe_sbnd_elem_ids[bidit].count(nb->id()))
341 boundary_node_ids.push_back(fe_elem_pd_node_map.at(nb->id()));
343 node_ids[2] = fe_elem_pd_node_map.at(nb->id());
347 Point p2 = *new_mesh->node_ptr(node_ids[2]);
348 for (
unsigned int i = 0; i < boundary_node_ids.size(); ++i)
350 Point p1 = *new_mesh->node_ptr(boundary_node_ids[i]);
351 Real val = (p1(1) - p0(1)) * (p2(0) - p1(0)) - (p1(0) - p0(0)) * (p2(1) - p1(1));
354 node_ids[1] = boundary_node_ids[i];
362 Elem * new_elem =
new Tri3;
363 new_elem->set_id(new_elem_id);
365 new_elem->subdomain_id() = min_converted_fe_blk_id + 10000;
367 new_elem->subdomain_id() = old_elem->subdomain_id() + 10000;
368 new_elem = new_mesh->add_elem(new_elem);
369 new_elem->set_node(0) = new_mesh->node_ptr(node_ids[0]);
370 new_elem->set_node(1) = new_mesh->node_ptr(node_ids[1]);
371 new_elem->set_node(2) = new_mesh->node_ptr(node_ids[2]);
375 new_boundary_info.add_side(new_elem, 0, 1000 + bidit);
376 if (old_boundary_info.get_sideset_name(bidit) !=
"")
377 new_boundary_info.sideset_name(1000 + bidit) =
378 "pd_side_" + old_boundary_info.get_sideset_name(bidit);
384 node_ids[0] = fe_elem_pd_node_map.at(eidit);
385 Point p0 = *new_mesh->node_ptr(node_ids[0]);
388 if (old_elem->n_nodes() == 4 ||
389 old_elem->n_nodes() == 10)
392 mooseError(
"Peridynamics sideset generation doesn't accept tetrahedral elements!");
396 std::vector<dof_id_type> boundary_elem_ids;
397 for (
unsigned int i = 0; i < old_elem->n_neighbors(); ++i)
399 Elem * nb = old_elem->neighbor_ptr(i);
402 if (fe_sbnd_elem_ids[bidit].count(nb->id()))
403 boundary_elem_ids.push_back(nb->id());
405 node_ids[3] = fe_elem_pd_node_map.at(nb->id());
409 Point p3 = *new_mesh->node_ptr(node_ids[3]);
410 for (
unsigned int i = 0; i < boundary_elem_ids.size(); ++i)
412 Elem * nb_i = old_mesh->elem_ptr(boundary_elem_ids[i]);
413 for (
unsigned int j = i + 1; j < boundary_elem_ids.size(); ++j)
416 Elem * nb_j = old_mesh->elem_ptr(boundary_elem_ids[j]);
417 unsigned int common_nb = 0;
418 for (
unsigned int k = 0; k < nb_j->n_neighbors();
421 if (nb_j->neighbor_ptr(k) !=
nullptr &&
422 nb_i->has_neighbor(nb_j->neighbor_ptr(k)))
430 std::pair<dof_id_type, dof_id_type> pair;
431 if (eidit < boundary_elem_ids[i])
432 pair = std::make_pair(eidit, boundary_elem_ids[i]);
434 pair = std::make_pair(boundary_elem_ids[i], eidit);
436 if (elem_edge_node.count(pair))
438 for (
const auto & nbid : elem_edge_node[pair])
439 if (nbid != old_elem->id() && old_mesh->elem_ptr(nbid)->has_neighbor(nb_j))
443 if (eidit < boundary_elem_ids[j])
444 pair = std::make_pair(eidit, boundary_elem_ids[j]);
446 pair = std::make_pair(boundary_elem_ids[j], eidit);
447 if (elem_edge_node.count(pair))
449 for (
const auto & nbid : elem_edge_node[pair])
450 if (nbid != old_elem->id() && old_mesh->elem_ptr(nbid)->has_neighbor(nb_i))
456 Point p1 = *new_mesh->node_ptr(fe_elem_pd_node_map.at(boundary_elem_ids[i]));
457 Point p2 = *new_mesh->node_ptr(fe_elem_pd_node_map.at(boundary_elem_ids[j]));
460 ((p1(1) - p0(1)) * (p2(2) - p0(2)) - (p1(2) - p0(2)) * (p2(1) - p0(1))) *
462 ((p1(2) - p0(2)) * (p2(0) - p0(0)) - (p1(0) - p0(0)) * (p2(2) - p0(2))) *
464 ((p1(0) - p0(0)) * (p2(1) - p0(1)) - (p1(1) - p0(1)) * (p2(0) - p0(0))) *
468 node_ids[1] = fe_elem_pd_node_map.at(boundary_elem_ids[i]);
469 node_ids[2] = fe_elem_pd_node_map.at(boundary_elem_ids[j]);
473 node_ids[1] = fe_elem_pd_node_map.at(boundary_elem_ids[j]);
474 node_ids[2] = fe_elem_pd_node_map.at(boundary_elem_ids[i]);
478 Elem * new_elem =
new Tet4;
479 new_elem->set_id(new_elem_id);
481 new_elem->subdomain_id() = min_converted_fe_blk_id + 10000;
483 new_elem->subdomain_id() = old_elem->subdomain_id() + 10000;
484 new_elem = new_mesh->add_elem(new_elem);
485 new_elem->set_node(0) = new_mesh->node_ptr(node_ids[0]);
486 new_elem->set_node(1) = new_mesh->node_ptr(node_ids[1]);
487 new_elem->set_node(2) = new_mesh->node_ptr(node_ids[2]);
488 new_elem->set_node(3) = new_mesh->node_ptr(node_ids[3]);
491 if (eidit < boundary_elem_ids[i])
492 elem_edge_node[std::make_pair(eidit, boundary_elem_ids[i])].insert(
493 boundary_elem_ids[j]);
495 elem_edge_node[std::make_pair(boundary_elem_ids[i], eidit)].insert(
496 boundary_elem_ids[j]);
498 if (eidit < boundary_elem_ids[j])
499 elem_edge_node[std::make_pair(eidit, boundary_elem_ids[j])].insert(
500 boundary_elem_ids[i]);
502 elem_edge_node[std::make_pair(boundary_elem_ids[j], eidit)].insert(
503 boundary_elem_ids[i]);
507 new_boundary_info.add_side(new_elem, 0, 1000 + bidit);
508 if (old_boundary_info.get_sideset_name(bidit) !=
"")
509 new_boundary_info.sideset_name(1000 + bidit) =
510 "pd_side_" + old_boundary_info.get_sideset_name(bidit);
521 std::map<dof_id_type, dof_id_type> fe_elems_map;
522 for (
const auto & eid : fe_elems_ids)
524 Elem * old_elem = old_mesh->elem_ptr(eid);
525 Elem * new_elem = Elem::build(old_elem->type()).release();
526 new_elem->set_id(new_elem_id);
527 new_elem->subdomain_id() = old_elem->subdomain_id();
528 new_elem = new_mesh->add_elem(new_elem);
529 for (
unsigned int j = 0; j < old_elem->n_nodes(); ++j)
530 new_elem->set_node(j) = new_mesh->node_ptr(fe_nodes_map.at(old_elem->node_ptr(j)->id()));
532 fe_elems_map.insert(std::make_pair(old_elem->id(), new_elem_id));
541 if (old_boundary_info.n_edge_conds())
542 mooseError(
"PeridynamicsMesh doesn't support edgesets!");
545 if (old_boundary_info.n_nodeset_conds())
546 old_boundary_info.build_side_list_from_node_list();
550 auto old_fe_sbc_tuples = old_boundary_info.build_side_list();
553 std::map<boundary_id_type, std::set<dof_id_type>> old_fe_bnd_elem_ids;
555 std::map<dof_id_type, std::map<boundary_id_type, dof_id_type>> old_fe_elem_bnd_side_ids;
556 for (
const auto & sbct : old_fe_sbc_tuples)
558 old_fe_bnd_elem_ids[std::get<2>(sbct)].insert(std::get<0>(sbct));
559 old_fe_elem_bnd_side_ids[std::get<0>(sbct)].insert(
560 std::make_pair(std::get<2>(sbct), std::get<1>(sbct)));
564 std::set<boundary_id_type> old_side_bid(old_boundary_info.get_side_boundary_ids());
567 for (
const auto & sbid : old_side_bid)
568 for (
const auto & beid : old_fe_bnd_elem_ids[sbid])
569 if (conv_elem_ids.count(beid))
572 new_boundary_info.add_node(new_mesh->node_ptr(fe_elem_pd_node_map.at(beid)), sbid + 1000);
573 if (old_boundary_info.get_sideset_name(sbid) !=
"")
574 new_boundary_info.nodeset_name(sbid + 1000) =
575 "pd_nodes_" + old_boundary_info.get_sideset_name(sbid);
580 new_boundary_info.add_side(
581 new_mesh->elem_ptr(fe_elems_map[beid]), old_fe_elem_bnd_side_ids[beid][sbid], sbid);
582 new_boundary_info.sideset_name(sbid) = old_boundary_info.get_sideset_name(sbid);
588 new_boundary_info.add_side(
589 new_mesh->elem_ptr(fe_elems_map[beid]), old_fe_elem_bnd_side_ids[beid][sbid], sbid);
590 new_boundary_info.sideset_name(sbid) = old_boundary_info.get_sideset_name(sbid);
595 auto old_node_bc_tuples = old_boundary_info.build_node_list();
597 std::map<boundary_id_type, std::set<dof_id_type>> old_bnd_node_ids;
598 for (
const auto & nbct : old_node_bc_tuples)
599 old_bnd_node_ids[std::get<1>(nbct)].insert(std::get<0>(nbct));
601 std::set<boundary_id_type> old_node_bid(old_boundary_info.get_node_boundary_ids());
603 for (
const auto & nbid : old_node_bid)
604 for (
const auto & bnid : old_bnd_node_ids[nbid])
605 if (fe_nodes_ids.count(bnid))
607 new_boundary_info.add_node(new_mesh->node_ptr(fe_nodes_map.at(bnid)), nbid);
608 new_boundary_info.nodeset_name(nbid) = old_boundary_info.get_sideset_name(nbid);
612 for (
unsigned int i = 0; i < n_pd_nodes; ++i)
620 SubdomainID real_blk_id =
624 new_boundary_info.add_node(new_mesh->node_ptr(i), 999 - j);
625 new_boundary_info.nodeset_name(999 - j) =
626 "pd_nodes_block_" + Moose::stringify(blk_id + 1000);
631 new_boundary_info.add_node(new_mesh->node_ptr(i), 999);
632 new_boundary_info.nodeset_name(999) =
"pd_nodes_all";
637 return dynamic_pointer_cast<MeshBase>(new_mesh);