diff --git a/framework/doc/content/source/meshgenerators/RefineSidesetGenerator.md b/framework/doc/content/source/meshgenerators/RefineSidesetGenerator.md new file mode 100644 index 000000000000..05cfb4076ff2 --- /dev/null +++ b/framework/doc/content/source/meshgenerators/RefineSidesetGenerator.md @@ -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 diff --git a/framework/include/meshgenerators/RefineSidesetGenerator.h b/framework/include/meshgenerators/RefineSidesetGenerator.h index f02713f11beb..b43ee76bea05 100644 --- a/framework/include/meshgenerators/RefineSidesetGenerator.h +++ b/framework/include/meshgenerators/RefineSidesetGenerator.h @@ -28,23 +28,23 @@ class RefineSidesetGenerator : public MeshGenerator /// Input mesh to refine std::unique_ptr & _input; - /// List of block(s) to refine + /// List of boundarie(s) to refine const std::vector _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 _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 _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 recursive_refine(const std::vector boundary_ids, - const std::vector boundary_side, - std::unique_ptr & mesh, - const std::vector 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 + recursive_refine(const std::vector boundary_ids, + std::unique_ptr & mesh, + const std::vector refinement, + const int max, + int ref_step = 0); }; diff --git a/framework/src/meshgenerators/RefineSidesetGenerator.C b/framework/src/meshgenerators/RefineSidesetGenerator.C index 3757c9e8074b..f99f132cbfc0 100644 --- a/framework/src/meshgenerators/RefineSidesetGenerator.C +++ b/framework/src/meshgenerators/RefineSidesetGenerator.C @@ -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("input", "Input mesh to modify"); - params.addRequiredParam>("boundaries", "The list of boundaries to be modified"); + params.addRequiredParam>("boundaries", + "The list of boundaries to be modified"); params.addRequiredParam>( "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( "enable_neighbor_refinement", true, "Toggles whether neighboring level one elements should be refined or not. Defaults to true"); - params.addParam>("boundary_side", " "); + MultiMooseEnum boundary_side("primary secondary both", "both"); + params.addParam("boundary_side", + boundary_side, + "Whether the generator should refine itself(primary), its " + "neighbors(secondary), or itself and its neighbors(both)"); return params; } @@ -42,66 +46,76 @@ RefineSidesetGenerator::RefineSidesetGenerator(const InputParameters & parameter _boundaries(getParam>("boundaries")), _refinement(getParam>("refinement")), _enable_neighbor_refinement(getParam("enable_neighbor_refinement")), - _boundary_side(getParam>("boundary_side")) + _boundary_side(getParam("boundary_side")) { } + std::unique_ptr RefineSidesetGenerator::generate() { - // Get the list of boundary ids from the boundary names - const auto boundary_ids = - MooseMeshUtils::getBoundaryIDs(*_input, getParam>("boundary"), true); - - // Check that the block ids/names exist in the mesh - /* - std::set mesh_boundaries; - _input->subdomain_ids(mesh_blocks); + const auto boundary_ids = MooseMeshUtils::getBoundaryIDs( + *_input, getParam>("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>("boundaries")[i], - "' was not found within the mesh"); + if (boundary_ids[i] == Moose::INVALID_BOUNDARY_ID && isParamValid("boundaries")) + paramError("boundaries", + "The boundary '", + getParam>("boundaries")[i], + "' was not found within the mesh"); } - */ + std::unique_ptr 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 RefineSidesetGenerator::recursive_refine(std::vector boundary_ids, - std::vector boundary_side, - std::unique_ptr & mesh, - std::vector refinement, - int max, - int ref_step) + std::unique_ptr & mesh, + std::vector 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(mesh); + mesh->prepare_for_use(); + std::vector> 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 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 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 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); - }*/ + } } } } @@ -109,7 +123,6 @@ RefineSidesetGenerator::recursive_refine(std::vector boundary_ 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); } diff --git a/test/tests/meshgenerators/refine_sideset_generator/gold/test_left_in.e b/test/tests/meshgenerators/refine_sideset_generator/gold/test_left_in.e new file mode 100644 index 000000000000..033dabe19831 Binary files /dev/null and b/test/tests/meshgenerators/refine_sideset_generator/gold/test_left_in.e differ diff --git a/test/tests/meshgenerators/refine_sideset_generator/gold/test_multi_in.e b/test/tests/meshgenerators/refine_sideset_generator/gold/test_multi_in.e new file mode 100644 index 000000000000..697a5b179cca Binary files /dev/null and b/test/tests/meshgenerators/refine_sideset_generator/gold/test_multi_in.e differ diff --git a/test/tests/meshgenerators/refine_sideset_generator/test_left.i b/test/tests/meshgenerators/refine_sideset_generator/test_left.i new file mode 100644 index 000000000000..b08a171e4259 --- /dev/null +++ b/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 +[] diff --git a/test/tests/meshgenerators/refine_sideset_generator/test_multi.i b/test/tests/meshgenerators/refine_sideset_generator/test_multi.i new file mode 100644 index 000000000000..957c09abba60 --- /dev/null +++ b/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 +[] diff --git a/test/tests/meshgenerators/refine_sideset_generator/tests b/test/tests/meshgenerators/refine_sideset_generator/tests new file mode 100644 index 000000000000..f50dc68b8ede --- /dev/null +++ b/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' + [] + [] +[]