https://mooseframework.inl.gov
Public Types | Public Member Functions | Static Public Member Functions | Public Attributes | Static Public Attributes | Protected Member Functions | Static Protected 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 Types

typedef DataFileName DataFileParameterType
 

Public Member Functions

 MeshGeneratorPD (const InputParameters &parameters)
 
std::unique_ptr< MeshBase > generate ()
 Function to convert the finite element mesh to peridynamics mesh. More...
 
std::unique_ptr< MeshBase > generateInternal ()
 
const std::set< MeshGeneratorName > & getRequestedMeshGenerators () const
 
const std::set< MeshGeneratorName > & getRequestedMeshGeneratorsForSub () const
 
void addParentMeshGenerator (const MeshGenerator &mg, const AddParentChildKey)
 
void addChildMeshGenerator (const MeshGenerator &mg, const AddParentChildKey)
 
const std::set< const MeshGenerator *, Comparator > & getParentMeshGenerators () const
 
const std::set< const MeshGenerator *, Comparator > & getChildMeshGenerators () const
 
const std::set< const MeshGenerator *, Comparator > & getSubMeshGenerators () const
 
bool isParentMeshGenerator (const MeshGeneratorName &name, const bool direct=true) const
 
bool isChildMeshGenerator (const MeshGeneratorName &name, const bool direct=true) const
 
bool isNullMeshName (const MeshGeneratorName &name) const
 
bool hasSaveMesh () const
 
bool hasOutput () const
 
const std::string & getSavedMeshName () const
 
bool hasGenerateData () const
 
bool isDataOnly () const
 
virtual bool enabled () const
 
std::shared_ptr< MooseObjectgetSharedPtr ()
 
std::shared_ptr< const MooseObjectgetSharedPtr () const
 
MooseAppgetMooseApp () const
 
const std::string & type () const
 
virtual const std::string & name () const
 
std::string typeAndName () const
 
std::string errorPrefix (const std::string &error_type) const
 
void callMooseError (std::string msg, const bool with_prefix) const
 
MooseObjectParameterName uniqueParameterName (const std::string &parameter_name) const
 
const InputParametersparameters () const
 
MooseObjectName uniqueName () const
 
const T & getParam (const std::string &name) const
 
std::vector< std::pair< T1, T2 > > getParam (const std::string &param1, const std::string &param2) const
 
const T * queryParam (const std::string &name) const
 
const T & getRenamedParam (const std::string &old_name, const std::string &new_name) const
 
getCheckedPointerParam (const std::string &name, const std::string &error_string="") const
 
bool isParamValid (const std::string &name) const
 
bool isParamSetByUser (const std::string &nm) const
 
void paramError (const std::string &param, Args... args) const
 
void paramWarning (const std::string &param, Args... args) const
 
void paramInfo (const std::string &param, Args... args) const
 
void connectControllableParams (const std::string &parameter, const std::string &object_type, const std::string &object_name, const std::string &object_parameter) const
 
void mooseError (Args &&... args) const
 
void mooseErrorNonPrefixed (Args &&... args) const
 
void mooseDocumentedError (const std::string &repo_name, const unsigned int issue_num, Args &&... args) const
 
void mooseWarning (Args &&... args) const
 
void mooseWarningNonPrefixed (Args &&... args) const
 
void mooseDeprecated (Args &&... args) const
 
void mooseInfo (Args &&... args) const
 
std::string getDataFileName (const std::string &param) const
 
std::string getDataFileNameByName (const std::string &relative_path) const
 
std::string getDataFilePath (const std::string &relative_path) const
 
const Parallel::Communicator & comm () const
 
processor_id_type n_processors () const
 
processor_id_type processor_id () const
 

Static Public Member Functions

static InputParameters validParams ()
 
static bool hasGenerateData (const InputParameters &params)
 
static void setHasGenerateData (InputParameters &params)
 

Public Attributes

const ConsoleStream _console
 

Static Public Attributes

static const std::string data_only_param
 
static constexpr auto SYSTEM
 
static constexpr auto NAME
 

Protected Member Functions

virtual void generateData ()
 
T & copyMeshProperty (const std::string &target_data_name, const std::string &source_data_name, const std::string &source_mesh)
 
T & copyMeshProperty (const std::string &source_data_name, const std::string &source_mesh)
 
std::unique_ptr< MeshBase > & getMesh (const std::string &param_name, const bool allow_invalid=false)
 
std::vector< std::unique_ptr< MeshBase > *> getMeshes (const std::string &param_name)
 
std::unique_ptr< MeshBase > & getMeshByName (const MeshGeneratorName &mesh_generator_name)
 
std::vector< std::unique_ptr< MeshBase > *> getMeshesByName (const std::vector< MeshGeneratorName > &mesh_generator_names)
 
void declareMeshForSub (const std::string &param_name)
 
void declareMeshesForSub (const std::string &param_name)
 
void declareMeshForSubByName (const MeshGeneratorName &mesh_generator_name)
 
void declareMeshesForSubByName (const std::vector< MeshGeneratorName > &mesh_generator_names)
 
std::unique_ptr< MeshBase > buildMeshBaseObject (unsigned int dim=libMesh::invalid_uint)
 
std::unique_ptr< ReplicatedMesh > buildReplicatedMesh (unsigned int dim=libMesh::invalid_uint)
 
std::unique_ptr< DistributedMesh > buildDistributedMesh (unsigned int dim=libMesh::invalid_uint)
 
void addMeshSubgenerator (const std::string &type, const std::string &name, Ts... extra_input_parameters)
 
void addMeshSubgenerator (const std::string &type, const std::string &name, InputParameters params)
 
void declareNullMeshName (const MeshGeneratorName &name)
 
const T & getMeshProperty (const std::string &data_name, const std::string &prefix)
 
const T & getMeshProperty (const std::string &data_name)
 
bool hasMeshProperty (const std::string &data_name, const std::string &prefix) const
 
bool hasMeshProperty (const std::string &data_name, const std::string &prefix) const
 
bool hasMeshProperty (const std::string &data_name) const
 
bool hasMeshProperty (const std::string &data_name) const
 
std::string meshPropertyName (const std::string &data_name) const
 
T & declareMeshProperty (const std::string &data_name, Args &&... args)
 
T & declareMeshProperty (const std::string &data_name, const T &data_value)
 
T & declareMeshProperty (const std::string &data_name, Args &&... args)
 
T & declareMeshProperty (const std::string &data_name, const T &data_value)
 
T & setMeshProperty (const std::string &data_name, Args &&... args)
 
T & setMeshProperty (const std::string &data_name, const T &data_value)
 
T & setMeshProperty (const std::string &data_name, Args &&... args)
 
T & setMeshProperty (const std::string &data_name, const T &data_value)
 

Static Protected Member Functions

static std::string meshPropertyName (const std::string &data_name, const std::string &prefix)
 

Protected Attributes

unsigned int _pd_blk_offset_number = 1000
 a number used to offset the block ID after being converted into PD mesh More...
 
