www.mooseframework.org
Public Member Functions | Protected Attributes | List of all members
MeshGeneratorPD Class Reference

Generate peridynamics mesh based on finite element mesh. More...

#include <MeshGeneratorPD.h>

Inheritance diagram for MeshGeneratorPD:
[legend]

Public Member Functions

 MeshGeneratorPD (const InputParameters &parameters)
 
std::unique_ptr< MeshBase > generate ()
 Function to convert the finite element mesh to peridynamics mesh. More...
 

Protected Attributes

std::unique_ptr< MeshBase > & _input
 Reference to the input finite element mesh. More...
 
bool _has_conv_blk_ids
 block ID(s) of input FE mesh when only certain block(s) needs to be converted to PD mesh this is used when there are listable to-be-converted blocks More...
 
std::set< SubdomainID > _conv_blk_ids
 
bool _has_non_conv_blk_ids
 block ID(s) of input FE mesh when only certain block(s) needs NOT to be converted to PD mesh this is usually used when there are considerable to-be-converted blocks but a few not to be converted More...
 
std::set< SubdomainID > _non_conv_blk_ids
 
bool _retain_fe_mesh
 flag to specify whether the FE mesh should be retained or not in addition to newly created PD mesh More...
 
bool _single_converted_blk
 flag to specify whether to combine converted PD mesh blocks into a single mesh block or not this is used when all PD blocks have the same properties More...
 
bool _construct_pd_sideset
 flag to specify whether PD sideset should be constructed or not More...
 
bool _has_connect_blk_id_pairs
 pairs of converted FE block IDs when only certain blocks need to be connected using interfacial bonds this is used when there are listable to-be-connected blocks More...
 
std::multimap< SubdomainID, SubdomainID > _connect_blk_id_pairs
 
bool _has_non_connect_blk_id_pairs
 pairs of converted FE block IDs when only certain blocks need NOT to be connected this is usually used when there are considerable to-be-connected blocks but a few not to be connected More...
 
std::multimap< SubdomainID, SubdomainID > _non_connect_blk_id_pairs
 
bool _single_interface_blk
 flag to specify whether a single block should be used for all interfacial bonds this is used when all interfacial bonds have the same properties More...
 

Detailed Description

Generate peridynamics mesh based on finite element mesh.

Definition at line 23 of file MeshGeneratorPD.h.

Constructor & Destructor Documentation

◆ MeshGeneratorPD()

MeshGeneratorPD::MeshGeneratorPD ( const InputParameters &  parameters)

Definition at line 58 of file MeshGeneratorPD.C.

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"))
69 {
71  mooseError("Please specifiy either 'convert_block_ids' or 'non_convert_block_ids'!");
72 
74  {
75  std::vector<SubdomainID> ids = getParam<std::vector<SubdomainID>>("non_convert_block_ids");
76  for (unsigned int i = 0; i < ids.size(); ++i)
77  _non_conv_blk_ids.insert(ids[i]);
78  }
79 
81  {
82  std::vector<SubdomainID> ids = getParam<std::vector<SubdomainID>>("convert_block_ids");
83  for (unsigned int i = 0; i < ids.size(); ++i)
84  _conv_blk_ids.insert(ids[i]);
85  }
86 
88  mooseError("Please specifiy either 'connect_block_id_pairs' or 'non_connect_block_id_pairs'!");
89 
90  _connect_blk_id_pairs.clear();
92  {
93  std::vector<SubdomainID> ids = getParam<std::vector<SubdomainID>>("connect_block_id_pairs");
94 
95  if (ids.size() % 2 != 0)
96  mooseError("Input parameter 'connect_block_id_pairs' must contain even number of entries!");
97 
98  const unsigned int pairs = ids.size() / 2;
99  for (unsigned int i = 0; i < pairs; ++i) // consider the renumbering of IDs of converted blocks
100  _connect_blk_id_pairs.insert(std::make_pair(ids[2 * i] + 1000, ids[2 * i + 1] + 1000));
101  }
102 
105  {
106  std::vector<SubdomainID> ids = getParam<std::vector<SubdomainID>>("non_connect_block_id_pairs");
107 
108  if (ids.size() % 2 != 0)
109  mooseError(
110  "Input parameter 'non_connect_block_id_pairs' must contain even number of entries!");
111 
112  const unsigned int pairs = ids.size() / 2;
113  for (unsigned int i = 0; i < pairs; ++i) // consider the renumbering of IDs of converted blocks
114  _non_connect_blk_id_pairs.insert(std::make_pair(ids[2 * i] + 1000, ids[2 * i + 1] + 1000));
115  }
116 }

