Skip to content

Commit

Permalink
fix and closes #15895
Browse files Browse the repository at this point in the history
Fixed gold file

added block restricted BMBB

this should work

added test for block restricted mode

fix and closes #15793

Fixed gold file

remove recover from test

added documentation

use Elem::invalid_subdomain_id isntead of -1

added tests and pedantic mode

updated documentation

removed depndenccy from #15794 and sqhased
  • Loading branch information
Andrea Rovinelli committed Oct 16, 2020
1 parent 97e06a9 commit 6723b73
Show file tree
Hide file tree
Showing 13 changed files with 322 additions and 29 deletions.
Expand Up @@ -10,6 +10,9 @@ To split the mesh, nodes shared by multiple blocks are duplicated N-1 times (whe

As an option, the interface can be split into $Q$ different sidesets, where $Q$ is the number of adjacent block pairs. This is achieved by setting `split_interface=true` and is useful when modeling interfaces with different parameters.

The split can be restricted to the blocks listed in the `block` input parameter. When blocks are provided the additional boundary `interface_transition` is added. The `interface_transition` boundary identifies the interface between the provided blocks and the rest of the mesh. The creation of `interface_transition` boundary can be inhibited by setting `add_transition_interface=false` and transition boundaries are added to the `interface` sidesets.
If present, the `interface_transition` boundary can be split by setting `split_transition_interface=true`.

## Example Input File Syntax

### Single Interface
Expand Down
9 changes: 8 additions & 1 deletion framework/include/meshgenerators/BreakMeshByBlockGenerator.h
Expand Up @@ -10,6 +10,7 @@
#pragma once

#include "BreakMeshByBlockGeneratorBase.h"
#include <unordered_set>

class BreakMeshByBlockGenerator;

Expand All @@ -26,7 +27,14 @@ class BreakMeshByBlockGenerator : public BreakMeshByBlockGeneratorBase
std::unique_ptr<MeshBase> generate() override;

protected:
subdomain_id_type blockRestricteElementSubdomainID(const Elem * elem);

std::unique_ptr<MeshBase> & _input;
std::vector<SubdomainID> _block;
std::unordered_set<SubdomainID> _block_set;
const bool _block_restricted;
const bool _add_transition_interface;
const bool _split_transition_interface;

private:
/// generate the new boundary interface
Expand All @@ -37,4 +45,3 @@ class BreakMeshByBlockGenerator : public BreakMeshByBlockGeneratorBase
std::set<std::pair<dof_id_type, unsigned int>>>
_new_boundary_sides_map;
};

Expand Up @@ -65,4 +65,3 @@ class BreakMeshByBlockGeneratorBase : public MeshGenerator
void mapBoundaryIdAndBoundaryName(boundary_id_type & /*boundaryID*/,
const std::string & /*boundaryName*/);
};

161 changes: 134 additions & 27 deletions framework/src/meshgenerators/BreakMeshByBlockGenerator.C
Expand Up @@ -12,7 +12,7 @@

#include "libmesh/distributed_mesh.h"
#include "libmesh/elem.h"

#include "libmesh/partitioner.h"
#include <typeinfo>

registerMooseObject("MooseApp", BreakMeshByBlockGenerator);
Expand All @@ -28,14 +28,39 @@ BreakMeshByBlockGenerator::validParams()
"attached. Naming convention for the new boundaries will be the old "
"boundary name plus \"_to_\" plus the subdomain name. At the moment"
"this only works on REPLICATED mesh");
params.addParam<std::vector<SubdomainID>>(
"block",
"The list of subdomain names where neml mehcanisc should be used, "
"default all blocks.");
params.addParam<bool>("add_transition_interface",
true,
"If true (default) and block is not empty, a special boundary named "
"interface_transition is generate between listed blocks and other blocks. "
"The transition boundary will not be split if split_interface=true");
params.addParam<bool>("split_transition_interface",
false,
"If true (default) and block is not empty, a special boundary named "
"interface_transition is generate between listed blocks and other blocks. "
"The transition boundary will not be split if split_interface=true");
return params;
}

BreakMeshByBlockGenerator::BreakMeshByBlockGenerator(const InputParameters & parameters)
: BreakMeshByBlockGeneratorBase(parameters), _input(getMesh("input"))
: BreakMeshByBlockGeneratorBase(parameters),
_input(getMesh("input")),
_block(parameters.isParamSetByUser("block") ? getParam<std::vector<SubdomainID>>("block")
: std::vector<SubdomainID>(0)),
_block_set(_block.begin(), _block.end()),
_block_restricted(parameters.isParamSetByUser("block")),
_add_transition_interface(getParam<bool>("add_transition_interface")),
_split_transition_interface(getParam<bool>("split_transition_interface"))
{
if (typeid(_input).name() == typeid(DistributedMesh).name())
mooseError("BreakMeshByBlockGenerator only works with ReplicatedMesh.");

if (!_add_transition_interface && _split_transition_interface)
mooseError("BreakMeshByBlockGenerator cannot split the transition interface becasue "
"add_transition_interface is false");
}

