https://mooseframework.inl.gov
Loading...
Searching...
No Matches
Public Types | Public Member Functions | Static Public Member Functions | Public Attributes | Static Public Attributes | Protected Member Functions | Static Protected Member Functions | Protected Attributes | Private Member Functions | Static Private Member Functions | Private 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.
 
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 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
 
unsigned int _phantom_blk_offset_number = 10000
 a number used to offset the block ID for phantom elements
 
unsigned int _pd_nodeset_offset_number = 999
 a number used to offset the boundary nodeset ID after being converted into PD nodeset
 
std::unique_ptr< MeshBase > & _input
 Reference to the input finite element mesh.
 
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
 
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
 
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
 
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
 
bool _construct_pd_sideset
 flag to specify whether PD sideset should be constructed or not
 
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
 
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
 
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
 
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
 
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
 

Private Member Functions

virtual std::string meshPropertyPrefix (const std::string &) const override final
 
void checkGetMesh (const MeshGeneratorName &mesh_generator_name, const std::string &param_name) const
 
const MeshGeneratorName * getMeshGeneratorNameFromParam (const std::string &param_name, const bool allow_invalid) const
 
const std::vector< MeshGeneratorName > & getMeshGeneratorNamesFromParam (const std::string &param_name) const
 
RestartableDataValuesetMeshPropertyHelper (const std::string &data_name)
 
const RestartableDataValuegetMeshPropertyInternal (const std::string &data_name, const std::string &prefix) const
 
void mooseErrorInternal (Args &&... args) const
 

Static Private Member Functions

static const hit::Node * getHitNode (const InputParameters &params)
 
static std::string messagePrefix (const InputParameters &params, const bool hit_prefix)
 

Private Attributes

std::set< MeshGeneratorName > _requested_mesh_generators
 
std::set< MeshGeneratorName > _requested_mesh_generators_for_sub
 
std::vector< std::pair< std::string, std::unique_ptr< MeshBase > * > > _requested_meshes
 
std::vector< std::pair< std::string, std::unique_ptr< CSG::CSGBase > * > > _requested_csg_bases
 
std::unique_ptr< MeshBase > _null_mesh
 
std::unique_ptr< CSG::CSGBase_null_csg_base
 
std::set< const MeshGenerator *, Comparator > _parent_mesh_generators
 
std::set< const MeshGenerator *, Comparator > _child_mesh_generators
 
std::set< const MeshGenerator *, Comparator > _sub_mesh_generators
 
std::set< std::string > _null_mesh_names
 
const std::string & _save_with_name
 
const bool _data_only
 
const ParallelParamObject_parent
 
const MooseBase_si_moose_base
 
const FEProblemBase_si_problem
 
MooseApp_meta_data_app
 
const MooseObject *const _meta_data_object
 

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
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
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)
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::multimap< SubdomainID, SubdomainID > _pd_bonding_blk_pairs
bool _has_bonding_blk_pairs
pairs of converted FE block IDs when only certain blocks need to be connected using interfacial bonds...
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 ...
bool _retain_fe_mesh
flag to specify whether the FE mesh should be retained or not in addition to newly created PD mesh
std::set< boundary_id_type > _fe_sidesets_for_pd_construction
bool _construct_pd_sideset
flag to specify whether PD sideset should be constructed or not
bool _merge_pd_interfacial_blks
flag to specify whether a single block should be used for all PD interfacial blocks this is used when...
std::multimap< SubdomainID, SubdomainID > _pd_non_bonding_blk_pairs
std::unique_ptr< MeshBase > & _input
Reference to the input finite element mesh.
unsigned int _pd_blk_offset_number
a number used to offset the block ID after being converted into PD mesh
bool _merge_pd_blks
flag to specify whether to combine converted PD mesh blocks into a single mesh block or not this is u...
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...
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...
std::set< SubdomainID > _blks_as_fe
std::set< SubdomainID > _blks_to_pd
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...
std::unique_ptr< MeshBase > & getMesh(const std::string &param_name, const bool allow_invalid=false)
const InputParameters & parameters() const
void mooseError(Args &&... args) const
bool isParamValid(const std::string &name) const

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 count
std::set< std::string > sideset
for(PetscInt i=0;i< nvars;++i)
unsigned int _phantom_blk_offset_number
a number used to offset the block ID for phantom elements
unsigned int _pd_nodeset_offset_number
a number used to offset the boundary nodeset ID after being converted into PD nodeset
std::unique_ptr< MeshBase > buildMeshBaseObject(unsigned int dim=libMesh::invalid_uint)
Peridynamics mesh class.
dof_id_type nPDNodes() const
Function to return number of PD nodes.
void setNodeBlockID(SubdomainID id)
Function to set block ID for all PD nodes.
dof_id_type nPDBonds() const
Function to return number of PD Edge elements.
SubdomainID getNodeBlockID(dof_id_type node_id)
Function to return block ID for node node_id.
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::vector< dof_id_type > getNeighbors(dof_id_type node_id)
Function to return neighbor nodes indices for node node_id.
std::string stringify(const T &t)
const Elem & get(const ElemType type_in)
if(subdm)
uint8_t dof_id_type
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

◆ 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 addRequiredParam(const std::string &name, const std::string &doc_string)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
static InputParameters validParams()

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: