Skip to content

Commit 5854ed9

Browse files
author
Sebastian Schunert
committed
Add mesh generator that checks if a set of blocks is enclosed by a set of sidesets (#20621)
1 parent 98a7c88 commit 5854ed9

File tree

7 files changed

+258
-0
lines changed

7 files changed

+258
-0
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# SidesetsEncloseBlocks
2+
3+
!syntax description /Mesh/SidesetsEncloseBlocks
4+
5+
This mesh generator ensures that the blocks provided by the
6+
[!param](/meshgenerators/SidesetsEncloseBlocks/block)
7+
parameter are enclosed by the sidesets provided by [!param](/meshgenerators/SidesetsEncloseBlocks/boundary).
8+
If that is not the case, the behavior of the mesh generator depends on whether
9+
[!param](/meshgenerators/SidesetsEncloseBlocks/new_boundary) is provided.
10+
If it is not provided, then an error is thrown. If it is provided, then the side
11+
that is not covered is added to the new boundary.
12+
13+
!syntax parameters /Mesh/SidesetsEncloseBlocks
14+
15+
!syntax inputs /Mesh/SidesetsEncloseBlocks
16+
17+
!syntax children /Mesh/SidesetsEncloseBlocks
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//* This file is part of the MOOSE framework
2+
//* https://www.mooseframework.org
3+
//*
4+
//* All rights reserved, see COPYRIGHT for full restrictions
5+
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6+
//*
7+
//* Licensed under LGPL 2.1, please see LICENSE for details
8+
//* https://www.gnu.org/licenses/lgpl-2.1.html
9+
10+
#pragma once
11+
12+
#include "MeshGenerator.h"
13+
14+
/**
15+
* MeshGenerator that checks if a set of blocks is enclosed by a set of sidesets.
16+
* It can either add sides that are not covered by a sideset by a new sidesets or
17+
* error out.
18+
*/
19+
class SidesetsEncloseBlocks : public MeshGenerator
20+
{
21+
public:
22+
static InputParameters validParams();
23+
24+
SidesetsEncloseBlocks(const InputParameters & parameters);
25+
26+
std::unique_ptr<MeshBase> generate() override;
27+
28+
protected:
29+
std::unique_ptr<MeshBase> & _input;
30+
};
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
//* This file is part of the MOOSE framework
2+
//* https://www.mooseframework.org
3+
//*
4+
//* All rights reserved, see COPYRIGHT for full restrictions
5+
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6+
//*
7+
//* Licensed under LGPL 2.1, please see LICENSE for details
8+
//* https://www.gnu.org/licenses/lgpl-2.1.html
9+
10+
#include "SidesetsEncloseBlocks.h"
11+
#include "InputParameters.h"
12+
#include "MooseTypes.h"
13+
#include "MooseMeshUtils.h"
14+
#include "CastUniquePointer.h"
15+
16+
#include "libmesh/remote_elem.h"
17+
18+
registerMooseObject("MooseApp", SidesetsEncloseBlocks);
19+
20+
defineLegacyParams(SidesetsEncloseBlocks);
21+
22+
InputParameters
23+
SidesetsEncloseBlocks::validParams()
24+
{
25+
InputParameters params = MeshGenerator::validParams();
26+
27+
params.addRequiredParam<MeshGeneratorName>("input", "The mesh we want to modify");
28+
params.addParam<std::vector<SubdomainName>>(
29+
"block", "The set of blocks that are checked if they are enclosed by boundary");
30+
params.addParam<std::vector<BoundaryName>>("boundary",
31+
"The name of the boundaries enclosing the ");
32+
params.addParam<BoundaryName>("new_boundary", "The name of the boundary to create");
33+
params.addClassDescription(
34+
"MeshGenerator that checks if a set of blocks is enclosed by a set of sidesets."
35+
"It can either add sides that are not covered by a sideset by a new sidesets or"
36+
"error out.");
37+
38+
return params;
39+
}
40+
41+
SidesetsEncloseBlocks::SidesetsEncloseBlocks(const InputParameters & parameters)
42+
: MeshGenerator(parameters), _input(getMesh("input"))
43+
{
44+
}
45+
46+
std::unique_ptr<MeshBase>
47+
SidesetsEncloseBlocks::generate()
48+
{
49+
std::unique_ptr<MeshBase> mesh = std::move(_input);
50+
51+
// Get a reference to our BoundaryInfo object for later use
52+
BoundaryInfo & boundary_info = mesh->get_boundary_info();
53+
54+
// get a list of all sides; vector of tuples (elem, loc_side, side_set)
55+
auto side_list = boundary_info.build_active_side_list();
56+
57+
// error on finding a side that is not covered
58+
bool error_out = !isParamValid("new_boundary");
59+
boundary_id_type new_sideset_id;
60+
if (!error_out)
61+
{
62+
BoundaryName new_boundary = getParam<BoundaryName>("new_boundary");
63+
std::stringstream ss;
64+
ss << new_boundary;
65+
ss >> new_sideset_id;
66+
if (ss.fail())
67+
new_sideset_id = boundary_info.get_id_by_name(new_boundary);
68+
69+
// make sure that _sideset exists
70+
if (new_sideset_id == BoundaryInfo::invalid_id)
71+
paramError("new_boundary", "Not a valid boundary");
72+
}
73+
74+
// get blocks
75+
std::vector<subdomain_id_type> vec_block_ids =
76+
MooseMeshUtils::getSubdomainIDs(*mesh, getParam<std::vector<SubdomainName>>("block"));
77+
std::set<subdomain_id_type> blk_ids(vec_block_ids.begin(), vec_block_ids.end());
78+
79+
// get boundaries
80+
// check if the provided sideset name is actually a sideset id
81+
// if _sideset_name can be converted to integer it's interpreted
82+
// as sideset id
83+
auto boundary_name_vec = getParam<std::vector<BoundaryName>>("boundary");
84+
std::vector<boundary_id_type> bnd_ids_vec;
85+
bnd_ids_vec.reserve(boundary_name_vec.size());
86+
std::set<boundary_id_type> bnd_ids;
87+
for (auto & bnd_name : boundary_name_vec)
88+
{
89+
std::stringstream ss;
90+
boundary_id_type sideset_id;
91+
ss << bnd_name;
92+
ss >> sideset_id;
93+
if (ss.fail())
94+
sideset_id = boundary_info.get_id_by_name(bnd_name);
95+
96+
// make sure that _sideset exists
97+
if (sideset_id == BoundaryInfo::invalid_id)
98+
paramError("boundary", "Not a valid boundary");
99+
bnd_ids_vec.push_back(sideset_id);
100+
bnd_ids.insert(sideset_id);
101+
}
102+
103+
// loop over all elements in blocks and for each elem over each side
104+
// and check the neighbors
105+
for (auto & block_id : blk_ids)
106+
{
107+
for (const Elem * elem : as_range(mesh->active_local_subdomain_elements_begin(block_id),
108+
mesh->active_local_subdomain_elements_end(block_id)))
109+
{
110+
// loop through sides
111+
for (unsigned int j = 0; j < elem->n_sides(); ++j)
112+
{
113+
const Elem * neigh = elem->neighbor_ptr(j);
114+
115+
// is this an outside boundary to blocks?
116+
// NOTE: the next line is NOT sufficient for AMR!!
117+
bool is_outer_bnd = !neigh || blk_ids.find(neigh->subdomain_id()) == blk_ids.end();
118+
if (is_outer_bnd)
119+
{
120+
// get all boundary ids of this side, then compare the set of these boundary_ids
121+
// to the set of boundary_ids provided to the mesh generator; if the intersection
122+
// is empty then this side is NOT convered
123+
std::vector<boundary_id_type> side_boundary_ids_vec;
124+
boundary_info.raw_boundary_ids(elem, j, side_boundary_ids_vec);
125+
126+
std::set<boundary_id_type> intersection;
127+
std::set_intersection(side_boundary_ids_vec.begin(),
128+
side_boundary_ids_vec.end(),
129+
bnd_ids_vec.begin(),
130+
bnd_ids_vec.end(),
131+
std::inserter(intersection, intersection.end()));
132+
// is intersection emtpy?
133+
if (intersection.size() == 0)
134+
{
135+
if (error_out)
136+
mooseError("Element id ",
137+
elem->id(),
138+
" side ",
139+
j,
140+
" is external and not covered by specified boundaries.");
141+
else
142+
boundary_info.add_side(elem, j, new_sideset_id);
143+
}
144+
}
145+
}
146+
}
147+
}
148+
149+
return dynamic_pointer_cast<MeshBase>(mesh);
150+
}
Binary file not shown.
Binary file not shown.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[Mesh]
2+
[cmg]
3+
type = CartesianMeshGenerator
4+
dim = 2
5+
dx = '1 1 1 1'
6+
dy = '1 1 1 1'
7+
subdomain_id = '1 2 1 2
8+
1 3 4 4
9+
2 5 10 1
10+
1 2 2 2'
11+
[]
12+
13+
[add_sides]
14+
type = SideSetsBetweenSubdomainsGenerator
15+
primary_block = '3 4 5 10'
16+
paired_block = '1 2'
17+
new_boundary = 'interior'
18+
input = cmg
19+
[]
20+
21+
[enclosed]
22+
type = SidesetsEncloseBlocks
23+
block = '3 4 5 10'
24+
boundary = '1 4'
25+
input = add_sides
26+
[]
27+
[]
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
[Tests]
2+
design = 'meshgenerators/SidesetsEncloseBlocks.md'
3+
issues = '#20621'
4+
5+
[sidesets_enclosed_blocks]
6+
requirement = 'The system shall be able to check of a set of blocks is enclosed by a set of sidesets'
7+
recover = false
8+
9+
[check_no_error]
10+
type = 'Exodiff'
11+
input = 'sideset_enclose_blocks.i'
12+
exodiff = 'check_no_error.e'
13+
detail = '.'
14+
cli_args = '--mesh-only check_no_error.e'
15+
[]
16+
17+
[check_error]
18+
type = RunException
19+
input = 'sideset_enclose_blocks.i'
20+
expect_err = "Element id 5 side 0 is external and not covered by specified boundaries."
21+
cli_args = 'Mesh/add_sides/paired_block="1" --mesh-only'
22+
detail = ' and error out if this condition is not met.'
23+
[]
24+
25+
[add_new_boundary]
26+
type = 'Exodiff'
27+
input = 'sideset_enclose_blocks.i'
28+
exodiff = 'add_new_boundary.e'
29+
max_parallel = 1
30+
cli_args = 'Mesh/add_sides/paired_block="1" Mesh/enclosed/new_boundary=12 --mesh-only add_new_boundary.e'
31+
detail = ' and upon user request add missing sides into a specified input.'
32+
[]
33+
[]
34+
[]

0 commit comments

Comments
 (0)