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< CSG::CSGBasegenerateInternalCSG ()
 
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 hasGenerateCSG () const
 
bool isDataOnly () const
 
virtual bool enabled () const
 
std::shared_ptr< MooseObjectgetSharedPtr ()
 
std::shared_ptr< const MooseObjectgetSharedPtr () const
 
bool isKokkosObject () const
 
MooseAppgetMooseApp () const
 
const std::string & type () const
 
const std::string & name () const
 
std::string typeAndName () const
 
MooseObjectParameterName uniqueParameterName (const std::string &parameter_name) const
 
MooseObjectName uniqueName () const
 
const InputParametersparameters () const
 
const hit::Node * getHitNode () const
 
bool hasBase () const
 
const std::string & getBase () const
 
const TgetParam (const std::string &name) const
 
std::vector< std::pair< T1, T2 > > getParam (const std::string &param1, const std::string &param2) const
 
const TqueryParam (const std::string &name) const
 
const TgetRenamedParam (const std::string &old_name, const std::string &new_name) const
 
T getCheckedPointerParam (const std::string &name, const std::string &error_string="") const
 
bool haveParameter (const std::string &name) const
 
bool isParamValid (const std::string &name) const
 
bool isParamSetByUser (const std::string &name) const
 
void connectControllableParams (const std::string &parameter, const std::string &object_type, const std::string &object_name, const std::string &object_parameter) const
 
void paramError (const std::string &param, Args... args) const
 
void paramWarning (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
 
std::string messagePrefix (const bool hit_prefix=true) const
 
std::string errorPrefix (const std::string &) const
 
void mooseError (Args &&... args) const
 
void mooseDocumentedError (const std::string &repo_name, const unsigned int issue_num, Args &&... args) const
 
void mooseErrorNonPrefixed (Args &&... args) const
 
void mooseWarning (Args &&... args) const
 
void mooseWarning (Args &&... args) const
 
void mooseWarningNonPrefixed (Args &&... args) const
 
void mooseWarningNonPrefixed (Args &&... args) const
 
void mooseDeprecated (Args &&... args) const
 
void mooseDeprecated (Args &&... args) const
 
void mooseDeprecatedNoTrace (Args &&... args) const
 
void mooseInfo (Args &&... args) const
 
void callMooseError (std::string msg, const bool with_prefix, const hit::Node *node=nullptr, const bool show_trace=true) 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 bool hasGenerateCSG (const InputParameters &params)
 
static void callMooseError (MooseApp *const app, const InputParameters &params, std::string msg, const bool with_prefix, const hit::Node *node, const bool show_trace=true)
 
static void setHasGenerateData (InputParameters &params)
 
static void setHasGenerateCSG (InputParameters &params)
 

Public Attributes

 usingCombinedWarningSolutionWarnings
 
const ConsoleStream _console
 

Static Public Attributes

static const std::string data_only_param
 
static const std::string type_param
 
static const std::string name_param
 
static const std::string unique_name_param
 
static const std::string app_param
 
static const std::string moose_base_param
 
static const std::string kokkos_object_param
 
static constexpr auto SYSTEM
 
static constexpr auto NAME
 

Protected Member Functions

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