unsigned int _phantom_blk_offset_number = 10000
 a number used to offset the block ID for phantom elements More...
 
unsigned int _pd_nodeset_offset_number = 999
 a number used to offset the boundary nodeset ID after being converted into PD nodeset More...
 
std::unique_ptr< MeshBase > & _input
 Reference to the input finite element mesh. More...
 
bool _has_blks_to_pd
 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_blks_to_pd
 
bool _has_blks_as_fe
 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_blks_as_fe
 
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 _merge_pd_blks
 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_sidesets_to_pd
 list of sideset ID(s) to be constructed based on converted PD mesh if the _construct_pd_sideset is true More...
 
std::set< boundary_id_type_fe_sidesets_for_pd_construction
 
bool _has_bonding_blk_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_pd_bonding_blk_pairs
 
bool _has_non_bonding_blk_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_pd_non_bonding_blk_pairs
 
bool _merge_pd_interfacial_blks
 flag to specify whether a single block should be used for all PD interfacial blocks this is used when all interfacial bonds have the same properties More...
 
MooseMesh *const _mesh
 
const bool & _enabled
 
MooseApp_app
 
const std::string _type
 
const std::string _name
 
const InputParameters_pars
 
Factory_factory
 
ActionFactory_action_factory
 
const Parallel::Communicator & _communicator
 

Detailed Description

Generate peridynamics mesh based on finite element mesh.

Definition at line 19 of file MeshGeneratorPD.h.

Constructor & Destructor Documentation

◆ MeshGeneratorPD()

MeshGeneratorPD::MeshGeneratorPD ( const InputParameters parameters)

Definition at line 64 of file MeshGeneratorPD.C.

66  _input(getMesh("input")),
67  _has_blks_to_pd(isParamValid("blocks_to_pd")),
68  _has_blks_as_fe(isParamValid("blocks_as_fe")),
69  _retain_fe_mesh(getParam<bool>("retain_fe_mesh")),
70  _merge_pd_blks(getParam<bool>("merge_pd_blocks")),
71  _construct_pd_sideset(getParam<bool>("construct_pd_sidesets")),
72  _has_sidesets_to_pd(isParamValid("sidesets_to_pd")),
73  _has_bonding_blk_pairs(isParamValid("bonding_block_pairs")),
74  _has_non_bonding_blk_pairs(isParamValid("non_bonding_block_pairs")),
75  _merge_pd_interfacial_blks(getParam<bool>("merge_pd_interfacial_blocks"))
76 {
78  mooseError("Please specifiy either 'blocks_to_pd' or 'blocks_as_fe'!");
79 
80  if (_has_blks_as_fe)
81  {
82  std::vector<SubdomainID> ids = getParam<std::vector<SubdomainID>>("blocks_as_fe");
83  for (unsigned int i = 0; i < ids.size(); ++i)
84  _blks_as_fe.insert(ids[i]);
85  }
86 
87  if (_has_blks_to_pd)
88  {
89  std::vector<SubdomainID> ids = getParam<std::vector<SubdomainID>>("blocks_to_pd");
90  for (unsigned int i = 0; i < ids.size(); ++i)
91  _blks_to_pd.insert(ids[i]);
92  }
93 
95  mooseError("'sidesets_to_pd' is provided without setting "
96  "'construct_pd_sidesets' to 'true'!");
97 
99  {
100  std::vector<boundary_id_type> ids = getParam<std::vector<boundary_id_type>>("sidesets_to_pd");
101  for (unsigned int i = 0; i < ids.size(); ++i)
102  _fe_sidesets_for_pd_construction.insert(ids[i]);
103  }
104 
106  mooseError("Please specifiy either 'bonding_block_pairs' or "
107  "'non_bonding_block_pairs'!");
108 
109  _pd_bonding_blk_pairs.clear();
111  {
112  std::vector<std::vector<SubdomainID>> id_pairs =
113  getParam<std::vector<std::vector<SubdomainID>>>("bonding_block_pairs");
114 
115  for (unsigned int i = 0; i < id_pairs.size(); ++i)
116  _pd_bonding_blk_pairs.insert(std::make_pair(id_pairs[i][0] + _pd_blk_offset_number,
117  id_pairs[i][1] + _pd_blk_offset_number));
118  } // considered the renumbering of IDs of converted blocks
119 
122  {
123  std::vector<std::vector<SubdomainID>> id_pairs =
124  getParam<std::vector<std::vector<SubdomainID>>>("non_bonding_block_pairs");
125 
126  for (unsigned int i = 0; i < id_pairs.size(); ++i)
127  _pd_non_bonding_blk_pairs.insert(std::make_pair(id_pairs[i][0] + _pd_blk_offset_number,
128  id_pairs[i][1] + _pd_blk_offset_number));
129  } // considered the renumbering of IDs of converted blocks
130 }
std::set< boundary_id_type > _fe_sidesets_for_pd_construction
std::multimap< SubdomainID, SubdomainID > _pd_non_bonding_blk_pairs
std::set< SubdomainID > _blks_to_pd
std::multimap< SubdomainID, SubdomainID > _pd_bonding_blk_pairs
bool _merge_pd_interfacial_blks
flag to specify whether a single block should be used for all PD interfacial blocks this is used when...
bool _merge_pd_blks
flag to specify whether to combine converted PD mesh blocks into a single mesh block or not this is u...
MeshGenerator(const InputParameters &parameters)
bool _retain_fe_mesh
flag to specify whether the FE mesh should be retained or not in addition to newly created PD mesh ...
bool _has_non_bonding_blk_pairs
pairs of converted FE block IDs when only certain blocks need NOT to be connected this is usually use...
bool isParamValid(const std::string &name) const
bool _has_blks_to_pd
block ID(s) of input FE mesh when only certain block(s) needs to be converted to PD mesh this is used...
bool _has_sidesets_to_pd
list of sideset ID(s) to be constructed based on converted PD mesh if the _construct_pd_sideset is tr...
std::unique_ptr< MeshBase > & getMesh(const std::string &param_name, const bool allow_invalid=false)
std::unique_ptr< MeshBase > & _input
Reference to the input finite element mesh.
bool _has_blks_as_fe
block ID(s) of input FE mesh when only certain block(s) needs NOT to be converted to PD mesh this is ...
std::set< SubdomainID > _blks_as_fe
bool _has_bonding_blk_pairs
pairs of converted FE block IDs when only certain blocks need to be connected using interfacial bonds...
unsigned int _pd_blk_offset_number
a number used to offset the block ID after being converted into PD mesh
void mooseError(Args &&... args) const
const InputParameters & parameters() const
bool _construct_pd_sideset
flag to specify whether PD sideset should be constructed or not

Member Function Documentation

◆ generate()

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

Function to convert the finite element mesh to peridynamics mesh.

Returns
The converted mesh

Implements MeshGenerator.

Definition at line 133 of file MeshGeneratorPD.C.

