Skip to content

Commit

Permalink
Merge pull request #18914 from socratesgorilla/refineSideset2
Browse files Browse the repository at this point in the history
Adding a RefineSidesetGenerator for refining boundaries
  • Loading branch information
loganharbour committed Oct 9, 2021
2 parents a70fe3b + a0f3ef8 commit d7c47ba
Show file tree
Hide file tree
Showing 10 changed files with 344 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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
59 changes: 59 additions & 0 deletions framework/include/meshgenerators/RefineSidesetGenerator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#pragma once

#include "MeshGenerator.h"

/**
* MeshGenerator for refining one or more sidesets
*/
class RefineSidesetGenerator : public MeshGenerator
{
public:
static InputParameters validParams();

RefineSidesetGenerator(const InputParameters & parameters);

protected:
virtual std::unique_ptr<MeshBase> generate() override;

private:
/// Input mesh to refine
std::unique_ptr<MeshBase> & _input;

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

/// 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/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 boundaries. This is done recursively in order
* to minimize the number of refinement iterations to as little as possible.
* @param boundary_ids Vector of boundary_ids to refine
* @param mesh The mesh to refine
* @param refinement Vector describing how many times to refine each boundary,
* corresponding to their placement in boundary_ids
* @param max Max value of all the refinement levels in the above vector
* @param ref_step Step counter for the recursive function, defaults to 0 for initial call.
* @return Unique pointer to a refined MeshBase
*/
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);
};
126 changes: 126 additions & 0 deletions framework/src/meshgenerators/RefineSidesetGenerator.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "RefineSidesetGenerator.h"
#include "MooseMeshUtils.h"

#include "libmesh/elem.h"
#include "libmesh/mesh_refinement.h"
#include "CastUniquePointer.h"

registerMooseObject("MooseApp", RefineSidesetGenerator);

InputParameters
RefineSidesetGenerator::validParams()
{
InputParameters params = MeshGenerator::validParams();
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<int>>(
"refinement",
"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");
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;
}

RefineSidesetGenerator::RefineSidesetGenerator(const InputParameters & parameters)
: MeshGenerator(parameters),
_input(getMesh("input")),
_boundaries(getParam<std::vector<BoundaryName>>("boundaries")),
_refinement(getParam<std::vector<int>>("refinement")),
_enable_neighbor_refinement(getParam<bool>("enable_neighbor_refinement")),
_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>>("boundaries"), false);

// 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_BOUNDARY_ID)
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, mesh, _refinement, max);
}

std::unique_ptr<MeshBase>
RefineSidesetGenerator::recursive_refine(std::vector<boundary_id_type> boundary_ids,
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)
{
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);
}
}
}
}
}
}
}
MeshRefinement refinedmesh(*mesh);
if (!_enable_neighbor_refinement)
refinedmesh.face_level_mismatch_limit() = 0;
refinedmesh.refine_elements();
ref_step++;
return recursive_refine(boundary_ids, mesh, refinement, max, ref_step);
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
30 changes: 30 additions & 0 deletions test/tests/meshgenerators/refine_sideset_generator/test_left.i
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[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'
[]
[refine]
type = RefineSidesetGenerator
input = eg
boundaries = 'left'
refinement = '3'
boundary_side = 'primary'
enable_neighbor_refinement = false
[]
[]

[Outputs]
exodus = true
[]
37 changes: 37 additions & 0 deletions test/tests/meshgenerators/refine_sideset_generator/test_multi.i
Original file line number Diff line number Diff line change
@@ -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
[]
Original file line number Diff line number Diff line change
@@ -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
[]
40 changes: 40 additions & 0 deletions test/tests/meshgenerators/refine_sideset_generator/tests
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
[Tests]
issues = '#18913'
design = 'meshgenerators/RefineSidesetGenerator.md'
[generate]
requirement = 'The system shall support the ability to refine'

[left]
type = 'Exodiff'
input = 'test_left.i'
exodiff = 'test_left_in.e'
cli_args = '--mesh-only'
recover = false
detail = 'neighboring elements of an external boundary along a mesh'
[]
[secondary]
type = 'Exodiff'
input = 'test_secondary.i'
exodiff = 'test_secondary_in.e'
cli_args = '--mesh-only'
recover = false
detail = 'neighboring elements of a specified boundary along a mesh'
[]
[both]
type = 'Exodiff'
input = 'test_multi.i'
exodiff = 'test_multi_in.e'
recover = false
cli_args = "--mesh-only"
detail = 'both the neighboring elements of, and the elements along, a specified boundary'
[]
[]
[failureBoundary]
type = 'RunException'
input = 'test_multi.i'
recover = false
cli_args = "Mesh/refine/boundaries='foo' --mesh-only"
expect_err = "The boundary *"
requirement = 'The system shall error if the specified boundary to be refined does not exist'
[]
[]

0 comments on commit d7c47ba

Please sign in to comment.