Member Function Documentation

◆ generate()

std::unique_ptr< MeshBase > MeshGeneratorPD::generate ( )

Function to convert the finite element mesh to peridynamics mesh.

Returns
The converted mesh

Definition at line 119 of file MeshGeneratorPD.C.

120 {
121  // get the MeshBase object this generator will be working on
122  std::unique_ptr<MeshBase> old_mesh = std::move(_input);
123 
124  // STEP 1: obtain FE block(s) and elements to be converted to PD mesh
125 
126  // get the IDs of all available blocks in the input FE mesh
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());
130 
131  // the maximum FE block ID, which will be used in determine the block ID for interfacial bond in
132  // the case of single interface block
133  const unsigned int max_fe_blk_id = *all_blk_ids.rbegin();
134 
135  // categorize mesh blocks into converted and non-converted blocks
136  if (_has_conv_blk_ids)
137  std::set_difference(all_blk_ids.begin(),
138  all_blk_ids.end(),
139  _conv_blk_ids.begin(),
140  _conv_blk_ids.end(),
141  std::inserter(_non_conv_blk_ids, _non_conv_blk_ids.begin()));
142  else if (_has_non_conv_blk_ids)
143  std::set_difference(all_blk_ids.begin(),
144  all_blk_ids.end(),
145  _non_conv_blk_ids.begin(),
146  _non_conv_blk_ids.end(),
147  std::inserter(_conv_blk_ids, _conv_blk_ids.begin()));
148  else // if no block ids provided by user, by default, convert all FE mesh to PD mesh
149  _conv_blk_ids = all_blk_ids;
150 
151  // the minimum converted FE block ID, which will be used to assign block ID for non-interfacial
152  // bond in the case of combine converted blocks
153  const unsigned int min_converted_fe_blk_id = *_conv_blk_ids.begin();
154 
155  // IDs of to-be-converted FE elems
156  std::set<dof_id_type> conv_elem_ids;
157  // retained FE mesh and non-converted FE mesh, if any
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())
161  if (_conv_blk_ids.count(old_elem->subdomain_id())) // record to-be-converted FE elem IDs
162  {
163  conv_elem_ids.insert(old_elem->id());
164  if (_retain_fe_mesh) // save converted elems and their nodes if need to be retained
165  {
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));
169  }
170  }
171  else // save non-converted elements and their nodes
172  {
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));
176  }
177 
178  // number of FE elements and nodes in the old mesh to be saved in the new mesh
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;
182 
183  // determine the number of phantom elements to be generated in the new mesh based on sideset in
184  // old mesh
185  BoundaryInfo & old_boundary_info = old_mesh->get_boundary_info();
186 
187  // save the IDs of FE sidesets (excluding constructed from nodesets) in old mesh
188  std::set<boundary_id_type> fe_sbnd_ids = old_boundary_info.get_side_boundary_ids();
189  // determine number of FE side elements, the number of actual phantom elements is less than or
190  // equal to the number of FE side elements, this number is used to reserve number of elements
191  // in the new mesh only
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();
194  // 0: element ID, 1: side ID, 2: boundary ID
195  for (const auto & sbct : fe_sbc_tuples)
196  {
197  fe_sbnd_elem_ids[std::get<2>(sbct)].insert(std::get<0>(sbct));
198  ++n_phantom_elems;
199  }
200 
201  // STEP 2: generate PD data based on to-be-converted FE mesh and prepare for new mesh
202 
203  PeridynamicsMesh & pd_mesh = dynamic_cast<PeridynamicsMesh &>(*_mesh);
204  // generate PD node data
206  *old_mesh, conv_elem_ids, _connect_blk_id_pairs, _non_connect_blk_id_pairs);
207 
208  // number of PD elements and nodes to be created
209  dof_id_type n_pd_nodes = pd_mesh.nPDNodes();
210  dof_id_type n_pd_bonds = pd_mesh.nPDBonds();
211 
212  // initialize an empty new mesh object
213  std::unique_ptr<MeshBase> new_mesh = _mesh->buildMeshBaseObject();
214  new_mesh->clear();
215  // set new mesh dimension
216  new_mesh->set_mesh_dimension(old_mesh->mesh_dimension());
217  new_mesh->set_spatial_dimension(old_mesh->spatial_dimension());
218  // reserve elements and nodes for the new mesh
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);
221 
222  BoundaryInfo & new_boundary_info = new_mesh->get_boundary_info();
223 
224  // STEP 3: add points of PD and FE (retained and/or non-converted) nodes, if any, to new mesh
225 
226  // save PD nodes to new mesh first
227  unsigned int new_node_id = 0;
228  // map of IDs of converted FE elements and PD nodes
229  std::map<dof_id_type, dof_id_type> fe_elem_pd_node_map;
230  for (const auto & eid : conv_elem_ids)
231  {
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));
234 
235  ++new_node_id;
236  }
237  // then save both retained and non-converted FE nodes, if any, to the new mesh
238  // map of IDs of the same point in old and new meshes
239  std::map<dof_id_type, dof_id_type> fe_nodes_map;
240  for (const auto & nid : fe_nodes_ids)
241  {
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));
244 
245  ++new_node_id;
246  }
247 
248  // STEP 4: generate PD, phantom, and FE elems using retained and/or non-converted meshes if any
249 
250  // first, generate PD elements for new mesh
251  unsigned int new_elem_id = 0;
252  for (unsigned int i = 0; i < n_pd_nodes; ++i)
253  {
254  std::vector<dof_id_type> pd_node_neighbors = pd_mesh.getNeighbors(i); // neighbors of a PD node
255  for (unsigned int j = 0; j < pd_node_neighbors.size(); ++j)
256  if (pd_node_neighbors[j] > i)
257  {
258  SubdomainID bid_i = pd_mesh.getNodeBlockID(i);
259  SubdomainID bid_j = pd_mesh.getNodeBlockID(pd_node_neighbors[j]);
260  Elem * new_elem = new Edge2;
261  new_elem->set_id(new_elem_id);
262  if (bid_i == bid_j) // assign block ID to PD non-interfacial elems
264  new_elem->subdomain_id() = min_converted_fe_blk_id + 1000;
265  else
266  new_elem->subdomain_id() = bid_i;
267  else if (_single_interface_blk) // assign block ID (max_fe_blk_id + 1 + 1000) to all PD
268  // interfacial elems
269  new_elem->subdomain_id() = max_fe_blk_id + 1 + 1000;
270  else // assign a new block ID (node i blk ID + node j blk ID) to this PD interfacial elems
271  new_elem->subdomain_id() = bid_i + bid_j;
272 
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]);
276 
277  ++new_elem_id;
278  }
279  }
280 
281  if (_single_converted_blk) // update PD node block ID
282  pd_mesh.setNodeBlockID(min_converted_fe_blk_id + 1000);
283 
284  // then generate phantom elements for sidesets in PD mesh, this is optional
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])
289  {
290  bool should_add = false;
291  Elem * old_elem = old_mesh->elem_ptr(eidit);
292  if (_conv_blk_ids.count(old_elem->subdomain_id()))
293  {
294  std::vector<dof_id_type> node_ids;
295  if (new_mesh->mesh_dimension() == 2) // 2D
296  {
297  node_ids.resize(3);
298  node_ids[0] = fe_elem_pd_node_map.at(eidit);
299  Point p0 = *new_mesh->node_ptr(node_ids[0]);
300  // search for two more nodes to construct a phantom 3-node triangular element
301  if (old_elem->n_nodes() == 3 ||
302  old_elem->n_nodes() == 6) // original triangular FE elements: 3-node or 6-node
303  {
304  // check existence of counterclockwise nodes ordering
305  for (unsigned int i = 0; i < old_elem->n_neighbors(); ++i)
306  {
307  Elem * nb = old_elem->neighbor_ptr(i);
308  if (nb != nullptr)
309  {
310  for (unsigned int j = 0; j < nb->n_neighbors(); ++j)
311  {
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)
315  {
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()));
318  Real val =
319  (p1(1) - p0(1)) * (p2(0) - p1(0)) - (p1(0) - p0(0)) * (p2(1) - p1(1));
320  if (val < 0) // counterclockwise
321  {
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());
324  should_add = true;
325  }
326  }
327  }
328  }
329  }
330  }
331  else // original quadrilateral FE elements: 4-node, 8-node and 9-node
332  {
333  // find potential nodes for construction of the phantom triangular element
334  std::vector<dof_id_type> boundary_node_ids;
335  for (unsigned int i = 0; i < old_elem->n_neighbors(); ++i)
336  {
337  Elem * nb = old_elem->neighbor_ptr(i);
338  if (nb != nullptr)
339  {
340  if (fe_sbnd_elem_ids[bidit].count(nb->id()))
341  boundary_node_ids.push_back(fe_elem_pd_node_map.at(nb->id()));
342  else
343  node_ids[2] = fe_elem_pd_node_map.at(nb->id());
344  }
345  }
346  // check existence of counterclockwise ordering based on the above found nodes
347  Point p2 = *new_mesh->node_ptr(node_ids[2]);
348  for (unsigned int i = 0; i < boundary_node_ids.size(); ++i)
349  {
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));
352  if (val < 0) // counterclockwise
353  {
354  node_ids[1] = boundary_node_ids[i];
355  should_add = true;
356  }
357  }
358  }
359 
360  if (should_add)
361  {
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;
366  else
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]);
372 
373  ++new_elem_id;
374 
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);
379  }
380  }
381  else // 3D
382  {
383  node_ids.resize(4);
384  node_ids[0] = fe_elem_pd_node_map.at(eidit);
385  Point p0 = *new_mesh->node_ptr(node_ids[0]);
386  // search for three more nodes to construct a phantom 4-node tetrahedral element
387 
388  if (old_elem->n_nodes() == 4 ||
389  old_elem->n_nodes() == 10) // original tetrahedral FE elements: 4-node or 10-node
390  {
391  // construct phantom element based on original tet mesh
392  mooseError("Peridynamics sideset generation doesn't accept tetrahedral elements!");
393  }
394  else // original hexahedral FE elements
395  {
396  std::vector<dof_id_type> boundary_elem_ids;
397  for (unsigned int i = 0; i < old_elem->n_neighbors(); ++i)
398  {
399  Elem * nb = old_elem->neighbor_ptr(i);
400  if (nb != nullptr)
401  {
402  if (fe_sbnd_elem_ids[bidit].count(nb->id()))
403  boundary_elem_ids.push_back(nb->id());
404  else
405  node_ids[3] = fe_elem_pd_node_map.at(nb->id());
406  }
407  }
408  // choose three nodes ordered in a way such that the normal points to the fourth node
409  Point p3 = *new_mesh->node_ptr(node_ids[3]);
410  for (unsigned int i = 0; i < boundary_elem_ids.size(); ++i)
411  {
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)
414  {
415  should_add = false;
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();
419  ++k) // check whether nb_i and nb_j shares two common neighbors
420  {
421  if (nb_j->neighbor_ptr(k) != nullptr &&
422  nb_i->has_neighbor(nb_j->neighbor_ptr(k)))
423  ++common_nb;
424  }
425  if (common_nb == 2)
426  {
427  should_add = true;
428  // check whether this new elem overlaps with already created elems by the saved
429  // edge and nodes of previously created phantom elems
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]);
433  else
434  pair = std::make_pair(boundary_elem_ids[i], eidit);
435 
436  if (elem_edge_node.count(pair))
437  {
438  for (const auto & nbid : elem_edge_node[pair])
439  if (nbid != old_elem->id() && old_mesh->elem_ptr(nbid)->has_neighbor(nb_j))
440  should_add = false;
441  }
442 
443  if (eidit < boundary_elem_ids[j])
444  pair = std::make_pair(eidit, boundary_elem_ids[j]);
445  else
446  pair = std::make_pair(boundary_elem_ids[j], eidit);
447  if (elem_edge_node.count(pair))
448  {
449  for (const auto & nbid : elem_edge_node[pair])
450  if (nbid != old_elem->id() && old_mesh->elem_ptr(nbid)->has_neighbor(nb_i))
451  should_add = false;
452  }
453 
454  if (should_add)
455  {
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]));
458  // check whether the normal of face formed by p0, p1 and p2 points to p3
459  Real val =
460  ((p1(1) - p0(1)) * (p2(2) - p0(2)) - (p1(2) - p0(2)) * (p2(1) - p0(1))) *
461  (p3(0) - p0(0)) +
462  ((p1(2) - p0(2)) * (p2(0) - p0(0)) - (p1(0) - p0(0)) * (p2(2) - p0(2))) *
463  (p3(1) - p0(1)) +
464  ((p1(0) - p0(0)) * (p2(1) - p0(1)) - (p1(1) - p0(1)) * (p2(0) - p0(0))) *
465  (p3(2) - p0(2));
466  if (val > 0) // normal point to p3
467  {
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]);
470  }
471  else
472  {
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]);
475  }
476 
477  // construct the new phantom element
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;
482  else
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]);
489 
490  // save the edges and nodes used in the new phantom elem
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]);
494  else
495  elem_edge_node[std::make_pair(boundary_elem_ids[i], eidit)].insert(
496  boundary_elem_ids[j]);
497 
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]);
501  else
502  elem_edge_node[std::make_pair(boundary_elem_ids[j], eidit)].insert(
503  boundary_elem_ids[i]);
504 
505  ++new_elem_id;
506 
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);
511  }
512  }
513  }
514  }
515  }
516  }
517  }
518  }
519 
520  // next, save non-converted or retained FE elements if any to new mesh
521  std::map<dof_id_type, dof_id_type> fe_elems_map; // IDs of the same elem in the old and new meshes
522  for (const auto & eid : fe_elems_ids)
523  {
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()));
531 
532  fe_elems_map.insert(std::make_pair(old_elem->id(), new_elem_id));
533 
534  ++new_elem_id;
535  }
536 
537  // STEP 5: convert old boundary_info to new boundary_info
538 
539  // peridynamics ONLY accept nodesets and sidesets
540  // nodeset consisting single node in the converted FE block will no longer be available
541  if (old_boundary_info.n_edge_conds())
542  mooseError("PeridynamicsMesh doesn't support edgesets!");
543 
544  // check the existence of nodesets, if exist, build sidesets in case this hasn't been done yet
545  if (old_boundary_info.n_nodeset_conds())
546  old_boundary_info.build_side_list_from_node_list();
547 
548  // first, create a tuple to collect all sidesets (including those converted from nodesets) in the
549  // old mesh
550  auto old_fe_sbc_tuples = old_boundary_info.build_side_list();
551  // 0: element ID, 1: side ID, 2: boundary ID
552  // map of set of elem IDs connected to each boundary in the old mesh
553  std::map<boundary_id_type, std::set<dof_id_type>> old_fe_bnd_elem_ids;
554  // map of set of side ID for each elem in the old mesh
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)
557  {
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)));
561  }
562 
563  // next, convert element lists in old mesh to PD nodesets in new mesh
564  std::set<boundary_id_type> old_side_bid(old_boundary_info.get_side_boundary_ids());
565 
566  // loop through all old FE _sideset_ boundaries
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)) // for converted FE mesh
570  {
571  // save corresponding boundaries on converted FE mesh to PD nodes
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);
576 
577  if (_retain_fe_mesh) // if retained, copy the corresponding boundaries, if any, to new mesh
578  // from old mesh
579  {
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);
583  }
584  }
585  else // for non-converted FE mesh, if any, copy the corresponding boundaries to new mesh
586  // from old mesh
587  {
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);
591  }
592 
593  // similar for sideset above, save _nodesets_ of non-converted and/or retained FE mesh, if any, to
594  // new mesh
595  auto old_node_bc_tuples = old_boundary_info.build_node_list();
596  // 0: node ID, 1: boundary ID
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));
600 
601  std::set<boundary_id_type> old_node_bid(old_boundary_info.get_node_boundary_ids());
602 
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))
606  {
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);
609  }
610 
611  // create nodesets to include all PD nodes for PD blocks in the new mesh
612  for (unsigned int i = 0; i < n_pd_nodes; ++i)
613  {
614  if (_conv_blk_ids.size() > 1 && !_single_converted_blk)
615  {
616  unsigned int j = 0;
617  for (const auto & blk_id : _conv_blk_ids)
618  {
619  ++j;
620  SubdomainID real_blk_id =
621  blk_id + 1000; // account for the 1000 increment after converting to PD mesh
622  if (pd_mesh.getNodeBlockID(i) == real_blk_id)
623  {
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);
627  }
628  }
629  }
630 
631  new_boundary_info.add_node(new_mesh->node_ptr(i), 999);
632  new_boundary_info.nodeset_name(999) = "pd_nodes_all";
633  }
634 
635  old_mesh.reset(); // destroy the old_mesh unique_ptr
636 
637  return dynamic_pointer_cast<MeshBase>(new_mesh);
638 }

