Skip to content

Commit

Permalink
Added RefineSidesetGenerator to mesh_generators
Browse files Browse the repository at this point in the history
Updated generate function for RefineSidesetGenerator.C

Added test files for RefineSidesetGenerator

Cleanup code and add documentation for RefineSidesetGenerator

Updated test files, added golds to RefineSidesetGenerator

Formatting and doc edits for PR idaholab#18913

More formatting changes, and optimizing the recursive refine algorithm

Applying the formatting patch for RefineSideset

Changed get_boundary_info() call to work in-line rather than an explicit declaration

Clang-format changes to RefineSidesetGenerator.C

Added documentation files to RefineSidesetGenerator.

Apply minor formatting and documentation changes from code review

Update framework/src/meshgenerators/RefineSidesetGenerator.C

Update framework/src/meshgenerators/RefineSidesetGenerator.C

Co-Authored-By: Logan Harbour <loganhharbour@gmail.com>
  • Loading branch information
socratesgorilla and loganharbour committed Sep 30, 2021
1 parent 7e77205 commit ebf9280
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 54 deletions.
@@ -0,0 +1,15 @@
# RefineSidesetGenerator

!syntax description /Mesh/RefineSidesetGenerator

## Overview

This MeshGenerator object allows the user to refine one or more boundaries in a mesh, as well as neighboring elements of the boundary/boundaries.

The user has to provide the name(s) of the boundary/boundaries to be modified, as well as the corresponding levels of refinement for each boundary. These must match up to the order of the aforementioned boundary name list, e.g. if the boundaries you wish to modify are 'left right', with 1 refinement for left, 2 for right, then the refinement list will need to look like '1 2'. By default, refinement in libmesh refines neighboring boundaries to avoid meshing problems. This generator shares this default, but it can be disabled with setting [!param](/Mesh/RefineSidesetGenerator/enable_neighbor_refinement) to `false`. Additionally, the user must provide the type of refinement to perform in [!param](/Mesh/RefineSidesetGenerator/boundary_side) where "primary" merely refines the elements on the boundary, "secondary" only refines the neighbors of the boundary, and "both" refines both the elements on the boundary and its neighboring elements.

!syntax parameters /Mesh/RefineSidesetGenerator

!syntax inputs /Mesh/RefineSidesetGenerator

!syntax children /Mesh/RefineSidesetGenerator
22 changes: 11 additions & 11 deletions framework/include/meshgenerators/RefineSidesetGenerator.h
Expand Up @@ -28,23 +28,23 @@ class RefineSidesetGenerator : public MeshGenerator
/// Input mesh to refine
std::unique_ptr<MeshBase> & _input;

/// List of block(s) to refine
/// List of boundarie(s) to refine
const std::vector<BoundaryName> _boundaries;

/// The amount of times to refine each block, corresponding to their index in 'block'
/// The amount of times to refine each boundary, corresponding to their index in 'boundaries'
const std::vector<int> _refinement;

/// Toggles whether neighboring level one elements should be refined or not. Defaults to true.
const bool _enable_neighbor_refinement;

/// Side(s) of the boundary to be refined
const std::vector<MooseEnum> _boundary_side;
/// Side(s) of the boundary/boundaries to be refined. Can be either "primary"(just the boundary elements), "secondary"(just the neighboring elements), or "both."
const MultiMooseEnum _boundary_side;

/// The actual function refining the blocks. This is done recursively in order to minimize the number of refinement iterations to as little as possible.
virtual std::unique_ptr<MeshBase> recursive_refine(const std::vector<boundary_id_type> boundary_ids,
const std::vector<MooseEnum> boundary_side,
std::unique_ptr<MeshBase> & mesh,
const std::vector<int> refinement,
const int max,
int ref_step = 0);
/// The actual function refining the boundaries. This is done recursively in order to minimize the number of refinement iterations.
virtual std::unique_ptr<MeshBase>
recursive_refine(const std::vector<boundary_id_type> boundary_ids,
std::unique_ptr<MeshBase> & mesh,
const std::vector<int> refinement,
const int max,
int ref_step = 0);
};
99 changes: 56 additions & 43 deletions framework/src/meshgenerators/RefineSidesetGenerator.C
Expand Up @@ -20,18 +20,22 @@ InputParameters
RefineSidesetGenerator::validParams()
{
InputParameters params = MeshGenerator::validParams();
MooseEnum boundary_side("primary secondary both", "both");
params.addClassDescription("Mesh generator which refines one or more sidesets");
params.addRequiredParam<MeshGeneratorName>("input", "Input mesh to modify");
params.addRequiredParam<std::vector<BoundaryName>>("boundaries", "The list of boundaries to be modified");
params.addRequiredParam<std::vector<BoundaryName>>("boundaries",
"The list of boundaries to be modified");
params.addRequiredParam<std::vector<int>>(
"refinement",
"The amount of times to refine each block, corresponding to their index in 'block'");
"The amount of times to refine each sideset, corresponding to their index in 'boundaries'");
params.addParam<bool>(
"enable_neighbor_refinement",
true,
"Toggles whether neighboring level one elements should be refined or not. Defaults to true");
params.addParam<std::vector<MooseEnum>>("boundary_side", " ");
MultiMooseEnum boundary_side("primary secondary both", "both");
params.addParam<MultiMooseEnum>("boundary_side",
boundary_side,
"Whether the generator should refine itself(primary), its "
"neighbors(secondary), or itself and its neighbors(both)");

