Skip to content

Commit e36d182

Browse files
authored
Merge pull request #31761 from miaoyinb/transitionXYZD
XYZDelaunay Hole Conversion and Stitching Improvements
2 parents b79a48d + 28487c1 commit e36d182

File tree

16 files changed

+353
-219
lines changed

16 files changed

+353
-219
lines changed

framework/doc/content/source/meshgenerators/BoundaryElementConversionGenerator.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ There are four types of linear 3D elements supported by this mesh generator: `HE
2020

2121
The most common application of this mesh generator is applied to external boundaries of the [!param](/Mesh/BoundaryElementConversionGenerator/input) mesh. The mesh generator can also be applied to internal boundaries, in which case both sides of the internal boundary are converted. Users can enable [!param](/Mesh/BoundaryElementConversionGenerator/external_boundaries_checking) to enforce that the specified boundaries are external to avert unintended behavior.
2222

23+
!alert note
24+
In distributed mesh mode, the mesh is temporarily serialized to enable some essential methods.
25+
2326
### HEX8
2427

2528
All the six sides of a `HEX8` elements are `QUAD4`. Any sides involved in the given boundaries will need to be divided into two `TRI3` sides that belong to two different new elements. To keep the other `QUAD4` sides unchanged, a simple strategy is adopted. First, the `HEX8` elements are divided into six `PYRAMID5` elements, each of which is defined by one of the `QUAD4` sides and the centroid of the `HEX8` element. For those `QUAD4` sides involved in the given boundaries, the `PYRAMID5` elements are further divided into two `TET4` elements (see the top row of [boundary_transition] as an example).

framework/doc/content/source/meshgenerators/XYZDelaunayGenerator.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ volume elements with non-Tri3 surface sides, it cannot be stitched
4343
with the output mesh without modifications.
4444
[!param](/Mesh/XYZDelaunayGenerator/convert_holes_for_stitching) needs to
4545
be set as `true` to allow the stitching of such hole meshes after modifications.
46+
These hole meshes can either be converted into pure Tet4 meshes, or they can be
47+
converted using boundary element conversion
48+
(see [`BoundaryElementConversionGenerator`](/BoundaryElementConversionGenerator.md))
49+
to only convert elements near the external boundaries. This can be controlled
50+
by the [!param](/Mesh/XYZDelaunayGenerator/conversion_method) parameter.
4651

4752
!alert note
4853
In distributed mesh mode, the [!param](/Mesh/XYZDelaunayGenerator/boundary) input mesh is temporarily serialized when it is set to be stitched with at least one of the [!param](/Mesh/XYZDelaunayGenerator/holes) input meshes. Additionally, the [!param](/Mesh/XYZDelaunayGenerator/holes) input meshes are always temporarily serialized to ensure compatibility with required processing methods.

framework/include/meshgenerators/CombinerGenerator.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,6 @@ class CombinerGenerator : public MeshGenerator
2929
void fillPositions();
3030

3131
protected:
32-
/**
33-
* Helper funciton for copying one mesh into another
34-
*/
35-
void copyIntoMesh(UnstructuredMesh & destination, const UnstructuredMesh & source);
36-
3732
// Holds pointers to the mesh smart pointers (to be populated later).
3833
const std::vector<std::unique_ptr<MeshBase> *> _meshes;
3934

framework/include/meshgenerators/XYZDelaunayGenerator.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,15 @@ class XYZDelaunayGenerator : public MeshGenerator
4444
/// Whether to stitch to the mesh defining each hole
4545
const std::vector<bool> _stitch_holes;
4646

47-
/// Whether to convert 3D hole meshes with non-TRI3 surface elements into all-TET4 meshes
47+
/// Whether to convert 3D hole meshes with non-TRI3 surface elements into a compatible form
4848
const bool _convert_holes_for_stitching;
4949

50+
/// Method to convert 3D hole meshes into compatible meshes
51+
const MooseEnum _conversion_method;
52+
53+
/// Whether to stitch all holes in one combined stitching step
54+
const bool _combined_stitching;
55+
5056
/// Type of algorithm used to find matching nodes (binary or exhaustive)
5157
const MooseEnum _algorithm;
5258

framework/include/utils/MooseMeshElementConversionUtils.h

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ struct BCTupleKeyComp
3535
* @param elem_id The id of the element to be split
3636
* @param converted_elems_ids a vector to record the ids of the newly created TET4 elements
3737
*/
38-
void hexElemSplitter(ReplicatedMesh & mesh,
38+
void hexElemSplitter(MeshBase & mesh,
3939
const std::vector<libMesh::BoundaryInfo::BCTuple> & bdry_side_list,
4040
const dof_id_type elem_id,
4141
std::vector<dof_id_type> & converted_elems_ids);
@@ -47,7 +47,7 @@ void hexElemSplitter(ReplicatedMesh & mesh,
4747
* @param elem_id The id of the element to be split
4848
* @param converted_elems_ids a vector to record the ids of the newly created TET4 elements
4949
*/
50-
void pyramidElemSplitter(ReplicatedMesh & mesh,
50+
void pyramidElemSplitter(MeshBase & mesh,
5151
const std::vector<libMesh::BoundaryInfo::BCTuple> & bdry_side_list,
5252
const dof_id_type elem_id,
5353
std::vector<dof_id_type> & converted_elems_ids);
@@ -59,7 +59,7 @@ void pyramidElemSplitter(ReplicatedMesh & mesh,
5959
* @param elem_id The id of the element to be split
6060
* @param converted_elems_ids a vector to record the ids of the newly created TET4 elements
6161
*/
62-
void prismElemSplitter(ReplicatedMesh & mesh,
62+
void prismElemSplitter(MeshBase & mesh,
6363
const std::vector<libMesh::BoundaryInfo::BCTuple> & bdry_side_list,
6464
const dof_id_type elem_id,
6565
std::vector<dof_id_type> & converted_elems_ids);
@@ -207,7 +207,7 @@ pyramidNodesToTetNodesDeterminer(std::vector<const Node *> & pyramid_nodes,
207207
* @param delete_block_to_remove A bool indicating whether the block to be removed will be
208208
* deleted in this method
209209
*/
210-
void convert3DMeshToAllTet4(ReplicatedMesh & mesh,
210+
void convert3DMeshToAllTet4(MeshBase & mesh,
211211
const std::vector<std::pair<dof_id_type, bool>> & elems_to_process,
212212
std::vector<dof_id_type> & converted_elems_ids_to_track,
213213
const subdomain_id_type block_id_to_remove,
@@ -217,7 +217,7 @@ void convert3DMeshToAllTet4(ReplicatedMesh & mesh,
217217
* Convert all the elements in a 3D mesh consisting of only linear elements into TET4 elements.
218218
* @param mesh The mesh to be converted
219219
*/
220-
void convert3DMeshToAllTet4(ReplicatedMesh & mesh);
220+
void convert3DMeshToAllTet4(MeshBase & mesh);
221221

222222
/**
223223
* Collect the boundary information of the given element in a mesh.
@@ -241,7 +241,7 @@ elementBoundaryInfoCollector(const std::vector<libMesh::BoundaryInfo::BCTuple> &
241241
* @param elem_side_info The boundary IDs associated with the sides of the element
242242
* @param subdomain_id_shift_base the reference id used to shift the subdomain ID for new elements
243243
*/
244-
void convertElem(ReplicatedMesh & mesh,
244+
void convertElem(MeshBase & mesh,
245245
const dof_id_type & elem_id,
246246
const std::vector<unsigned int> & side_indices,
247247
const std::vector<std::vector<boundary_id_type>> & elem_side_info,
@@ -255,7 +255,7 @@ void convertElem(ReplicatedMesh & mesh,
255255
* @param elem_side_info The boundary IDs associated with the sides of the HEX8 element
256256
* @param subdomain_id_shift_base the reference id used to shift the subdomain ID for new elements
257257
*/
258-
void convertHex8Elem(ReplicatedMesh & mesh,
258+
void convertHex8Elem(MeshBase & mesh,
259259
const dof_id_type & elem_id,
260260
const std::vector<unsigned int> & side_indices,
261261
const std::vector<std::vector<boundary_id_type>> & elem_side_info,
@@ -270,7 +270,7 @@ void convertHex8Elem(ReplicatedMesh & mesh,
270270
* @param side_info The boundary IDs associated with the side of the HEX8 element
271271
* @param subdomain_id_shift_base the reference id used to shift the subdomain ID for new elements
272272
*/
273-
void createUnitPyramid5FromHex8(ReplicatedMesh & mesh,
273+
void createUnitPyramid5FromHex8(MeshBase & mesh,
274274
const dof_id_type & elem_id,
275275
const unsigned int & side_index,
276276
const Node * new_node,
@@ -286,7 +286,7 @@ void createUnitPyramid5FromHex8(ReplicatedMesh & mesh,
286286
* @param side_info The boundary IDs associated with the side of the HEX8 element
287287
* @param subdomain_id_shift_base the reference id used to shift the subdomain ID for new elements
288288
*/
289-
void createUnitTet4FromHex8(ReplicatedMesh & mesh,
289+
void createUnitTet4FromHex8(MeshBase & mesh,
290290
const dof_id_type & elem_id,
291291
const unsigned int & side_index,
292292
const Node * new_node,
@@ -301,7 +301,7 @@ void createUnitTet4FromHex8(ReplicatedMesh & mesh,
301301
* @param elem_side_info The boundary IDs associated with the sides of the PRISM6 element
302302
* @param subdomain_id_shift_base the reference id used to shift the subdomain ID for new elements
303303
*/
304-
void convertPrism6Elem(ReplicatedMesh & mesh,
304+
void convertPrism6Elem(MeshBase & mesh,
305305
const dof_id_type & elem_id,
306306
const std::vector<unsigned int> & side_indices,
307307
const std::vector<std::vector<boundary_id_type>> & elem_side_info,
@@ -315,7 +315,7 @@ void convertPrism6Elem(ReplicatedMesh & mesh,
315315
* @param side_info The boundary IDs associated with the side of the PRISM6 element
316316
* @param subdomain_id_shift_base the reference id used to shift the subdomain ID for new elements
317317
*/
318-
void createUnitTet4FromPrism6(ReplicatedMesh & mesh,
318+
void createUnitTet4FromPrism6(MeshBase & mesh,
319319
const dof_id_type & elem_id,
320320
const unsigned int & side_index,
321321
const Node * new_node,
@@ -332,7 +332,7 @@ void createUnitTet4FromPrism6(ReplicatedMesh & mesh,
332332
* @param side_info The boundary IDs associated with the side of the PRISM6 element
333333
* @param subdomain_id_shift_base the reference id used to shift the subdomain ID for new elements
334334
*/
335-
void createUnitPyramid5FromPrism6(ReplicatedMesh & mesh,
335+
void createUnitPyramid5FromPrism6(MeshBase & mesh,
336336
const dof_id_type & elem_id,
337337
const unsigned int & side_index,
338338
const Node * new_node,
@@ -346,7 +346,7 @@ void createUnitPyramid5FromPrism6(ReplicatedMesh & mesh,
346346
* @param elem_side_info The boundary IDs associated with the sides of the PYRAMID
347347
* @param subdomain_id_shift_base the reference id used to shift the subdomain ID for new elements
348348
*/
349-
void convertPyramid5Elem(ReplicatedMesh & mesh,
349+
void convertPyramid5Elem(MeshBase & mesh,
350350
const dof_id_type & elem_id,
351351
const std::vector<std::vector<boundary_id_type>> & elem_side_info,
352352
const SubdomainID & subdomain_id_shift_base);
@@ -357,7 +357,7 @@ void convertPyramid5Elem(ReplicatedMesh & mesh,
357357
* @param elem_id The ID of the original element
358358
* @param new_elem_ptr The pointer to the new element that will retain the extra integer
359359
*/
360-
void retainEEID(ReplicatedMesh & mesh, const dof_id_type & elem_id, Elem * new_elem_ptr);
360+
void retainEEID(MeshBase & mesh, const dof_id_type & elem_id, Elem * new_elem_ptr);
361361

362362
/**
363363
* Generate a transition layer of elements with TRI3 surfaces on the given boundaries.
@@ -369,10 +369,11 @@ void retainEEID(ReplicatedMesh & mesh, const dof_id_type & elem_id, Elem * new_e
369369
* @param external_boundaries_checking Whether to check if the provided boundaries are external
370370
* boundaries
371371
*/
372-
void transitionLayerGenerator(ReplicatedMesh & mesh,
372+
void transitionLayerGenerator(MeshBase & mesh,
373373
const std::vector<BoundaryName> & boundary_names,
374374
const unsigned int conversion_element_layer_number,
375375
const bool external_boundaries_checking);
376+
376377
/**
377378
* Assign a subdomain name suffix to the converted elements created during transition layer
378379
* generation.
@@ -385,7 +386,7 @@ void transitionLayerGenerator(ReplicatedMesh & mesh,
385386
* elements
386387
*/
387388
void assignConvertedElementsSubdomainNameSuffix(
388-
ReplicatedMesh & mesh,
389+
MeshBase & mesh,
389390
const std::set<subdomain_id_type> & original_subdomain_ids,
390391
const subdomain_id_type sid_shift_base,
391392
const SubdomainName & tet_suffix,

framework/include/utils/MooseMeshUtils.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "MooseUtils.h"
1616
#include "MooseTypes.h"
1717
#include "FaceInfo.h"
18+
#include "MeshGenerator.h"
1819

1920
namespace MooseMeshUtils
2021
{
@@ -451,4 +452,22 @@ void createSubdomainFromSidesets(std::unique_ptr<MeshBase> & mesh,
451452
void convertBlockToMesh(std::unique_ptr<MeshBase> & source_mesh,
452453
std::unique_ptr<MeshBase> & target_mesh,
453454
const std::vector<SubdomainName> & target_blocks);
455+
456+
/**
457+
* Helper function for copying one mesh into another
458+
* @param mg The mesh generator calling this function
459+
* @param destination The mesh to copy into
460+
* @param source The mesh to copy from
461+
* @param avoid_merging_subdomains If true, subdomain IDs in the source mesh will
462+
* be offset to avoid merging with subdomain IDs in the destination mesh
463+
* @param avoid_merging_boundaries If true, boundary IDs in the source mesh will
464+
* be offset to avoid merging with boundary IDs in the destination mesh
465+
* @param communicator The communicator for parallel operations
466+
*/
467+
void copyIntoMesh(MeshGenerator & mg,
468+
UnstructuredMesh & destination,
469+
const UnstructuredMesh & source,
470+
const bool avoid_merging_subdomains,
471+
const bool avoid_merging_boundaries,
472+
const Parallel::Communicator & communicator);
454473
}

framework/src/meshgenerators/BoundaryElementConversionGenerator.C

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include "CastUniquePointer.h"
1313
#include "MooseMeshUtils.h"
1414

15+
#include "libmesh/mesh_serializer.h"
16+
1517
registerMooseObject("MooseApp", BoundaryElementConversionGenerator);
1618

1719
InputParameters
@@ -62,11 +64,9 @@ BoundaryElementConversionGenerator::BoundaryElementConversionGenerator(
6264
std::unique_ptr<MeshBase>
6365
BoundaryElementConversionGenerator::generate()
6466
{
65-
auto replicated_mesh_ptr = dynamic_cast<ReplicatedMesh *>(_input.get());
66-
if (!replicated_mesh_ptr)
67-
paramError("input", "Input is not a replicated mesh, which is required");
67+
UnstructuredMesh & mesh = dynamic_cast<UnstructuredMesh &>(*_input);
6868

69-
ReplicatedMesh & mesh = *replicated_mesh_ptr;
69+
libMesh::MeshSerializer serial_mesh(mesh);
7070

7171
// collect the subdomain ids of the original mesh
7272
std::set<subdomain_id_type> original_subdomain_ids;
@@ -75,7 +75,6 @@ BoundaryElementConversionGenerator::generate()
7575
{
7676
original_subdomain_ids.emplace((*elem_it)->subdomain_id());
7777
}
78-
7978
try
8079
{
8180
MooseMeshElementConversionUtils::transitionLayerGenerator(
@@ -93,7 +92,6 @@ BoundaryElementConversionGenerator::generate()
9392
else
9493
paramError("input", e.what());
9594
}
96-
9795
try
9896
{
9997
MooseMeshElementConversionUtils::assignConvertedElementsSubdomainNameSuffix(
@@ -111,5 +109,11 @@ BoundaryElementConversionGenerator::generate()
111109
paramError("converted_pyramid_element_subdomain_name_suffix", e.what());
112110
}
113111

112+
// MeshSerializer's destructor calls delete_remote_elements()
113+
if (!mesh.is_replicated())
114+
mesh.prepare_for_use();
115+
else
116+
mesh.set_isnt_prepared();
117+
114118
return std::move(_input);
115119
}

0 commit comments

Comments
 (0)