134 {
135  // get the MeshBase object this generator will be working on
136  std::unique_ptr<MeshBase> old_mesh = std::move(_input);
137 
138  // STEP 1: obtain FE block(s) and elements to be converted to PD mesh
139 
140  // get the IDs of all available blocks in the input FE mesh
141  std::set<SubdomainID> all_fe_blks;
142  for (const auto & old_elem : old_mesh->element_ptr_range())
143  all_fe_blks.insert(old_elem->subdomain_id());
144 
145  // double check the existence of the block ids provided by user
146  if (_has_blks_to_pd)
147  for (const auto & blkit : _blks_to_pd)
148  if (!all_fe_blks.count(blkit))
149  mooseError("Block ID ", blkit, " in the 'blocks_to_pd' does not exist in the FE mesh!");
150 
151  if (_has_blks_as_fe)
152  for (const auto & blkit : _blks_as_fe)
153  if (!all_fe_blks.count(blkit))
154  mooseError("Block ID ", blkit, " in the 'blocks_as_fe' does not exist in the FE mesh!");
155 
156  // the maximum FE block ID, which will be used in determine the block ID for interfacial bond in
157  // the case of single interface block
158  const unsigned int max_fe_blk_id = *all_fe_blks.rbegin();
159 
160  // categorize mesh blocks into converted and non-converted blocks
161  if (_has_blks_to_pd)
162  std::set_difference(all_fe_blks.begin(),
163  all_fe_blks.end(),
164  _blks_to_pd.begin(),
165  _blks_to_pd.end(),
166  std::inserter(_blks_as_fe, _blks_as_fe.begin()));
167  else if (_has_blks_as_fe)
168  std::set_difference(all_fe_blks.begin(),
169  all_fe_blks.end(),
170  _blks_as_fe.begin(),
171  _blks_as_fe.end(),
172  std::inserter(_blks_to_pd, _blks_to_pd.begin()));
173  else // if no block ids provided by user, by default, convert all FE mesh to PD mesh
174  _blks_to_pd = all_fe_blks;
175 
177  {
178  for (const auto & blk_pair : _pd_bonding_blk_pairs)
179  {
180  if (!all_fe_blks.count(blk_pair.first - _pd_blk_offset_number))
181  mooseError("Block ID ",
182  blk_pair.first - _pd_blk_offset_number,
183  " in the 'bonding_block_pairs' does not exist in the FE mesh!");
184  if (!all_fe_blks.count(blk_pair.second - _pd_blk_offset_number))
185  mooseError("Block ID ",
186  blk_pair.second - _pd_blk_offset_number,
187  " in the 'bonding_block_pairs' does not exist in the FE mesh!");
188  if (!_blks_to_pd.count(blk_pair.first - _pd_blk_offset_number))
189  mooseError("Block ID ",
190  blk_pair.first - _pd_blk_offset_number,
191  " in the 'bonding_block_pairs' is a FE mesh block!");
192  if (!_blks_to_pd.count(blk_pair.second - _pd_blk_offset_number))
193  mooseError("Block ID ",
194  blk_pair.second - _pd_blk_offset_number,
195  " in the 'bonding_block_pairs' is a FE mesh block!");
196  }
197  }
198 
200  for (const auto & blk_pair : _pd_non_bonding_blk_pairs)
201  {
202  if (!all_fe_blks.count(blk_pair.first - _pd_blk_offset_number))
203  mooseError("Block ID ",
204  blk_pair.first - _pd_blk_offset_number,
205  " in the 'non_bonding_block_pairs' does not exist in the FE mesh!");
206  if (!all_fe_blks.count(blk_pair.second - _pd_blk_offset_number))
207  mooseError("Block ID ",
208  blk_pair.second - _pd_blk_offset_number,
209  " in the 'non_bonding_block_pairs' does not exist in the FE mesh!");
210  if (!_blks_as_fe.count(blk_pair.first - _pd_blk_offset_number))
211  mooseError("Block ID ",
212  blk_pair.first - _pd_blk_offset_number,
213  " in the 'non_bonding_block_pairs' is a FE mesh block!");
214  if (!_blks_as_fe.count(blk_pair.second - _pd_blk_offset_number))
215  mooseError("Block ID ",
216  blk_pair.second - _pd_blk_offset_number,
217  " in the 'non_bonding_block_pairs' is a FE mesh block!");
218  }
219 
220  // the minimum converted FE block ID, which will be used to assign block ID for non-interfacial
221  // bond in the case of combine converted blocks
222  const unsigned int min_converted_fe_blk_id = *_blks_to_pd.begin();
223 
224  // IDs of to-be-converted FE elems
225  std::set<dof_id_type> elems_to_pd;
226  // retained FE mesh and non-converted FE mesh, if any
227  std::set<dof_id_type> fe_nodes;
228  std::set<dof_id_type> fe_elems;
229  for (const auto & old_elem : old_mesh->element_ptr_range())
230  if (_blks_to_pd.count(old_elem->subdomain_id())) // record to-be-converted FE elem IDs
231  {
232  elems_to_pd.insert(old_elem->id());
233  if (_retain_fe_mesh) // save converted elems and their nodes if need to be retained
234  {
235  fe_elems.insert(old_elem->id());
236  for (unsigned int i = 0; i < old_elem->n_nodes(); ++i)
237  fe_nodes.insert(old_elem->node_id(i));
238  }
239  }
240  else // save non-converted elements and their nodes
241  {
242  fe_elems.insert(old_elem->id());
243  for (unsigned int i = 0; i < old_elem->n_nodes(); ++i)
244  fe_nodes.insert(old_elem->node_id(i));
245  }
246 
247  // number of FE elements and nodes in the old mesh to be saved in the new mesh
248  dof_id_type n_fe_nodes = fe_nodes.size();
249  dof_id_type n_fe_elems = fe_elems.size();
250  dof_id_type n_phantom_elems = 0;
251 
252  // determine the number of phantom elements to be generated in the new mesh based on sideset in
253  // old mesh
254  BoundaryInfo & old_boundary_info = old_mesh->get_boundary_info();
255  const std::set<boundary_id_type> & all_fe_sidesets = old_boundary_info.get_side_boundary_ids();
256 
257  // double check the existence of the sideset ids provided by user
259  {
260  for (const auto & sideset : _fe_sidesets_for_pd_construction)
261  if (!all_fe_sidesets.count(sideset))
262  mooseError("Sideset ID ",
263  sideset,
264  " in the 'sidesets_to_pd' does not exist in the finite "
265  "element mesh!");
266  }
267  else // save the IDs of all FE sidesets, this will be updated to the converted FE block later
268  _fe_sidesets_for_pd_construction = all_fe_sidesets;
269 
270  // determine number of FE side elements, the number of actual phantom elements is less than or
271  // equal to the number of FE side elements, this number is used to reserve number of elements
272  // in the new mesh only
273  std::map<boundary_id_type, std::set<dof_id_type>> fe_bid_eid;
274  auto fe_sbc_tuples = old_boundary_info.build_side_list();
275  // 0: element ID, 1: side ID, 2: boundary ID
276  for (const auto & sbct : fe_sbc_tuples)
278  std::get<2>(sbct))) // save elements of to-be-constructed sidesets only
279  {
280  fe_bid_eid[std::get<2>(sbct)].insert(std::get<0>(sbct));
281  ++n_phantom_elems;
282  }
283 
284  // STEP 2: generate PD data based on to-be-converted FE mesh and prepare for new mesh
285 
286  PeridynamicsMesh & pd_mesh = dynamic_cast<PeridynamicsMesh &>(*_mesh);
287  // generate PD node data, including neighbors
289  *old_mesh, elems_to_pd, _pd_bonding_blk_pairs, _pd_non_bonding_blk_pairs);
290 
291  // number of PD elements and nodes to be created
292  dof_id_type n_pd_nodes = pd_mesh.nPDNodes();
293  dof_id_type n_pd_bonds = pd_mesh.nPDBonds();
294 
295  // initialize an empty new mesh object
296  std::unique_ptr<MeshBase> new_mesh = buildMeshBaseObject();
297  new_mesh->clear();
298  // set new mesh dimension
299  new_mesh->set_mesh_dimension(old_mesh->mesh_dimension());
300  new_mesh->set_spatial_dimension(old_mesh->spatial_dimension());
301  // reserve elements and nodes for the new mesh
302  new_mesh->reserve_nodes(n_pd_nodes + n_fe_nodes);
303  new_mesh->reserve_elem(n_pd_bonds + n_fe_elems + n_phantom_elems);
304 
305  BoundaryInfo & new_boundary_info = new_mesh->get_boundary_info();
306 
307  // STEP 3: add points of PD and FE (retained and/or non-converted) nodes, if any, to new mesh
308 
309  // save PD nodes to new mesh first
310  unsigned int new_node_id = 0;
311  // map of IDs of converted FE elements and PD nodes
312  std::map<dof_id_type, dof_id_type> fe_elem_pd_node_map;
313  for (const auto & eid : elems_to_pd)
314  {
315  new_mesh->add_point(old_mesh->elem_ptr(eid)->vertex_average(), new_node_id);
316  fe_elem_pd_node_map.insert(std::make_pair(eid, new_node_id));
317 
318  ++new_node_id;
319  }
320  // then save both retained and non-converted FE nodes, if any, to the new mesh
321  // map of IDs of the same point in old and new meshes
322  std::map<dof_id_type, dof_id_type> fe_nodes_map;
323  for (const auto & nid : fe_nodes)
324  {
325  new_mesh->add_point(*old_mesh->node_ptr(nid), new_node_id);
326  fe_nodes_map.insert(std::make_pair(old_mesh->node_ptr(nid)->id(), new_node_id));
327 
328  ++new_node_id;
329  }
330 
331  // STEP 4: generate PD, phantom, and FE elems using retained and/or non-converted meshes if any
332 
333  // first, generate PD elements for new mesh
334  unsigned int new_elem_id = 0;
335  for (unsigned int i = 0; i < n_pd_nodes; ++i)
336  {
337  std::vector<dof_id_type> pd_node_neighbors = pd_mesh.getNeighbors(i); // neighbors of a PD node
338  for (unsigned int j = 0; j < pd_node_neighbors.size(); ++j)
339  if (pd_node_neighbors[j] > i)
340  {
341  SubdomainID bid_i = pd_mesh.getNodeBlockID(i);
342  SubdomainID bid_j = pd_mesh.getNodeBlockID(pd_node_neighbors[j]);
343  Elem * new_elem = new Edge2;
344  new_elem->set_id(new_elem_id);
345  if (bid_i == bid_j) // assign block ID to PD non-inter-block bonds
346  if (_merge_pd_blks)
347  new_elem->subdomain_id() = min_converted_fe_blk_id + _pd_blk_offset_number;
348  else
349  new_elem->subdomain_id() = bid_i;
350  else if (_merge_pd_interfacial_blks) // assign block ID (max_fe_blk_id + 1 +
351  // _pd_blk_offset_number) to all PD inter-block bonds
352  new_elem->subdomain_id() = max_fe_blk_id + 1 + _pd_blk_offset_number;
353  else // assign a new block ID (node i blk ID + node j blk ID) to this PD inter-block bonds
354  new_elem->subdomain_id() = bid_i + bid_j;
355 
356  new_elem = new_mesh->add_elem(new_elem);
357  new_elem->set_node(0, new_mesh->node_ptr(i));
358  new_elem->set_node(1, new_mesh->node_ptr(pd_node_neighbors[j]));
359 
360  ++new_elem_id;
361  }
362  }
363 
364  if (_merge_pd_blks) // update PD node block ID if use single block ID for all PD blocks
365  pd_mesh.setNodeBlockID(min_converted_fe_blk_id + _pd_blk_offset_number);
366 
367  // then generate phantom elements for sidesets in PD mesh, this is optional
368  std::map<std::pair<dof_id_type, dof_id_type>, std::set<dof_id_type>> elem_edge_nodes;
370  {
371  for (const auto & bidit : _fe_sidesets_for_pd_construction)
372  {
373  for (const auto & eidit : fe_bid_eid[bidit])
374  {
375  bool should_add = false;
376  Elem * old_elem = old_mesh->elem_ptr(eidit);
377  if (_blks_to_pd.count(
378  old_elem->subdomain_id())) // limit the sidesets to the converted FE blocks only
379  {
380  std::vector<dof_id_type> pd_nodes;
381  Point p0, p1, p2, p3;
382 
383  if (old_elem->dim() == 2) // 2D: construct 3-node triangular phanton elems
384  {
385  pd_nodes.resize(3);
386  // the current elem on the boundary side is the first node of a phantom element
387  pd_nodes[0] = fe_elem_pd_node_map.at(eidit);
388  p0 = *new_mesh->node_ptr(pd_nodes[0]);
389 
390  // search for two more nodes to construct a phantom 3-node triangular element
391  if (old_elem->n_nodes() == 3 ||
392  old_elem->n_nodes() == 6) // original triangular FE elements: 3-node or 6-node
393  {
394  // one special case of triangular mesh: two elems share a boundary node
395  bool has_neighbor_on_boundary = false;
396  for (unsigned int i = 0; i < old_elem->n_neighbors(); ++i)
397  {
398  Elem * nb = old_elem->neighbor_ptr(i);
399  if (nb != nullptr)
400  {
401  if (fe_bid_eid[bidit].count(nb->id()))
402  {
403  has_neighbor_on_boundary = true;
404  pd_nodes[1] = fe_elem_pd_node_map.at(nb->id());
405  p1 = *new_mesh->node_ptr(pd_nodes[1]);
406  }
407  else
408  {
409  pd_nodes[2] = fe_elem_pd_node_map.at(nb->id());
410  p2 = *new_mesh->node_ptr(pd_nodes[2]);
411  }
412  }
413  }
414 
415  if (has_neighbor_on_boundary &&
416  (p1(1) - p0(1)) * (p2(0) - p1(0)) - (p1(0) - p0(0)) * (p2(1) - p1(1)) < 0)
417  {
418  should_add = true;
419  }
420  else // common case of triangular mesh: three elems share a boundary node
421  {
422  for (unsigned int i = 0; i < old_elem->n_neighbors(); ++i)
423  {
424  Elem * nb = old_elem->neighbor_ptr(i);
425 
426  if (nb != nullptr)
427  {
428  p2 = *new_mesh->node_ptr(fe_elem_pd_node_map.at(nb->id()));
429 
430  for (unsigned int j = 0; j < nb->n_neighbors(); ++j)
431  {
432  Elem * nb_nb = nb->neighbor_ptr(j);
433 
434  if (nb_nb != nullptr && fe_bid_eid[bidit].count(nb_nb->id()) &&
435  nb_nb->id() != eidit)
436  {
437  p1 = *new_mesh->node_ptr(fe_elem_pd_node_map.at(nb_nb->id()));
438 
439  // add new phantom elem only if (p0, p1, p2) is counterclockwisely ordered
440  if ((p1(1) - p0(1)) * (p2(0) - p1(0)) - (p1(0) - p0(0)) * (p2(1) - p1(1)) <
441  0)
442  {
443  should_add = true;
444  pd_nodes[1] = fe_elem_pd_node_map.at(nb_nb->id());
445  pd_nodes[2] = fe_elem_pd_node_map.at(nb->id());
446  }
447  }
448  }
449 
450  if (!should_add) // if using the neighbor's neighbor is not a success
451  {
452  // one special case of triangular mesh: four elems share a boundary node
453  // other cases of more than four elems share a boundary node is not considered
454  for (unsigned int i = 0; i < old_elem->n_neighbors(); ++i)
455  {
456  Elem * nb = old_elem->neighbor_ptr(i);
457 
458  if (nb != nullptr)
459  {
460  p2 = *new_mesh->node_ptr(fe_elem_pd_node_map.at(nb->id()));
461 
462  for (unsigned int j = 0; j < nb->n_neighbors(); ++j)
463  {
464  Elem * nb_nb = nb->neighbor_ptr(j);
465  if (nb_nb != nullptr && nb_nb->id() != eidit)
466  {
467  for (unsigned int k = 0; k < nb_nb->n_neighbors(); ++k)
468  {
469  Elem * nb_nb_nb = nb_nb->neighbor_ptr(k);
470 
471  if (nb_nb_nb != nullptr &&
472  fe_bid_eid[bidit].count(nb_nb_nb->id()) &&
473  nb_nb_nb->id() != eidit)
474  {
475  p1 = *new_mesh->node_ptr(fe_elem_pd_node_map.at(nb_nb_nb->id()));
476 
477  // add new phantom elem only if (p0, p1, p2) is counterclockwisely
478  // ordered
479  if ((p1(1) - p0(1)) * (p2(0) - p1(0)) -
480  (p1(0) - p0(0)) * (p2(1) - p1(1)) <
481  0)
482  {
483  should_add = true;
484  pd_nodes[1] = fe_elem_pd_node_map.at(nb_nb_nb->id());
485  pd_nodes[2] = fe_elem_pd_node_map.at(nb->id());
486  }
487  }
488  }
489  }
490  }
491  }
492  }
493  }
494  }
495  }
496  }
497  }
498  else if (old_elem->n_nodes() == 4 || old_elem->n_nodes() == 8 ||
499  old_elem->n_nodes() ==
500  9) // original quadrilateral FE elements: 4-node, 8-node and 9-node
501  {
502  std::vector<dof_id_type> pd_boundary_node_ids;
503  for (unsigned int i = 0; i < old_elem->n_neighbors(); ++i)
504  {
505  Elem * nb = old_elem->neighbor_ptr(i);
506  if (nb != nullptr && fe_bid_eid[bidit].count(nb->id()))
507  pd_boundary_node_ids.push_back(fe_elem_pd_node_map.at(nb->id()));
508  }
509  // the neighbor opposite to the boundary side is the third node for the phantom elem
510  pd_nodes[2] = fe_elem_pd_node_map.at(
511  old_elem
512  ->neighbor_ptr(old_elem->opposite_side(
513  old_boundary_info.side_with_boundary_id(old_elem, bidit)))
514  ->id());
515  p2 = *new_mesh->node_ptr(pd_nodes[2]);
516 
517  // if two boundary neighbors, one of them is the second node for the phantom elem
518  // if one boundary neighbors, it is the second node for the phantom elem
519  for (unsigned int i = 0; i < pd_boundary_node_ids.size(); ++i)
520  {
521  p1 = *new_mesh->node_ptr(pd_boundary_node_ids[i]);
522 
523  // new phantom elem only if (p0, p1, p2) is counterclockwisely orderd
524  if ((p1(1) - p0(1)) * (p2(0) - p1(0)) - (p1(0) - p0(0)) * (p2(1) - p1(1)) < 0)
525  {
526  should_add = true;
527  pd_nodes[1] = pd_boundary_node_ids[i];
528  }
529  }
530  }
531  else
532  mooseError("Element type ",
533  old_elem->type(),
534  " is not supported for PD sideset construction!");
535 
536  if (should_add)
537  {
538  Elem * new_elem = new Tri3;
539  new_elem->set_id(new_elem_id);
540  if (_merge_pd_blks)
541  new_elem->subdomain_id() = min_converted_fe_blk_id + _phantom_blk_offset_number;
542  else
543  new_elem->subdomain_id() = old_elem->subdomain_id() + _phantom_blk_offset_number;
544  new_elem = new_mesh->add_elem(new_elem);
545  new_elem->set_node(0, new_mesh->node_ptr(pd_nodes[0]));
546  new_elem->set_node(1, new_mesh->node_ptr(pd_nodes[1]));
547  new_elem->set_node(2, new_mesh->node_ptr(pd_nodes[2]));
548 
549  ++new_elem_id;
550 
551  new_boundary_info.add_side(new_elem, 0, _pd_blk_offset_number + bidit);
552  if (old_boundary_info.get_sideset_name(bidit) != "")
553  new_boundary_info.sideset_name(_pd_blk_offset_number + bidit) =
554  "pd_side_" + old_boundary_info.get_sideset_name(bidit);
555  }
556  }
557  else if (old_elem->dim() == 3) // 3D
558  {
559  pd_nodes.resize(4); // construct 4-node tetrahedral phanton elems
560  pd_nodes[0] = fe_elem_pd_node_map.at(eidit);
561  p0 = *new_mesh->node_ptr(pd_nodes[0]);
562  // search for three more nodes to construct a phantom 4-node tetrahedral element
563  if (old_elem->n_nodes() == 4 ||
564  old_elem->n_nodes() == 10) // original tetrahedral FE elements: 4-node or 10-node
565  {
566  // construct phantom element based on original tet mesh
567  mooseError("Peridynamics sideset generation does not accept tetrahedral elements!");
568  }
569  else if (old_elem->n_nodes() == 8 || old_elem->n_nodes() == 20 ||
570  old_elem->n_nodes() ==
571  27) // original hexahedral FE elements: 8-node, 20-node or 27-node
572  {
573  std::vector<dof_id_type> boundary_elem_ids;
574  for (unsigned int i = 0; i < old_elem->n_neighbors(); ++i)
575  {
576  Elem * nb = old_elem->neighbor_ptr(i);
577  if (nb != nullptr && fe_bid_eid[bidit].count(nb->id()))
578  boundary_elem_ids.push_back(nb->id());
579  }
580 
581  // find the fourth pd node by the boundary side of the element
582  pd_nodes[3] = fe_elem_pd_node_map.at(
583  old_elem
584  ->neighbor_ptr(old_elem->opposite_side(
585  old_boundary_info.side_with_boundary_id(old_elem, bidit)))
586  ->id());
587  p3 = *new_mesh->node_ptr(pd_nodes[3]);
588 
589  // choose two neighbors of current node (total of three pd nodes) ordered in a way
590  // such that the normal points to the fourth pd node
591  for (unsigned int i = 0; i < boundary_elem_ids.size(); ++i)
592  {
593  Elem * nb_i = old_mesh->elem_ptr(boundary_elem_ids[i]);
594  p1 = *new_mesh->node_ptr(fe_elem_pd_node_map.at(boundary_elem_ids[i]));
595 
596  for (unsigned int j = i + 1; j < boundary_elem_ids.size(); ++j)
597  {
598  Elem * nb_j = old_mesh->elem_ptr(boundary_elem_ids[j]);
599  p2 = *new_mesh->node_ptr(fe_elem_pd_node_map.at(boundary_elem_ids[j]));
600 
601  if (old_elem->which_neighbor_am_i(nb_i) !=
602  old_elem->opposite_side(old_elem->which_neighbor_am_i(nb_j)))
603  {
604  should_add = true;
605  // check whether this new elem overlaps with already created elems by the
606  // saved edge and nodes of previously created phantom elems
607  std::pair<dof_id_type, dof_id_type> nodes_pair_i;
608  nodes_pair_i.first = std::min(eidit, boundary_elem_ids[i]);
609  nodes_pair_i.second = std::max(eidit, boundary_elem_ids[i]);
610  if (elem_edge_nodes.count(nodes_pair_i))
611  {
612  for (const auto & nbid : elem_edge_nodes[nodes_pair_i])
613  if (nbid != old_elem->id() && old_mesh->elem_ptr(nbid)->has_neighbor(nb_j))
614  should_add = false;
615  }
616 
617  std::pair<dof_id_type, dof_id_type> nodes_pair_j;
618  nodes_pair_j.first = std::min(eidit, boundary_elem_ids[j]);
619  nodes_pair_j.second = std::max(eidit, boundary_elem_ids[j]);
620  if (elem_edge_nodes.count(nodes_pair_j))
621  {
622  for (const auto & nbid : elem_edge_nodes[nodes_pair_j])
623  if (nbid != old_elem->id() && old_mesh->elem_ptr(nbid)->has_neighbor(nb_i))
624  should_add = false;
625  }
626 
627  if (should_add)
628  {
629  // check whether the normal of face formed by p0, p1 and p2 points to p3
630  Real val =
631  ((p1(1) - p0(1)) * (p2(2) - p0(2)) - (p1(2) - p0(2)) * (p2(1) - p0(1))) *
632  (p3(0) - p0(0)) +
633  ((p1(2) - p0(2)) * (p2(0) - p0(0)) - (p1(0) - p0(0)) * (p2(2) - p0(2))) *
634  (p3(1) - p0(1)) +
635  ((p1(0) - p0(0)) * (p2(1) - p0(1)) - (p1(1) - p0(1)) * (p2(0) - p0(0))) *
636  (p3(2) - p0(2));
637  if (val > 0) // normal point to p3
638  {
639  pd_nodes[1] = fe_elem_pd_node_map.at(boundary_elem_ids[i]);
640  pd_nodes[2] = fe_elem_pd_node_map.at(boundary_elem_ids[j]);
641  }
642  else
643  {
644  pd_nodes[1] = fe_elem_pd_node_map.at(boundary_elem_ids[j]);
645  pd_nodes[2] = fe_elem_pd_node_map.at(boundary_elem_ids[i]);
646  }
647 
648  // construct the new phantom element
649  Elem * new_elem = new Tet4;
650  new_elem->set_id(new_elem_id);
651 
652  if (_merge_pd_blks)
653  new_elem->subdomain_id() =
654  min_converted_fe_blk_id + _phantom_blk_offset_number;
655  else
656  new_elem->subdomain_id() =
657  old_elem->subdomain_id() + _phantom_blk_offset_number;
658 
659  new_elem = new_mesh->add_elem(new_elem);
660  new_elem->set_node(0, new_mesh->node_ptr(pd_nodes[0]));
661  new_elem->set_node(1, new_mesh->node_ptr(pd_nodes[1]));
662  new_elem->set_node(2, new_mesh->node_ptr(pd_nodes[2]));
663  new_elem->set_node(3, new_mesh->node_ptr(pd_nodes[3]));
664 
665  // save the edges and nodes used in the new phantom elem, which will be used
666  // for creating new phantom elements
667  elem_edge_nodes[nodes_pair_i].insert(boundary_elem_ids[j]);
668  elem_edge_nodes[nodes_pair_j].insert(boundary_elem_ids[i]);
669 
670  ++new_elem_id;
671 
672  new_boundary_info.add_side(new_elem, 0, _pd_blk_offset_number + bidit);
673  if (old_boundary_info.get_sideset_name(bidit) != "")
674  {
675  new_boundary_info.sideset_name(_pd_blk_offset_number + bidit) =
676  "pd_side_" + old_boundary_info.get_sideset_name(bidit);
677  }
678  }
679  }
680  }
681  }
682  }
683  else
684  mooseError("Element type ",
685  old_elem->type(),
686  " is not supported for PD sidesets construction!");
687  }
688  }
689  }
690  }
691  }
692 
693  // next, save non-converted or retained FE elements, if any, to new mesh
694  std::map<dof_id_type, dof_id_type> fe_elems_map; // IDs of the same elem in the old and new meshes
695  for (const auto & eid : fe_elems)
696  {
697  Elem * old_elem = old_mesh->elem_ptr(eid);
698  Elem * new_elem = Elem::build(old_elem->type()).release();
699  new_elem->set_id(new_elem_id);
700  new_elem->subdomain_id() = old_elem->subdomain_id();
701  new_elem = new_mesh->add_elem(new_elem);
702  for (unsigned int j = 0; j < old_elem->n_nodes(); ++j)
703  new_elem->set_node(j, new_mesh->node_ptr(fe_nodes_map.at(old_elem->node_ptr(j)->id())));
704 
705  fe_elems_map.insert(std::make_pair(old_elem->id(), new_elem_id));
706 
707  ++new_elem_id;
708  }
709 
710  // STEP 5: convert old boundary_info to new boundary_info for retained FE mesh
711 
712  // peridynamics ONLY accept nodesets and sidesets
713  // nodeset consisting single node in the converted FE block will no longer be available
714  if (old_boundary_info.n_edge_conds())
715  mooseError("PeridynamicsMesh does not support edgesets!");
716 
717  // check the existence of nodesets, if exist, build sidesets in case this hasn't been done yet
718  if (old_boundary_info.n_nodeset_conds())
719  old_boundary_info.build_side_list_from_node_list();
720 
721  // first, create a tuple to collect all sidesets (including those converted from nodesets) in the
722  // old mesh
723  auto old_fe_sbc_tuples = old_boundary_info.build_side_list();
724  // 0: element ID, 1: side ID, 2: boundary ID
725  // map of set of elem IDs connected to each boundary in the old mesh
726  std::map<boundary_id_type, std::set<dof_id_type>> old_fe_bnd_elem_ids;
727  // map of set of side ID for each elem in the old mesh
728  std::map<dof_id_type, std::map<boundary_id_type, dof_id_type>> old_fe_elem_bnd_side_ids;
729  for (const auto & sbct : old_fe_sbc_tuples)
730  {
731  old_fe_bnd_elem_ids[std::get<2>(sbct)].insert(std::get<0>(sbct));
732  old_fe_elem_bnd_side_ids[std::get<0>(sbct)].insert(
733  std::make_pair(std::get<2>(sbct), std::get<1>(sbct)));
734  }
735 
736  // next, convert element lists in old mesh to PD nodesets in new mesh
737  std::set<boundary_id_type> old_side_bid(old_boundary_info.get_side_boundary_ids());
738 
739  // loop through all old FE _sideset_ boundaries
740  for (const auto & sbid : old_side_bid)
741  for (const auto & beid : old_fe_bnd_elem_ids[sbid])
742  if (elems_to_pd.count(beid)) // for converted FE mesh
743  {
744  // save corresponding boundaries on converted FE mesh to PD nodes
745  new_boundary_info.add_node(new_mesh->node_ptr(fe_elem_pd_node_map.at(beid)),
746  sbid + _pd_blk_offset_number);
747  if (old_boundary_info.get_sideset_name(sbid) != "")
748  new_boundary_info.nodeset_name(sbid + _pd_blk_offset_number) =
749  "pd_nodes_" + old_boundary_info.get_sideset_name(sbid);
750 
751  if (_retain_fe_mesh) // if retained, copy the corresponding boundaries, if any, to new mesh
752  // from old mesh
753  {
754  new_boundary_info.add_side(
755  new_mesh->elem_ptr(fe_elems_map[beid]), old_fe_elem_bnd_side_ids[beid][sbid], sbid);
756  new_boundary_info.sideset_name(sbid) = old_boundary_info.get_sideset_name(sbid);
757  }
758  }
759  else // for non-converted FE mesh, if any, copy the corresponding boundaries to new mesh
760  // from old mesh
761  {
762  new_boundary_info.add_side(
763  new_mesh->elem_ptr(fe_elems_map[beid]), old_fe_elem_bnd_side_ids[beid][sbid], sbid);
764  new_boundary_info.sideset_name(sbid) = old_boundary_info.get_sideset_name(sbid);
765  }
766 
767  // similar for sideset above, save _nodesets_ of non-converted and/or retained FE mesh, if any, to
768  // new mesh
769  auto old_node_bc_tuples = old_boundary_info.build_node_list();
770  // 0: node ID, 1: boundary ID
771  std::map<boundary_id_type, std::set<dof_id_type>> old_bnd_node_ids;
772  for (const auto & nbct : old_node_bc_tuples)
773  old_bnd_node_ids[std::get<1>(nbct)].insert(std::get<0>(nbct));
774 
775  std::set<boundary_id_type> old_node_bid(old_boundary_info.get_node_boundary_ids());
776 
777  for (const auto & nbid : old_node_bid)
778  for (const auto & bnid : old_bnd_node_ids[nbid])
779  if (fe_nodes.count(bnid))
780  {
781  new_boundary_info.add_node(new_mesh->node_ptr(fe_nodes_map.at(bnid)), nbid);
782  new_boundary_info.nodeset_name(nbid) = old_boundary_info.get_sideset_name(nbid);
783  }
784 
785  // create nodesets to include all PD nodes for PD blocks in the new mesh
786  for (unsigned int i = 0; i < n_pd_nodes; ++i)
787  {
788  if (_blks_to_pd.size() > 1 && !_merge_pd_blks)
789  {
790  unsigned int j = 0;
791  for (const auto & blk_id : _blks_to_pd)
792  {
793  ++j;
794  SubdomainID real_blk_id =
795  blk_id + _pd_blk_offset_number; // account for the _pd_blk_offset_number increment after
796  // converting to PD mesh
797  if (pd_mesh.getNodeBlockID(i) == real_blk_id)
798  {
799  new_boundary_info.add_node(new_mesh->node_ptr(i), _pd_nodeset_offset_number - j);
800  new_boundary_info.nodeset_name(_pd_nodeset_offset_number - j) =
801  "pd_nodes_block_" + Moose::stringify(blk_id + _pd_blk_offset_number);
802  }
803  }
804  }
805 
806  new_boundary_info.add_node(new_mesh->node_ptr(i), _pd_nodeset_offset_number);
807  new_boundary_info.nodeset_name(_pd_nodeset_offset_number) = "pd_nodes_all";
808  }
809 
810  old_mesh.reset(); // destroy the old_mesh unique_ptr
811 
812  return dynamic_pointer_cast<MeshBase>(new_mesh);
813 }
unsigned int _pd_nodeset_offset_number
a number used to offset the boundary nodeset ID after being converted into PD nodeset ...
std::set< boundary_id_type > _fe_sidesets_for_pd_construction
std::multimap< SubdomainID, SubdomainID > _pd_non_bonding_blk_pairs
dof_id_type nPDBonds() const
Function to return number of PD Edge elements.
void createPeridynamicsMeshData(MeshBase &fe_mesh, std::set< dof_id_type > converted_elem_id, std::multimap< SubdomainID, SubdomainID > bonding_block_pairs, std::multimap< SubdomainID, SubdomainID > non_bonding_block_pairs)
Function to assign values to member variables (PD mesh data) of this class this function will be call...
std::set< SubdomainID > _blks_to_pd
std::multimap< SubdomainID, SubdomainID > _pd_bonding_blk_pairs
std::vector< dof_id_type > getNeighbors(dof_id_type node_id)
Function to return neighbor nodes indices for node node_id.
Peridynamics mesh class.
bool _merge_pd_interfacial_blks
flag to specify whether a single block should be used for all PD interfacial blocks this is used when...
bool _merge_pd_blks
flag to specify whether to combine converted PD mesh blocks into a single mesh block or not this is u...
std::unique_ptr< T_DEST, T_DELETER > dynamic_pointer_cast(std::unique_ptr< T_SRC, T_DELETER > &src)
bool _retain_fe_mesh
flag to specify whether the FE mesh should be retained or not in addition to newly created PD mesh ...
bool _has_non_bonding_blk_pairs
pairs of converted FE block IDs when only certain blocks need NOT to be connected this is usually use...
bool _has_blks_to_pd
block ID(s) of input FE mesh when only certain block(s) needs to be converted to PD mesh this is used...
bool _has_sidesets_to_pd
list of sideset ID(s) to be constructed based on converted PD mesh if the _construct_pd_sideset is tr...
SubdomainID getNodeBlockID(dof_id_type node_id)
Function to return block ID for node node_id.
dof_id_type nPDNodes() const
Function to return number of PD nodes.
std::unique_ptr< MeshBase > & _input
Reference to the input finite element mesh.
bool _has_blks_as_fe
block ID(s) of input FE mesh when only certain block(s) needs NOT to be converted to PD mesh this is ...
std::string stringify(const T &t)
unsigned int _phantom_blk_offset_number
a number used to offset the block ID for phantom elements
std::set< SubdomainID > _blks_as_fe
bool _has_bonding_blk_pairs
pairs of converted FE block IDs when only certain blocks need to be connected using interfacial bonds...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
unsigned int _pd_blk_offset_number
a number used to offset the block ID after being converted into PD mesh
void mooseError(Args &&... args) const
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
std::unique_ptr< MeshBase > buildMeshBaseObject(unsigned int dim=libMesh::invalid_uint)
static const std::string k
Definition: NS.h:130
bool _construct_pd_sideset
flag to specify whether PD sideset should be constructed or not
void setNodeBlockID(SubdomainID id)
Function to set block ID for all PD nodes.
uint8_t dof_id_type

