Skip to content

Commit 8a5faa9

Browse files
authored
Merge pull request #29068 from DanielYankura/water_tight_nodeset_check
Added diagnostic check for watertight nodesets
2 parents a4c8527 + 58d384b commit 8a5faa9

File tree

6 files changed

+137
-4
lines changed

6 files changed

+137
-4
lines changed

framework/include/meshgenerators/MeshDiagnosticsGenerator.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ class MeshDiagnosticsGenerator : public MeshGenerator
3333
void checkSidesetsOrientation(const std::unique_ptr<MeshBase> & mesh) const;
3434
//// Routine to check is mesh is fully covered in sidesets
3535
void checkWaterTightSidesets(const std::unique_ptr<MeshBase> & mesh) const;
36+
//// Routine to check is mesh is fully covered in nodesets
37+
void checkWatertightNodesets(const std::unique_ptr<MeshBase> & mesh) const;
3638
/// Routine to check the element volumes
3739
void checkElementVolumes(const std::unique_ptr<MeshBase> & mesh) const;
3840
/// Routine to check the element types in each subdomain
@@ -62,6 +64,8 @@ class MeshDiagnosticsGenerator : public MeshGenerator
6264
const MooseEnum _check_sidesets_orientation;
6365
//// whether to check that each external side is assigned to a sideset
6466
const MooseEnum _check_watertight_sidesets;
67+
//// whether to check that each external node is assigned to a nodeset
68+
const MooseEnum _check_watertight_nodesets;
6569
/// whether to check element volumes
6670
const MooseEnum _check_element_volumes;
6771
/// minimum size for element volume to be counted as a tiny element

framework/src/meshgenerators/MeshDiagnosticsGenerator.C

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ MeshDiagnosticsGenerator::validParams()
4545
"check_for_watertight_sidesets",
4646
chk_option,
4747
"whether to check for external sides that are not assigned to any sidesets");
48+
params.addParam<MooseEnum>(
49+
"check_for_watertight_nodesets",
50+
chk_option,
51+
"whether to check for external nodes that are not assigned to any nodeset");
4852
params.addParam<MooseEnum>(
4953
"examine_element_volumes", chk_option, "whether to examine volume of the elements");
5054
params.addParam<Real>("minimum_element_volumes", 1e-16, "minimum size for element volume");
@@ -80,6 +84,7 @@ MeshDiagnosticsGenerator::MeshDiagnosticsGenerator(const InputParameters & param
8084
_input(getMesh("input")),
8185
_check_sidesets_orientation(getParam<MooseEnum>("examine_sidesets_orientation")),
8286
_check_watertight_sidesets(getParam<MooseEnum>("check_for_watertight_sidesets")),
87+
_check_watertight_nodesets(getParam<MooseEnum>("check_for_watertight_nodesets")),
8388
_check_element_volumes(getParam<MooseEnum>("examine_element_volumes")),
8489
_min_volume(getParam<Real>("minimum_element_volumes")),
8590
_max_volume(getParam<Real>("maximum_element_volumes")),
@@ -103,10 +108,10 @@ MeshDiagnosticsGenerator::MeshDiagnosticsGenerator(const InputParameters & param
103108
paramError("examine_non_conformality",
104109
"You must set this parameter to true to trigger mesh conformality check");
105110
if (_check_sidesets_orientation == "NO_CHECK" && _check_watertight_sidesets == "NO_CHECK" &&
106-
_check_element_volumes == "NO_CHECK" && _check_element_types == "NO_CHECK" &&
107-
_check_element_overlap == "NO_CHECK" && _check_non_planar_sides == "NO_CHECK" &&
108-
_check_non_conformal_mesh == "NO_CHECK" && _check_adaptivity_non_conformality == "NO_CHECK" &&
109-
_check_local_jacobian == "NO_CHECK")
111+
_check_watertight_nodesets == "NO_CHECK" && _check_element_volumes == "NO_CHECK" &&
112+
_check_element_types == "NO_CHECK" && _check_element_overlap == "NO_CHECK" &&
113+
_check_non_planar_sides == "NO_CHECK" && _check_non_conformal_mesh == "NO_CHECK" &&
114+
_check_adaptivity_non_conformality == "NO_CHECK" && _check_local_jacobian == "NO_CHECK")
110115
mooseError("You need to turn on at least one diagnostic. Did you misspell a parameter?");
111116
}
112117

@@ -129,6 +134,9 @@ MeshDiagnosticsGenerator::generate()
129134
if (_check_watertight_sidesets != "NO_CHECK")
130135
checkWaterTightSidesets(mesh);
131136

137+
if (_check_watertight_nodesets != "NO_CHECK")
138+
checkWatertightNodesets(mesh);
139+
132140
if (_check_element_volumes != "NO_CHECK")
133141
checkElementVolumes(mesh);
134142

@@ -335,6 +343,64 @@ MeshDiagnosticsGenerator::checkWaterTightSidesets(const std::unique_ptr<MeshBase
335343
diagnosticsLog(message, _check_watertight_sidesets, num_faces_without_sideset);
336344
}
337345