Member Data Documentation

◆ _connect_blk_id_pairs

std::multimap<SubdomainID, SubdomainID> MeshGeneratorPD::_connect_blk_id_pairs
protected

Definition at line 62 of file MeshGeneratorPD.h.

Referenced by generate(), and MeshGeneratorPD().

◆ _construct_pd_sideset

bool MeshGeneratorPD::_construct_pd_sideset
protected

flag to specify whether PD sideset should be constructed or not

Definition at line 57 of file MeshGeneratorPD.h.

Referenced by generate().

◆ _conv_blk_ids

std::set<SubdomainID> MeshGeneratorPD::_conv_blk_ids
protected

Definition at line 41 of file MeshGeneratorPD.h.

Referenced by generate(), and MeshGeneratorPD().

◆ _has_connect_blk_id_pairs

bool MeshGeneratorPD::_has_connect_blk_id_pairs
protected

pairs of converted FE block IDs when only certain blocks need to be connected using interfacial bonds this is used when there are listable to-be-connected blocks

Definition at line 61 of file MeshGeneratorPD.h.

Referenced by MeshGeneratorPD().

◆ _has_conv_blk_ids

bool MeshGeneratorPD::_has_conv_blk_ids
protected

block ID(s) of input FE mesh when only certain block(s) needs to be converted to PD mesh this is used when there are listable to-be-converted blocks