◆ validParams()

InputParameters MeshGeneratorPD::validParams ( )
static

Definition at line 21 of file MeshGeneratorPD.C.

22 {
24  params.addClassDescription("Mesh generator class to convert FE mesh to PD mesh");
25 
26  params.addRequiredParam<MeshGeneratorName>("input",
27  "The mesh based on which PD mesh will be created");
28  params.addParam<std::vector<SubdomainID>>("blocks_to_pd",
29  "IDs of the FE mesh blocks to be converted to PD mesh");
30  params.addParam<std::vector<SubdomainID>>(
31  "blocks_as_fe",
32  "IDs of the FE mesh blocks to not be converted to PD mesh. This should only be used when the "
33  "number of to-be-converted FE blocks is considerably large.");
34  params.addRequiredParam<bool>(
35  "retain_fe_mesh", "Whether to retain the FE mesh or not after conversion into PD mesh");
36  params.addParam<bool>(
37  "construct_pd_sidesets",
38  false,
39  "Whether to construct PD sidesets based on the sidesets in original FE mesh");
40  params.addParam<std::vector<boundary_id_type>>(
41  "sidesets_to_pd", "IDs of the FE sidesets to be reconstructed based on converted PD mesh");
42  params.addParam<std::vector<std::vector<SubdomainID>>>(
43  "bonding_block_pairs",
44  "List of FE block pairs between which inter-block bonds will be created after being "
45  "converted into PD mesh");
46  params.addParam<std::vector<std::vector<SubdomainID>>>(
47  "non_bonding_block_pairs",
48  "List of FE block pairs between which inter-block bonds will NOT be created after being "
49  "converted into PD mesh");
50  params.addParam<bool>(
51  "merge_pd_blocks",
52  false,
53  "Whether to merge all converted PD mesh blocks into a single block. This is "
54  "used when all PD blocks have the same properties");
55  params.addParam<bool>(
56  "merge_pd_interfacial_blocks",
57  false,
58  "Whether to merge all PD interfacial mesh blocks into a single block. This is used "
59  "when all PD interfacial blocks have the same properties");
60 
61  return params;
62 }
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addRequiredParam(const std::string &name, const std::string &doc_string)
static InputParameters validParams()
void addClassDescription(const std::string &doc_string)