std::unique_ptr<MeshBase>
Expand All @@ -61,7 +86,7 @@ BreakMeshByBlockGenerator::generate()
for (auto elem_id = node_it->second.begin(); elem_id != node_it->second.end(); elem_id++)
{
const Elem * current_elem = mesh->elem_ptr(*elem_id);
connected_blocks.insert(current_elem->subdomain_id());
connected_blocks.insert(blockRestricteElementSubdomainID(current_elem));
}

unsigned int node_multiplicity = connected_blocks.size();
Expand All @@ -72,10 +97,13 @@ BreakMeshByBlockGenerator::generate()
// retrieve connected elements from the map
const std::vector<dof_id_type> & connected_elems = node_it->second;

// find reference_subdomain_id (e.g. the subdomain with lower id)
// find reference_subdomain_id (e.g. the subdomain with lower id or the
// Elem::invalid_subdomain_id)
auto subdomain_it = connected_blocks.begin();
subdomain_id_type reference_subdomain_id = *subdomain_it;

subdomain_id_type reference_subdomain_id =
connected_blocks.find(Elem::invalid_subdomain_id) != connected_blocks.end()
? Elem::invalid_subdomain_id
: *subdomain_it;
// multiplicity counter to keep track of how many nodes we added
unsigned int multiplicity_counter = node_multiplicity;
for (auto elem_id : connected_elems)
Expand All @@ -85,7 +113,7 @@ BreakMeshByBlockGenerator::generate()
break;

