www.mooseframework.org
BreakMeshByBlockGenerator.C
Go to the documentation of this file.
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 
11 #include "CastUniquePointer.h"
12 
13 #include "libmesh/distributed_mesh.h"
14 #include "libmesh/elem.h"
15 
16 #include <typeinfo>
17 
19 
20 template <>
23 {
25  params.addRequiredParam<MeshGeneratorName>("input", "The mesh we want to modify");
26  params.addClassDescription("Break boundaries based on the subdomains to which their sides are "
27  "attached. Naming convention for the new boundaries will be the old "
28  "boundary name plus \"_to_\" plus the subdomain name. At the moment"
29  "this only works on REPLICATED mesh");
30  return params;
31 }
32 
34  : BreakMeshByBlockGeneratorBase(parameters), _input(getMesh("input"))
35 {
36  if (typeid(_input).name() == typeid(DistributedMesh).name())
37  mooseError("BreakMeshByBlockGenerator only works with ReplicatedMesh.");
38 }
39 
40 std::unique_ptr<MeshBase>
42 {
43  std::unique_ptr<MeshBase> mesh = std::move(_input);
44 
45  // initialize the node to element map
46  std::map<dof_id_type, std::vector<dof_id_type>> node_to_elem_map;
47  for (const auto & elem : mesh->active_element_ptr_range())
48  for (unsigned int n = 0; n < elem->n_nodes(); n++)
49  node_to_elem_map[elem->node_id(n)].push_back(elem->id());
50 
51  for (auto node_it = node_to_elem_map.begin(); node_it != node_to_elem_map.end(); ++node_it)
52  {
53  const dof_id_type current_node_id = node_it->first;
54  const Node * current_node = mesh->node_ptr(current_node_id);
55 
56  if (current_node != nullptr)
57  {
58  // find node multiplicity
59  std::set<subdomain_id_type> connected_blocks;
60  for (auto elem_id = node_it->second.begin(); elem_id != node_it->second.end(); elem_id++)
61  {
62  const Elem * current_elem = mesh->elem_ptr(*elem_id);
63  connected_blocks.insert(current_elem->subdomain_id());
64  }
65 
66  unsigned int node_multiplicity = connected_blocks.size();
67 
68  // check if current_node need to be duplicated
69  if (node_multiplicity > 1)
70  {
71  // retrieve connected elements from the map
72  const std::vector<dof_id_type> & connected_elems = node_it->second;
73 
74  // find reference_subdomain_id (e.g. the subdomain with lower id)
75  auto subdomain_it = connected_blocks.begin();
76  subdomain_id_type reference_subdomain_id = *subdomain_it;
77 
78  // multiplicity counter to keep track of how many nodes we added
79  unsigned int multiplicity_counter = node_multiplicity;
80  for (auto elem_id : connected_elems)
81  {
82  // all the duplicate nodes are added and assigned
83  if (multiplicity_counter == 0)
84  break;
85 
86  Elem * current_elem = mesh->elem_ptr(elem_id);
87  if (current_elem->subdomain_id() != reference_subdomain_id)
88  {
89  // assign the newly added node to current_elem
90  Node * new_node = nullptr;
91 
92  for (unsigned int node_id = 0; node_id < current_elem->n_nodes(); ++node_id)
93  if (current_elem->node_id(node_id) ==
94  current_node->id()) // if current node == node on element
95  {
96  // add new node
97  new_node = Node::build(*current_node, mesh->n_nodes()).release();
98  new_node->processor_id() = current_node->processor_id();
99  mesh->add_node(new_node);
100 
101  // Add boundary info to the new node
102  std::vector<boundary_id_type> node_boundary_ids =
103  mesh->boundary_info->boundary_ids(current_node);
104  mesh->boundary_info->add_node(new_node, node_boundary_ids);
105 
106  multiplicity_counter--; // node created, update multiplicity counter
107 
108  current_elem->set_node(node_id) = new_node;
109  break; // ones the proper node has been fixed in one element we can break the
110  // loop
111  }
112 
113  for (auto connected_elem_id : connected_elems)
114  {
115  Elem * connected_elem = mesh->elem_ptr(connected_elem_id);
116 
117  // Assign the newly added node to other connected elements with the same block_id
118  if (connected_elem->subdomain_id() == current_elem->subdomain_id() &&
119  connected_elem != current_elem)
120  {
121  for (unsigned int node_id = 0; node_id < connected_elem->n_nodes(); ++node_id)
122  if (connected_elem->node_id(node_id) ==
123  current_node->id()) // if current node == node on element
124  {
125  connected_elem->set_node(node_id) = new_node;
126  break;
127  }
128  }
129  }
130  }
131  }
132 
133  // create blocks pair and assign element side to new interface boundary map
134  for (auto elem_id : connected_elems)
135  {
136  for (auto connected_elem_id : connected_elems)
137  {
138  Elem * current_elem = mesh->elem_ptr(elem_id);
139  Elem * connected_elem = mesh->elem_ptr(connected_elem_id);
140 
141  if (current_elem != connected_elem &&
142  current_elem->subdomain_id() < connected_elem->subdomain_id())
143  {
144  if (current_elem->has_neighbor(connected_elem))
145  {
146  std::pair<subdomain_id_type, subdomain_id_type> blocks_pair =
147  std::make_pair(current_elem->subdomain_id(), connected_elem->subdomain_id());
148 
149  _new_boundary_sides_map[blocks_pair].insert(std::make_pair(
150  current_elem->id(), current_elem->which_neighbor_am_i(connected_elem)));
151  }
152  }
153  }
154  }
155 
156  } // end multiplicity check
157  } // end loop over nodes
158  } // end nodeptr check
159 
160  addInterfaceBoundary(*mesh);
161  return dynamic_pointer_cast<MeshBase>(mesh);
162 }
163 
164 void
166 {
167  BoundaryInfo & boundary_info = mesh.get_boundary_info();
168 
169  boundary_id_type boundaryID = findFreeBoundaryId(mesh);
170  std::string boundaryName = _interface_name;
171 
172  // loop over boundary sides
173  for (auto & boundary_side_map : _new_boundary_sides_map)
174  {
175 
176  // find the appropriate boundary name and id
177  // given master and slave block ID
178  if (_split_interface)
180  boundary_side_map.first.first,
181  boundary_side_map.first.second,
182  boundaryName,
183  boundaryID,
184  boundary_info);
185  else
186  boundary_info.sideset_name(boundaryID) = boundaryName;
187 
188  // loop over all the side belonging to each pair and add it to the proper interface
189  for (auto & element_side : boundary_side_map.second)
190  boundary_info.add_side(element_side.first, element_side.second, boundaryID);
191  }
192 }
registerMooseObject("MooseApp", BreakMeshByBlockGenerator)
void addInterfaceBoundary(MeshBase &mesh)
generate the new boundary interface
void findBoundaryNameAndInd(MeshBase &mesh, const subdomain_id_type &, const subdomain_id_type &, std::string &, boundary_id_type &, BoundaryInfo &)
given the master and slave blocks this method return the appropriate boundary id and name ...
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
std::unique_ptr< T_DEST, T_DELETER > dynamic_pointer_cast(std::unique_ptr< T_SRC, T_DELETER > &src)
These are reworked from https://stackoverflow.com/a/11003103.
void mooseError(Args &&... args) const
Definition: MooseObject.h:147
void addRequiredParam(const std::string &name, const std::string &doc_string)
This method adds a parameter and documentation string to the InputParameters object that will be extr...
std::string _interface_name
the name of the new interface
std::unique_ptr< MeshBase > & _input
bool _split_interface
the flag to split the interface by block
InputParameters validParams< BreakMeshByBlockGenerator >()
PetscInt n
BreakMeshByBlockGenerator(const InputParameters &parameters)
const std::string & name() const
Get the name of the object.
Definition: MooseObject.h:59
InputParameters validParams< BreakMeshByBlockGeneratorBase >()
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump...
std::map< std::pair< subdomain_id_type, subdomain_id_type >, std::set< std::pair< dof_id_type, unsigned int > > > _new_boundary_sides_map
BoundaryID findFreeBoundaryId(MeshBase &mesh)
this method finds the first free boundary id
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.