346+
void
347+
MeshDiagnosticsGenerator::checkWatertightNodesets(const std::unique_ptr<MeshBase> & mesh) const
348+
{
349+
/*
350+
Diagnostic Overview:
351+
1) Mesh precheck
352+
2) Loop through all elements
353+
3) Loop through all sides of that element
354+
4) If side is external loop through its nodes
355+
5) If node is not associated with any nodeset add to list
356+
6) Print out node id
357+
*/
358+
if (mesh->mesh_dimension() < 2)
359+
mooseError("The nodeset check only works for 2D and 3D meshes");
360+
auto & boundary_info = mesh->get_boundary_info();
361+
unsigned int num_nodes_without_nodeset = 0;
362+
std::set<dof_id_type> checked_nodes_id;
363+
364+
for (const auto elem : mesh->active_element_ptr_range())
365+
{
366+
for (const auto i : elem->side_index_range())
367+
{
368+
// Check if side is external
369+
if (elem->neighbor_ptr(i) == nullptr)
370+
{
371+
// Side is external, now check nodes
372+
auto side = elem->side_ptr(i);
373+
const auto & node_list = side->get_nodes();
374+
for (unsigned int j = 0; j < side->n_nodes(); j++)
375+
{
376+
const auto node = node_list[j];
377+
if (checked_nodes_id.count(node->id()))
378+
continue;
379+
// if node has no nodeset, add it to list of bad nodes
380+
if (boundary_info.n_boundary_ids(node) == 0)
381+
{
382+
// This node does not have a nodeset!!!
383+
num_nodes_without_nodeset++;
384+
checked_nodes_id.insert(node->id());
385+
std::string message;
386+
if (num_nodes_without_nodeset < _num_outputs)
387+
{
388+
message =
389+
"Node " + std::to_string(node->id()) +
390+
" is on an external boundary of the mesh, but has not been assigned to a nodeset";
391+
_console << message << std::endl;
392+
}
393+
}
394+
}
395+
}
396+
}
397+
}
398+
std::string message;
399+
message = "Number of external nodes that have not been assigned to a nodeset: " +
400+
std::to_string(num_nodes_without_nodeset);
401+
diagnosticsLog(message, _check_watertight_nodesets, num_nodes_without_nodeset);
402+
}
403+
338404
void
339405
MeshDiagnosticsGenerator::checkElementVolumes(const std::unique_ptr<MeshBase> & mesh) const
340406
{
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[Mesh]
2+
[gmg]
3+
type = GeneratedMeshGenerator
4+
dim = 2
5+
nx = 2
6+
ny = 2
7+
[]
8+
[deletion]
9+
type = BoundaryDeletionGenerator
10+
input = gmg
11+
boundary_names = 'right'
12+
[]
13+
[diag]
14+
type = MeshDiagnosticsGenerator
15+
input = deletion
16+
check_for_watertight_nodesets = INFO
17+
[]
18+
[]
19+
20+
[Outputs]
21+
exodus = true
22+
[]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[Mesh]
2+
[gmg]
3+
type = GeneratedMeshGenerator
4+
dim = 3
5+
nx = 2
6+
ny = 2
7+
nz = 2
8+
[]
9+
[deletion]
10+
type = BoundaryDeletionGenerator
11+
input = gmg
12+
boundary_names = 'right'
13+
[]
14+
[diag]
15+
type = MeshDiagnosticsGenerator
16+
input = deletion
17+
check_for_watertight_nodesets = INFO
18+
[]
19+
[]
20+
21+
[Outputs]
22+
exodus = true
23+
[]

test/tests/meshgenerators/mesh_diagnostics_generator/all_at_once.i

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
examine_nonplanar_sides = INFO
1616
examine_sidesets_orientation = WARNING
1717
check_for_watertight_sidesets = WARNING
18+
check_for_watertight_nodesets = WARNING
1819
search_for_adaptivity_nonconformality = WARNING
1920
check_local_jacobian = WARNING
2021
[]

test/tests/meshgenerators/mesh_diagnostics_generator/tests

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,22 @@
4545
expect_out = 'Number of external element faces that have not been assigned to a sideset: 4'
4646
detail = '3D meshed cube missing a sideset on one side'
4747
[]
48+
[2D_watertight_nodesets]
49+
type = 'RunApp'
50+
input = '2D_missing_nodeset.i'
51+
cli_args = '--mesh-only'
52+
mesh_mode = 'replicated'
53+
expect_out = 'Number of external nodes that have not been assigned to a nodeset: 1'
54+
detail = '2D meshed square with one external node that does not belong to a nodeset'
55+
[]
56+
[3D_watertight_nodesets]
57+
type = 'RunApp'
58+
input = '3D_missing_nodeset.i'
59+
cli_args = '--mesh-only'
60+
mesh_mode = 'replicated'
61+
expect_out = 'Number of external nodes that have not been assigned to a nodeset: 1'
62+
detail = '3D meshed cube with one external node that does not belong to a nodeset'
63+
[]
4864
[overlap]
4965
type = 'RunApp'
5066
input = 'node_based_test.i'
@@ -253,6 +269,7 @@
253269
Mesh/diag/examine_nonplanar_sides=NO_CHECK
254270
Mesh/diag/examine_sidesets_orientation=NO_CHECK
255271
Mesh/diag/check_for_watertight_sidesets=NO_CHECK
272+
Mesh/diag/check_for_watertight_nodesets=NO_CHECK
256273
Mesh/diag/search_for_adaptivity_nonconformality=NO_CHECK
257274
Mesh/diag/check_local_jacobian=NO_CHECK --mesh-only"
258275
detail = 'a diagnostics object is created but no diagnostics are requested.'

0 commit comments

Comments
 (0)