Elem * current_elem = mesh->elem_ptr(elem_id);
if (current_elem->subdomain_id() != reference_subdomain_id)
if (blockRestricteElementSubdomainID(current_elem) != reference_subdomain_id)
{
// assign the newly added node to current_elem
Node * new_node = nullptr;
Expand All @@ -99,8 +127,9 @@ BreakMeshByBlockGenerator::generate()
// add new node
new_node = Node::build(*current_node, mesh->n_nodes()).release();

// We're duplicating nodes so that each subdomain elem has its own copy, so it seems
// natural to assign this new node the same proc id as corresponding subdomain elem
// We're duplicating nodes so that each subdomain elem has its own copy, so it
// seems natural to assign this new node the same proc id as corresponding
// subdomain elem
new_node->processor_id() = current_elem->processor_id();
mesh->add_node(new_node);

Expand Down Expand Up @@ -142,17 +171,36 @@ BreakMeshByBlockGenerator::generate()
{
Elem * current_elem = mesh->elem_ptr(elem_id);
Elem * connected_elem = mesh->elem_ptr(connected_elem_id);
subdomain_id_type curr_elem_subid = blockRestricteElementSubdomainID(current_elem);
subdomain_id_type connected_elem_subid =
blockRestricteElementSubdomainID(connected_elem);

if (current_elem != connected_elem &&
current_elem->subdomain_id() < connected_elem->subdomain_id())
if (current_elem != connected_elem && curr_elem_subid < connected_elem_subid)
{
if (current_elem->has_neighbor(connected_elem))
{

dof_id_type elem_id = current_elem->id();
unsigned int side = current_elem->which_neighbor_am_i(connected_elem);

// in this case we need to play a game to reorder the sides
if (_block_restricted)
{
connected_elem_subid = connected_elem->subdomain_id();
if (curr_elem_subid > connected_elem_subid) // we need to switch the ids
{
connected_elem_subid = current_elem->subdomain_id();
curr_elem_subid = connected_elem->subdomain_id();

elem_id = connected_elem->id();
side = connected_elem->which_neighbor_am_i(current_elem);
}
}

std::pair<subdomain_id_type, subdomain_id_type> blocks_pair =
std::make_pair(current_elem->subdomain_id(), connected_elem->subdomain_id());
std::make_pair(curr_elem_subid, connected_elem_subid);

_new_boundary_sides_map[blocks_pair].insert(std::make_pair(
current_elem->id(), current_elem->which_neighbor_am_i(connected_elem)));
_new_boundary_sides_map[blocks_pair].insert(std::make_pair(elem_id, side));
}
}
}
Expand All @@ -171,27 +219,86 @@ BreakMeshByBlockGenerator::addInterfaceBoundary(MeshBase & mesh)
{
BoundaryInfo & boundary_info = mesh.get_boundary_info();

boundary_id_type boundaryID = findFreeBoundaryId(mesh);
std::string boundaryName = _interface_name;
boundary_id_type boundaryID;
boundary_id_type boundaryID_interface = Moose::INVALID_BOUNDARY_ID;
boundary_id_type boundaryID_interface_transition = Moose::INVALID_BOUNDARY_ID;

std::string boundaryName;

// loop over boundary sides
for (auto & boundary_side_map : _new_boundary_sides_map)
{
if (!_block_restricted || (_block_restricted && !_add_transition_interface))
{
// find the appropriate boundary name and id
// given primary and secondary block ID
if (_split_interface)
findBoundaryNameAndInd(mesh,
boundary_side_map.first.first,
boundary_side_map.first.second,
boundaryName,
boundaryID,
boundary_info);
else
{
boundaryName = _interface_name;
boundaryID_interface = boundaryID_interface == Moose::INVALID_BOUNDARY_ID
? findFreeBoundaryId(mesh)
: boundaryID_interface;
boundaryID = boundaryID_interface;
boundary_info.sideset_name(boundaryID_interface) = boundaryName;
}
}
else // block resticted with transition boundary
{

const bool interior_boundary =
_block_set.find(boundary_side_map.first.first) != _block_set.end() &&
_block_set.find(boundary_side_map.first.second) != _block_set.end();

// find the appropriate boundary name and id
// given primary and secondary block ID
if (_split_interface)
findBoundaryNameAndInd(mesh,
boundary_side_map.first.first,
boundary_side_map.first.second,
boundaryName,
boundaryID,
boundary_info);
else
boundary_info.sideset_name(boundaryID) = boundaryName;
if ((_split_interface && interior_boundary) ||
(_split_transition_interface && !interior_boundary))
{
findBoundaryNameAndInd(mesh,
boundary_side_map.first.first,
boundary_side_map.first.second,
boundaryName,
boundaryID,
boundary_info);
}
else if (interior_boundary)
{
boundaryName = _interface_name;
boundaryID_interface = boundaryID_interface == Moose::INVALID_BOUNDARY_ID
? findFreeBoundaryId(mesh)
: boundaryID_interface;

boundaryID = boundaryID_interface;
boundary_info.sideset_name(boundaryID_interface) = boundaryName;
}
else
{
boundaryID_interface_transition =
boundaryID_interface_transition == Moose::INVALID_BOUNDARY_ID
? findFreeBoundaryId(mesh)
: boundaryID_interface_transition;
boundaryID = boundaryID_interface_transition;
boundaryName = "interface_transition";
boundary_info.sideset_name(boundaryID) = boundaryName;
}
}
// loop over all the side belonging to each pair and add it to the proper interface
for (auto & element_side : boundary_side_map.second)
boundary_info.add_side(element_side.first, element_side.second, boundaryID);
}
}

subdomain_id_type
BreakMeshByBlockGenerator::blockRestricteElementSubdomainID(const Elem * elem)
{
subdomain_id_type elem_subdomain_id = elem->subdomain_id();
if (_block_restricted && (_block_set.find(elem_subdomain_id) == _block_set.end()))
elem_subdomain_id = Elem::invalid_subdomain_id;

return elem_subdomain_id;
}
@@ -0,0 +1,21 @@
[Mesh]
[msh]
type = CartesianMeshGenerator
dim = 3
dx = '0.25 0.25 0.25 0.25'
dy = '0.25 0.25 0.25 0.25'
dz = '0.25 0.25 0.25 0.25'
subdomain_id = '0 1 2 3 4 5 6 7 8 9 10 11 12
13 14 15 16 17 18 19 20 21 22 23 24 25
26 27 28 29 30 31 32 33 34 35 36 37 38
39 40 41 42 43 44 45 46 47 48 49 50 51
52 53 54 55 56 57 58 59 60 61 62 63'
[]
[split]
input = msh
type = BreakMeshByBlockGenerator
block = '16 17 18 19 20 21 22 23 24 25
26 27 28 29 30 31 32 34 35 36 37 38
39 40 41 42 43 44 45 46 47'
[]
[]
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,69 @@
[GlobalParams]
displacements = "disp_x disp_y disp_z"
[]

[Mesh]
[./msh]
type = GeneratedMeshGenerator
nx = 2
ny = 3
nz = 4
xmin = -2.5
xmax = 2.5
ymin = -2
ymax = 2
zmin = -1.5
zmax = 1.5
dim = 3
[../]
[./subdomain_1]
type = SubdomainBoundingBoxGenerator
input = msh
bottom_left = '-2.5 -2 -1'
top_right = '2.5 0 0.5'
block_id = 1
[]
[./subdomain_2]
type = SubdomainBoundingBoxGenerator
input = subdomain_1
bottom_left = '-2.5 0 -1'
top_right = '2.5 2 0.5'
block_id = 2
[]
[./subdomain_3]
type = SubdomainBoundingBoxGenerator
input = subdomain_2
bottom_left = '-2.5 -2 0.5'
top_right = '1.25 2 1.5'
block_id = 3
[]
[./subdomain_4]
type = SubdomainBoundingBoxGenerator
input = subdomain_3
bottom_left = '1.25 -2 0.5'
top_right = '5 2 1.5'
block_id = 4
[]
[./subdomain_5]
type = SubdomainBoundingBoxGenerator
input = subdomain_4
bottom_left = '-2.5 -2 -1.5'
top_right = '1.25 2 -1'
block_id = 3
[]
[./subdomain_6]
type = SubdomainBoundingBoxGenerator
input = subdomain_5
bottom_left = '1.25 -2 -1.5'
top_right = '2.5 2 -1'
block_id = 4
[]
[./split]
type = BreakMeshByBlockGenerator
input = subdomain_6
[]
[]

[Outputs]
exodus = true
[]

0 comments on commit 6723b73

Please sign in to comment.