Definition at line 40 of file MeshGeneratorPD.h.

Referenced by generate(), and MeshGeneratorPD().

◆ _has_non_connect_blk_id_pairs

bool MeshGeneratorPD::_has_non_connect_blk_id_pairs
protected

pairs of converted FE block IDs when only certain blocks need NOT to be connected this is usually used when there are considerable to-be-connected blocks but a few not to be connected

Definition at line 66 of file MeshGeneratorPD.h.

Referenced by MeshGeneratorPD().

◆ _has_non_conv_blk_ids

bool MeshGeneratorPD::_has_non_conv_blk_ids
protected

block ID(s) of input FE mesh when only certain block(s) needs NOT to be converted to PD mesh this is usually used when there are considerable to-be-converted blocks but a few not to be converted

Definition at line 45 of file MeshGeneratorPD.h.

Referenced by generate(), and MeshGeneratorPD().

◆ _input

std::unique_ptr<MeshBase>& MeshGeneratorPD::_input
protected

Reference to the input finite element mesh.

Definition at line 36 of file MeshGeneratorPD.h.

Referenced by generate().

◆ _non_connect_blk_id_pairs

std::multimap<SubdomainID, SubdomainID> MeshGeneratorPD::_non_connect_blk_id_pairs
protected

Definition at line 67 of file MeshGeneratorPD.h.