Member Data Documentation

◆ _blks_as_fe

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

Definition at line 53 of file MeshGeneratorPD.h.

Referenced by generate(), and MeshGeneratorPD().

◆ _blks_to_pd

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

Definition at line 48 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 64 of file MeshGeneratorPD.h.

Referenced by generate(), and MeshGeneratorPD().

◆ _fe_sidesets_for_pd_construction

std::set<boundary_id_type> MeshGeneratorPD::_fe_sidesets_for_pd_construction
protected

Definition at line 67 of file MeshGeneratorPD.h.

Referenced by generate(), and MeshGeneratorPD().

◆ _has_blks_as_fe

bool MeshGeneratorPD::_has_blks_as_fe
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 52 of file MeshGeneratorPD.h.

Referenced by generate(), and MeshGeneratorPD().

◆ _has_blks_to_pd

bool MeshGeneratorPD::_has_blks_to_pd
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 47 of file MeshGeneratorPD.h.

Referenced by generate(), and MeshGeneratorPD().

◆ _has_bonding_blk_pairs

bool MeshGeneratorPD::_has_bonding_blk_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 71 of file MeshGeneratorPD.h.

Referenced by generate(), and MeshGeneratorPD().

◆ _has_non_bonding_blk_pairs

bool MeshGeneratorPD::_has_non_bonding_blk_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 76 of file MeshGeneratorPD.h.

