Skip to content

Commit

Permalink
Merge pull request #29068 from DanielYankura/water_tight_nodeset_check
Browse files Browse the repository at this point in the history
Added diagnostic check for watertight nodesets
  • Loading branch information
GiudGiud authored Nov 20, 2024
2 parents a4c8527 + 58d384b commit 8a5faa9
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 4 deletions.
4 changes: 4 additions & 0 deletions framework/include/meshgenerators/MeshDiagnosticsGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class MeshDiagnosticsGenerator : public MeshGenerator
void checkSidesetsOrientation(const std::unique_ptr<MeshBase> & mesh) const;
//// Routine to check is mesh is fully covered in sidesets
void checkWaterTightSidesets(const std::unique_ptr<MeshBase> & mesh) const;
//// Routine to check is mesh is fully covered in nodesets
void checkWatertightNodesets(const std::unique_ptr<MeshBase> & mesh) const;
/// Routine to check the element volumes
void checkElementVolumes(const std::unique_ptr<MeshBase> & mesh) const;
/// Routine to check the element types in each subdomain
Expand Down Expand Up @@ -62,6 +64,8 @@ class MeshDiagnosticsGenerator : public MeshGenerator
const MooseEnum _check_sidesets_orientation;
//// whether to check that each external side is assigned to a sideset
const MooseEnum _check_watertight_sidesets;
//// whether to check that each external node is assigned to a nodeset
const MooseEnum _check_watertight_nodesets;
/// whether to check element volumes
const MooseEnum _check_element_volumes;
/// minimum size for element volume to be counted as a tiny element
Expand Down
74 changes: 70 additions & 4 deletions framework/src/meshgenerators/MeshDiagnosticsGenerator.C
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ MeshDiagnosticsGenerator::validParams()
"check_for_watertight_sidesets",
chk_option,
"whether to check for external sides that are not assigned to any sidesets");
params.addParam<MooseEnum>(
"check_for_watertight_nodesets",
chk_option,
"whether to check for external nodes that are not assigned to any nodeset");
params.addParam<MooseEnum>(
"examine_element_volumes", chk_option, "whether to examine volume of the elements");
params.addParam<Real>("minimum_element_volumes", 1e-16, "minimum size for element volume");
Expand Down Expand Up @@ -80,6 +84,7 @@ MeshDiagnosticsGenerator::MeshDiagnosticsGenerator(const InputParameters & param
_input(getMesh("input")),
_check_sidesets_orientation(getParam<MooseEnum>("examine_sidesets_orientation")),
_check_watertight_sidesets(getParam<MooseEnum>("check_for_watertight_sidesets")),
_check_watertight_nodesets(getParam<MooseEnum>("check_for_watertight_nodesets")),
_check_element_volumes(getParam<MooseEnum>("examine_element_volumes")),
_min_volume(getParam<Real>("minimum_element_volumes")),
_max_volume(getParam<Real>("maximum_element_volumes")),
Expand All @@ -103,10 +108,10 @@ MeshDiagnosticsGenerator::MeshDiagnosticsGenerator(const InputParameters & param
paramError("examine_non_conformality",
"You must set this parameter to true to trigger mesh conformality check");
if (_check_sidesets_orientation == "NO_CHECK" && _check_watertight_sidesets == "NO_CHECK" &&
_check_element_volumes == "NO_CHECK" && _check_element_types == "NO_CHECK" &&
_check_element_overlap == "NO_CHECK" && _check_non_planar_sides == "NO_CHECK" &&
_check_non_conformal_mesh == "NO_CHECK" && _check_adaptivity_non_conformality == "NO_CHECK" &&
_check_local_jacobian == "NO_CHECK")
_check_watertight_nodesets == "NO_CHECK" && _check_element_volumes == "NO_CHECK" &&
_check_element_types == "NO_CHECK" && _check_element_overlap == "NO_CHECK" &&
_check_non_planar_sides == "NO_CHECK" && _check_non_conformal_mesh == "NO_CHECK" &&
_check_adaptivity_non_conformality == "NO_CHECK" && _check_local_jacobian == "NO_CHECK")
mooseError("You need to turn on at least one diagnostic. Did you misspell a parameter?");
}

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

if (_check_watertight_nodesets != "NO_CHECK")
checkWatertightNodesets(mesh);

if (_check_element_volumes != "NO_CHECK")
checkElementVolumes(mesh);

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

void
MeshDiagnosticsGenerator::checkWatertightNodesets(const std::unique_ptr<MeshBase> & mesh) const
{
/*
Diagnostic Overview:
1) Mesh precheck
2) Loop through all elements
3) Loop through all sides of that element
4) If side is external loop through its nodes
5) If node is not associated with any nodeset add to list
6) Print out node id
*/
if (mesh->mesh_dimension() < 2)
mooseError("The nodeset check only works for 2D and 3D meshes");
auto & boundary_info = mesh->get_boundary_info();
unsigned int num_nodes_without_nodeset = 0;
std::set<dof_id_type> checked_nodes_id;

for (const auto elem : mesh->active_element_ptr_range())
{
for (const auto i : elem->side_index_range())
{
// Check if side is external
if (elem->neighbor_ptr(i) == nullptr)
{
// Side is external, now check nodes
auto side = elem->side_ptr(i);
const auto & node_list = side->get_nodes();
for (unsigned int j = 0; j < side->n_nodes(); j++)
{
const auto node = node_list[j];
if (checked_nodes_id.count(node->id()))
continue;
// if node has no nodeset, add it to list of bad nodes
if (boundary_info.n_boundary_ids(node) == 0)
{
// This node does not have a nodeset!!!
num_nodes_without_nodeset++;
checked_nodes_id.insert(node->id());
std::string message;
if (num_nodes_without_nodeset < _num_outputs)
{
message =
"Node " + std::to_string(node->id()) +
" is on an external boundary of the mesh, but has not been assigned to a nodeset";
_console << message << std::endl;
}
}
}
}
}
}
std::string message;
message = "Number of external nodes that have not been assigned to a nodeset: " +
std::to_string(num_nodes_without_nodeset);
diagnosticsLog(message, _check_watertight_nodesets, num_nodes_without_nodeset);
}

void
MeshDiagnosticsGenerator::checkElementVolumes(const std::unique_ptr<MeshBase> & mesh) const
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[Mesh]
[gmg]
type = GeneratedMeshGenerator
dim = 2
nx = 2
ny = 2
[]
[deletion]
type = BoundaryDeletionGenerator
input = gmg
boundary_names = 'right'
[]
[diag]
type = MeshDiagnosticsGenerator
input = deletion
check_for_watertight_nodesets = INFO
[]
[]

[Outputs]
exodus = true
[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[Mesh]
[gmg]
type = GeneratedMeshGenerator
dim = 3
nx = 2
ny = 2
nz = 2
[]
[deletion]
type = BoundaryDeletionGenerator
input = gmg
boundary_names = 'right'
[]
[diag]
type = MeshDiagnosticsGenerator
input = deletion
check_for_watertight_nodesets = INFO
[]
[]

[Outputs]
exodus = true
[]
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
examine_nonplanar_sides = INFO
examine_sidesets_orientation = WARNING
check_for_watertight_sidesets = WARNING
check_for_watertight_nodesets = WARNING
search_for_adaptivity_nonconformality = WARNING
check_local_jacobian = WARNING
[]
Expand Down
17 changes: 17 additions & 0 deletions test/tests/meshgenerators/mesh_diagnostics_generator/tests
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,22 @@
expect_out = 'Number of external element faces that have not been assigned to a sideset: 4'
detail = '3D meshed cube missing a sideset on one side'
[]
[2D_watertight_nodesets]
type = 'RunApp'
input = '2D_missing_nodeset.i'
cli_args = '--mesh-only'
mesh_mode = 'replicated'
expect_out = 'Number of external nodes that have not been assigned to a nodeset: 1'
detail = '2D meshed square with one external node that does not belong to a nodeset'
[]
[3D_watertight_nodesets]
type = 'RunApp'
input = '3D_missing_nodeset.i'
cli_args = '--mesh-only'
mesh_mode = 'replicated'
expect_out = 'Number of external nodes that have not been assigned to a nodeset: 1'
detail = '3D meshed cube with one external node that does not belong to a nodeset'
[]
[overlap]
type = 'RunApp'
input = 'node_based_test.i'
Expand Down Expand Up @@ -253,6 +269,7 @@
Mesh/diag/examine_nonplanar_sides=NO_CHECK
Mesh/diag/examine_sidesets_orientation=NO_CHECK
Mesh/diag/check_for_watertight_sidesets=NO_CHECK
Mesh/diag/check_for_watertight_nodesets=NO_CHECK
Mesh/diag/search_for_adaptivity_nonconformality=NO_CHECK
Mesh/diag/check_local_jacobian=NO_CHECK --mesh-only"
detail = 'a diagnostics object is created but no diagnostics are requested.'
Expand Down

0 comments on commit 8a5faa9

Please sign in to comment.