Referenced by generate(), and MeshGeneratorPD().

◆ _non_conv_blk_ids

std::set<SubdomainID> MeshGeneratorPD::_non_conv_blk_ids
protected

Definition at line 46 of file MeshGeneratorPD.h.

Referenced by generate(), and MeshGeneratorPD().

◆ _retain_fe_mesh

bool MeshGeneratorPD::_retain_fe_mesh
protected

flag to specify whether the FE mesh should be retained or not in addition to newly created PD mesh

Definition at line 50 of file MeshGeneratorPD.h.

Referenced by generate().

◆ _single_converted_blk

bool MeshGeneratorPD::_single_converted_blk
protected

flag to specify whether to combine converted PD mesh blocks into a single mesh block or not this is used when all PD blocks have the same properties

Definition at line 54 of file MeshGeneratorPD.h.

Referenced by generate().

◆ _single_interface_blk

bool MeshGeneratorPD::_single_interface_blk
protected

flag to specify whether a single block should be used for all interfacial bonds this is used when all interfacial bonds have the same properties

Definition at line 71 of file MeshGeneratorPD.h.

Referenced by generate().


The documentation for this class was generated from the following files:
MeshGeneratorPD::_conv_blk_ids
std::set< SubdomainID > _conv_blk_ids
Definition: MeshGeneratorPD.h:41
MeshGeneratorPD::_retain_fe_mesh
bool _retain_fe_mesh
flag to specify whether the FE mesh should be retained or not in addition to newly created PD mesh
Definition: MeshGeneratorPD.h:50
PeridynamicsMesh::getNodeBlockID
SubdomainID getNodeBlockID(dof_id_type node_id)
Function to return block ID for node node_id.
Definition: PeridynamicsMesh.C:405
MeshGeneratorPD::_input
std::unique_ptr< MeshBase > & _input
Reference to the input finite element mesh.
Definition: MeshGeneratorPD.h:36
MeshGeneratorPD::_non_connect_blk_id_pairs
std::multimap< SubdomainID, SubdomainID > _non_connect_blk_id_pairs
Definition: MeshGeneratorPD.h:67
MeshGeneratorPD::_non_conv_blk_ids
std::set< SubdomainID > _non_conv_blk_ids
Definition: MeshGeneratorPD.h:46
MeshGeneratorPD::_has_connect_blk_id_pairs
bool _has_connect_blk_id_pairs
pairs of converted FE block IDs when only certain blocks need to be connected using interfacial bonds...
Definition: MeshGeneratorPD.h:61
MeshGeneratorPD::_single_converted_blk
bool _single_converted_blk
flag to specify whether to combine converted PD mesh blocks into a single mesh block or not this is u...
Definition: MeshGeneratorPD.h:54
MeshGeneratorPD::_has_conv_blk_ids
bool _has_conv_blk_ids
block ID(s) of input FE mesh when only certain block(s) needs to be converted to PD mesh this is used...
Definition: MeshGeneratorPD.h:40
MeshGeneratorPD::_single_interface_blk
bool _single_interface_blk
flag to specify whether a single block should be used for all interfacial bonds this is used when all...
Definition: MeshGeneratorPD.h:71
PeridynamicsMesh::createPeridynamicsMeshData
void createPeridynamicsMeshData(MeshBase &fe_mesh, std::set< dof_id_type > converted_elem_id, std::multimap< SubdomainID, SubdomainID > connect_block_id_pairs, std::multimap< SubdomainID, SubdomainID > non_connect_block_id_pairs)
Function to assign values to member variables (PD mesh data) of this class this function will be call...
Definition: PeridynamicsMesh.C:138
PeridynamicsMesh
Peridynamics mesh class.
Definition: PeridynamicsMesh.h:25
MeshGeneratorPD::_construct_pd_sideset
bool _construct_pd_sideset
flag to specify whether PD sideset should be constructed or not
Definition: MeshGeneratorPD.h:57
PeridynamicsMesh::setNodeBlockID
void setNodeBlockID(SubdomainID id)
Function to set block ID for all PD nodes.
Definition: PeridynamicsMesh.C:414
MeshGeneratorPD::_connect_blk_id_pairs
std::multimap< SubdomainID, SubdomainID > _connect_blk_id_pairs
Definition: MeshGeneratorPD.h:62
PeridynamicsMesh::nPDBonds
dof_id_type nPDBonds() const
Function to return number of PD Edge elements.
Definition: PeridynamicsMesh.C:132
PeridynamicsMesh::getNeighbors
std::vector< dof_id_type > getNeighbors(dof_id_type node_id)
Function to return neighbor nodes indices for node node_id.
Definition: PeridynamicsMesh.C:362
MeshGeneratorPD::_has_non_connect_blk_id_pairs
bool _has_non_connect_blk_id_pairs
pairs of converted FE block IDs when only certain blocks need NOT to be connected this is usually use...
Definition: MeshGeneratorPD.h:66
PeridynamicsMesh::nPDNodes
dof_id_type nPDNodes() const
Function to return number of PD nodes.
Definition: PeridynamicsMesh.C:126
MeshGeneratorPD::_has_non_conv_blk_ids
bool _has_non_conv_blk_ids
block ID(s) of input FE mesh when only certain block(s) needs NOT to be converted to PD mesh this is ...
Definition: MeshGeneratorPD.h:45