return params;
}
Expand All @@ -42,74 +46,83 @@ RefineSidesetGenerator::RefineSidesetGenerator(const InputParameters & parameter
_boundaries(getParam<std::vector<BoundaryName>>("boundaries")),
_refinement(getParam<std::vector<int>>("refinement")),
_enable_neighbor_refinement(getParam<bool>("enable_neighbor_refinement")),
_boundary_side(getParam<std::vector<MooseEnum>>("boundary_side"))
_boundary_side(getParam<MultiMooseEnum>("boundary_side"))
{
}

std::unique_ptr<MeshBase>
RefineSidesetGenerator::generate()
{

// Get the list of boundary ids from the boundary names
const auto boundary_ids =
MooseMeshUtils::getBoundaryIDs(*_input, getParam<std::vector<BoundaryName>>("boundary"), true);

// Check that the block ids/names exist in the mesh
/*
std::set<SubdomainID> mesh_boundaries;
_input->subdomain_ids(mesh_blocks);
const auto boundary_ids = MooseMeshUtils::getBoundaryIDs(
*_input, getParam<std::vector<BoundaryName>>("boundaries"), true);

// Check that the boundary ids/names exist in the mesh
for (std::size_t i = 0; i < boundary_ids.size(); ++i)
if (boundary_ids[i] == Moose::INVALID_BLOCK_ID || !mesh_boundaries.count(boundary_ids[i]))
{
if (isParamValid("_boundaries"))
paramError("boundaries",
"The boundary '",
getParam<std::vector<BoundaryName>>("boundaries")[i],
"' was not found within the mesh");
if (boundary_ids[i] == Moose::INVALID_BOUNDARY_ID && isParamValid("boundaries"))
paramError("boundaries",
"The boundary '",
getParam<std::vector<BoundaryName>>("boundaries")[i],
"' was not found within the mesh");
}
*/

std::unique_ptr<MeshBase> mesh = std::move(_input);
int max = *std::max_element(_refinement.begin(), _refinement.end());

return recursive_refine(boundary_ids, _boundary_side, mesh, _refinement, max);
return recursive_refine(boundary_ids, mesh, _refinement, max);
}

std::unique_ptr<MeshBase>
RefineSidesetGenerator::recursive_refine(std::vector<boundary_id_type> boundary_ids,
std::vector<MooseEnum> boundary_side,
std::unique_ptr<MeshBase> & mesh,
std::vector<int> refinement,
int max,
int ref_step)
std::unique_ptr<MeshBase> & mesh,
std::vector<int> refinement,
int max,
int ref_step)
{

// If the refinement step has reached the largest value in the _refinement array, return the mesh,
// as we are done.
if (ref_step == max)
return dynamic_pointer_cast<MeshBase>(mesh);
mesh->prepare_for_use();
std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>> sideList =
mesh->get_boundary_info().build_active_side_list();
for (std::size_t i = 0; i < boundary_ids.size(); i++)
{
if (refinement[i] > 0 && refinement[i] > ref_step)
{
BoundaryInfo boundInfo = mesh->get_boundary_info();
std::vector< std::tuple< dof_id_type, unsigned short int, boundary_id_type > > sideList = boundInfo.build_active_side_list();
for (std::tuple<dof_id_type, unsigned short int, boundary_id_type> tuple : sideList){
if (std::get<2>(tuple) == boundary_ids[i]){
//if (_boundary_side == "primary" || _boundary_side == "both"){
std::unique_ptr< Elem > elem = Elem::build_side_ptr(std::get<1>(tuple));
elem->set_refinement_flag(Elem::REFINE);
for (std::tuple<dof_id_type, unsigned short int, boundary_id_type> tuple : sideList)
{
if (std::get<2>(tuple) == boundary_ids[i])
{
Elem * elem = mesh->elem_ptr(std::get<0>(tuple));
if (_boundary_side[i] == "primary" || _boundary_side[i] == "both")
elem->set_refinement_flag(Elem::REFINE);
if (_boundary_side[i] == "secondary" || _boundary_side[i] == "both")
{
auto neighbor = elem->neighbor_ptr(std::get<1>(tuple));
// when we have multiple domains, domains will only refine the elements that they own
// since there can be instances where there is no neighbor, this null_ptr check is
// necessary
if (neighbor)
{
if (neighbor->active())
neighbor->set_refinement_flag(Elem::REFINE);
else
{
std::vector<Elem *> family_tree;
neighbor->active_family_tree_by_neighbor(family_tree, elem);
for (auto child_elem : family_tree)
child_elem->set_refinement_flag(Elem::REFINE);
}
}
}
/*
if (_boundary_side == "secondary" || _boundary_side == "both")
//std::get<0>(elem).neighbor_ptr(i)->set_refinement_flag(Elem::REFINE);
std::get<0>(elem);
}*/
}
}
}
}
MeshRefinement refinedmesh(*mesh);
if (!_enable_neighbor_refinement)
refinedmesh.face_level_mismatch_limit() = 0;
refinedmesh.refine_elements();

ref_step++;
return recursive_refine(boundary_ids, boundary_side, mesh, refinement, max, ref_step);
return recursive_refine(boundary_ids, mesh, refinement, max, ref_step);
}
Binary file not shown.
Binary file not shown.
37 changes: 37 additions & 0 deletions test/tests/meshgenerators/refine_sideset_generator/test_left.i
@@ -0,0 +1,37 @@
[Mesh]
[eg]
type = CartesianMeshGenerator
dim = 3
dx = '2 1 1'
dy = '2 3'
dz = '0.4 0.5 0.6 0.7'
ix = '2 1 1'
iy = '2 3'
iz = '1 1 1 1'
subdomain_id = '0 1 1 1
1 2 0 1
0 1 1 1
2 2 2 2
3 3 1 3
1 1 1 1'
[]
[sideset]
type = SideSetsBetweenSubdomainsGenerator
input = eg
primary_block = 1
paired_block = 2
new_boundary = sideset_1
[]
[refine]
type = RefineSidesetGenerator
input = sideset
boundaries = 'sideset_1'
refinement = '2'
boundary_side = 'secondary'
enable_neighbor_refinement = false
[]
[]

[Outputs]
exodus = true
[]
37 changes: 37 additions & 0 deletions test/tests/meshgenerators/refine_sideset_generator/test_multi.i
@@ -0,0 +1,37 @@
[Mesh]
[eg]
type = CartesianMeshGenerator
dim = 3
dx = '2 1 1'
dy = '2 3'
dz = '0.4 0.5 0.6 0.7'
ix = '2 1 1'
iy = '2 3'
iz = '1 1 1 1'
subdomain_id = '0 1 1 1
1 2 0 1
0 1 1 1
2 2 2 2
3 3 1 3
1 1 1 1'
[]
[sideset]
type = SideSetsBetweenSubdomainsGenerator
input = eg
primary_block = 1
paired_block = 2
new_boundary = sideset_1
[]
[refine]
type = RefineSidesetGenerator
input = sideset
boundaries = 'sideset_1'
refinement = '2'
boundary_side = 'both'
enable_neighbor_refinement = false
[]
[]

[Outputs]
exodus = true
[]
25 changes: 25 additions & 0 deletions test/tests/meshgenerators/refine_sideset_generator/tests
@@ -0,0 +1,25 @@
[Tests]
issues = '#18913'
design = 'meshgenerators/RefineSidesetGenerator.md'

[generate]
requirement = 'The system shall support the ability to refine'

[secondary]
type = 'Exodiff'
input = 'test_left.i'
exodiff = 'test_left_in.e'
cli_args = '--mesh-only'
recover = false
detail = 'a single block within a multi-domain mesh'
[]
[both]
type = 'Exodiff'
input = 'test_multi.i'
exodiff = 'test_multi_in.e'
recover = false
cli_args = "--mesh-only"
detail = 'multiple blocks within a multi-domain mesh'
[]
[]
[]

0 comments on commit ebf9280

Please sign in to comment.