Referenced by generate(), and MeshGeneratorPD().

◆ _has_sidesets_to_pd

bool MeshGeneratorPD::_has_sidesets_to_pd
protected

list of sideset ID(s) to be constructed based on converted PD mesh if the _construct_pd_sideset is true

Definition at line 66 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 43 of file MeshGeneratorPD.h.

Referenced by generate().

◆ _merge_pd_blks

bool MeshGeneratorPD::_merge_pd_blks
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 61 of file MeshGeneratorPD.h.

Referenced by generate().

◆ _merge_pd_interfacial_blks

bool MeshGeneratorPD::_merge_pd_interfacial_blks
protected

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

Definition at line 81 of file MeshGeneratorPD.h.

Referenced by generate().

◆ _pd_blk_offset_number

unsigned int MeshGeneratorPD::_pd_blk_offset_number = 1000
protected

a number used to offset the block ID after being converted into PD mesh

Definition at line 34 of file MeshGeneratorPD.h.

Referenced by generate(), and MeshGeneratorPD().

◆ _pd_bonding_blk_pairs

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

Definition at line 72 of file MeshGeneratorPD.h.

Referenced by generate(), and MeshGeneratorPD().

◆ _pd_nodeset_offset_number

unsigned int MeshGeneratorPD::_pd_nodeset_offset_number = 999
protected

a number used to offset the boundary nodeset ID after being converted into PD nodeset

Definition at line 40 of file MeshGeneratorPD.h.

Referenced by generate().

◆ _pd_non_bonding_blk_pairs

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

Definition at line 77 of file MeshGeneratorPD.h.

Referenced by generate(), and MeshGeneratorPD().

◆ _phantom_blk_offset_number

unsigned int MeshGeneratorPD::_phantom_blk_offset_number = 10000
protected

a number used to offset the block ID for phantom elements

Definition at line 37 of file MeshGeneratorPD.h.

Referenced by generate().

◆ _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 57 of file MeshGeneratorPD.h.

Referenced by generate().


The documentation for this class was generated from the following files: