Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://mooseframework.inl.gov
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 "SidesetAroundSubdomainUpdater.h"
11 : #include "DisplacedProblem.h"
12 : #include "Assembly.h"
13 :
14 : #include "libmesh/parallel_algebra.h"
15 : #include "libmesh/parallel_sync.h"
16 :
17 : registerMooseObject("MooseApp", SidesetAroundSubdomainUpdater);
18 :
19 : InputParameters
20 14523 : SidesetAroundSubdomainUpdater::validParams()
21 : {
22 14523 : InputParameters params = DomainUserObject::validParams();
23 14523 : params.addClassDescription("Sets up a boundary between inner_subdomains and outer_subdomains");
24 14523 : params.addParam<std::vector<SubdomainName>>("inner_subdomains",
25 : "Subdomains that own the boundary");
26 14523 : params.addParam<std::vector<SubdomainName>>("outer_subdomains",
27 : "Subdomains on the outside of the boundary");
28 14523 : params.addParam<BoundaryName>("mask_side",
29 : "If specified, only add sides where this sideset exists.");
30 43569 : params.addParam<bool>("assign_outer_surface_sides",
31 29046 : true,
32 : "Assign sides of elements im `inner_subdomains` that have no neighbor.");
33 14523 : params.addRequiredParam<BoundaryName>("update_sideset_name",
34 : "The name of the sideset to be updated. If the boundary "
35 : "does not exist it will be added to the system.");
36 14523 : params.renameParam(
37 : "update_sideset_name", "update_boundary_name", "The boundary name which is updated.");
38 14523 : params.addParam<BoundaryID>("update_sideset_id",
39 : Moose::INVALID_BOUNDARY_ID,
40 : "The ID of the sideset to be updated. If the boundary "
41 : "does not exist it will be added to the system.");
42 14523 : params.renameParam(
43 : "update_sideset_id", "update_boundary_id", "The boundary id which is updated.");
44 14523 : params.registerBase("MeshModifier");
45 14523 : return params;
46 0 : }
47 :
48 134 : SidesetAroundSubdomainUpdater::SidesetAroundSubdomainUpdater(const InputParameters & parameters)
49 : : DomainUserObject(parameters),
50 268 : _pid(_communicator.rank()),
51 134 : _displaced_problem(_fe_problem.getDisplacedProblem().get()),
52 134 : _neighbor_side(_assembly.neighborSide()),
53 134 : _assign_outer_surface_sides(getParam<bool>("assign_outer_surface_sides")),
54 134 : _boundary_name(getParam<BoundaryName>("update_boundary_name")),
55 134 : _boundary_id(_mesh.getBoundaryID(_boundary_name)),
56 134 : _mask_side(isParamValid("mask_side") ? _mesh.getBoundaryID(getParam<BoundaryName>("mask_side"))
57 : : Moose::INVALID_BOUNDARY_ID),
58 134 : _boundary_info(_mesh.getMesh().get_boundary_info()),
59 134 : _displaced_boundary_info(
60 402 : _displaced_problem ? &_displaced_problem->mesh().getMesh().get_boundary_info() : nullptr)
61 : {
62 : // subdomains
63 134 : const auto & inner_subdomains = getParam<std::vector<SubdomainName>>("inner_subdomains");
64 134 : const auto & outer_subdomains = getParam<std::vector<SubdomainName>>("outer_subdomains");
65 268 : for (const auto id : MooseMeshUtils::getSubdomainIDs(_mesh.getMesh(), inner_subdomains))
66 268 : _inner_ids.insert(id);
67 268 : for (const auto id : MooseMeshUtils::getSubdomainIDs(_mesh.getMesh(), outer_subdomains))
68 268 : _outer_ids.insert(id);
69 134 : std::set<SubdomainID> mesh_subdomains = _mesh.meshSubdomains();
70 :
71 268 : for (const auto & id : _inner_ids)
72 134 : if (mesh_subdomains.find(id) == mesh_subdomains.end())
73 0 : paramError("inner_subdomains", "The block '", id, "' was not found in the mesh");
74 268 : for (const auto & id : _outer_ids)
75 134 : if (mesh_subdomains.find(id) == mesh_subdomains.end())
76 0 : paramError("outer_subdomains", "The block '", id, "' was not found in the mesh");
77 :
78 : // save boundary name
79 134 : _boundary_info.sideset_name(_boundary_id) = _boundary_name;
80 134 : _boundary_info.nodeset_name(_boundary_id) = _boundary_name;
81 134 : if (_displaced_boundary_info)
82 : {
83 0 : _displaced_boundary_info->sideset_name(_boundary_id) = _boundary_name;
84 0 : _displaced_boundary_info->nodeset_name(_boundary_id) = _boundary_name;
85 : }
86 134 : if (!_mesh.getConstructNodeListFromSideList())
87 4 : mooseDoOnce(
88 : mooseWarning("The user has selected 'construct_node_list_from_side_list' as false, but "
89 : "SidesetAroundSubdomainUpdate is building node lists from the side lists."));
90 130 : }
91 :
92 : void
93 5472 : SidesetAroundSubdomainUpdater::executeOnExternalSide(const Elem * elem, unsigned int side)
94 : {
95 : // we should add the sideset only of the current element is in the "inner" set _and_ the user set
96 : // assign_surface_sides
97 5472 : if (_inner_ids.count(elem->subdomain_id()))
98 : {
99 7584 : if (_assign_outer_surface_sides && !_boundary_info.has_boundary_id(elem, side, _boundary_id) &&
100 3184 : (_mask_side == Moose::INVALID_BOUNDARY_ID ||
101 1792 : _boundary_info.has_boundary_id(elem, side, _mask_side)))
102 1456 : _add[_pid].emplace_back(elem->id(), side);
103 : }
104 : else
105 : {
106 1072 : if (_boundary_info.has_boundary_id(elem, side, _boundary_id))
107 208 : _remove[_pid].emplace_back(elem->id(), side);
108 : }
109 5472 : }
110 :
111 : void
112 9296 : SidesetAroundSubdomainUpdater::executeOnInternalSide()
113 : {
114 9296 : processSide(_current_elem, _current_side, _neighbor_elem);
115 9296 : processSide(_neighbor_elem, _neighbor_side, _current_elem);
116 9296 : }
117 :
118 : void
119 18592 : SidesetAroundSubdomainUpdater::processSide(const Elem * primary_elem,
120 : unsigned short int primary_side,
121 : const Elem * secondary_elem)
122 : {
123 : // undisplaced mesh
124 33136 : if (_inner_ids.count(primary_elem->subdomain_id()) &&
125 33136 : _outer_ids.count(secondary_elem->subdomain_id()))
126 : {
127 :
128 : // we are on an inner element facing an outer element->add boundary
129 19720 : if ((!_boundary_info.has_boundary_id(primary_elem, primary_side, _boundary_id)) &&
130 9848 : (_mask_side == Moose::INVALID_BOUNDARY_ID ||
131 1024 : _boundary_info.has_boundary_id(primary_elem, primary_side, _mask_side)))
132 8824 : _add[primary_elem->processor_id()].emplace_back(primary_elem->id(), primary_side);
133 : }
134 : else
135 : {
136 : // we are on an outer, between inner elements, or other elements etc., delete
137 : // the boundary for sure
138 8720 : if (_boundary_info.has_boundary_id(primary_elem, primary_side, _boundary_id))
139 128 : _remove[primary_elem->processor_id()].emplace_back(primary_elem->id(), primary_side);
140 : }
141 18592 : }
142 :
143 : void
144 492 : SidesetAroundSubdomainUpdater::initialize()
145 : {
146 492 : _add.clear();
147 492 : _remove.clear();
148 492 : }
149 :
150 : void
151 41 : SidesetAroundSubdomainUpdater::threadJoin(const UserObject & uo)
152 : {
153 41 : const auto & sas = static_cast<const SidesetAroundSubdomainUpdater &>(uo);
154 :
155 59 : for (const auto & [pid, list] : sas._add)
156 18 : _add[pid].insert(_add[pid].end(), list.begin(), list.end());
157 :
158 55 : for (const auto & [pid, list] : sas._remove)
159 14 : _remove[pid].insert(_remove[pid].end(), list.begin(), list.end());
160 41 : }
161 :
162 : void
163 451 : SidesetAroundSubdomainUpdater::finalize()
164 : {
165 451 : const auto & mesh = _mesh.getMesh();
166 : const auto * displaced_mesh =
167 451 : _displaced_problem ? &_displaced_problem->mesh().getMesh() : nullptr;
168 :
169 20741 : auto add_functor = [this, &mesh, &displaced_mesh](const processor_id_type, const auto & sent_data)
170 : {
171 10461 : for (auto & [elem_id, side] : sent_data)
172 : {
173 10280 : _boundary_info.add_side(mesh.elem_ptr(elem_id), side, _boundary_id);
174 10280 : if (_displaced_boundary_info)
175 0 : _displaced_boundary_info->add_side(displaced_mesh->elem_ptr(elem_id), side, _boundary_id);
176 : }
177 181 : };
178 :
179 : auto remove_functor =
180 1799 : [this, &mesh, &displaced_mesh](const processor_id_type, const SideList & sent_data)
181 : {
182 455 : for (const auto & [elem_id, side] : sent_data)
183 : {
184 336 : const auto elem = mesh.elem_ptr(elem_id);
185 336 : _boundary_info.remove_side(elem, side, _boundary_id);
186 1008 : for (const auto local_node_id : elem->nodes_on_side(side))
187 1008 : _boundary_info.remove_node(elem->node_ptr(local_node_id), _boundary_id);
188 336 : if (_displaced_boundary_info)
189 : {
190 0 : const auto displaced_elem = displaced_mesh->elem_ptr(elem_id);
191 0 : _displaced_boundary_info->remove_side(displaced_elem, side, _boundary_id);
192 0 : for (const auto local_node_id : displaced_elem->nodes_on_side(side))
193 0 : _displaced_boundary_info->remove_node(displaced_elem->node_ptr(local_node_id),
194 0 : _boundary_id);
195 : }
196 : }
197 119 : };
198 :
199 : // communicate and act on remote and local changes
200 451 : TIMPI::push_parallel_vector_data(_communicator, _remove, remove_functor);
201 451 : TIMPI::push_parallel_vector_data(_communicator, _add, add_functor);
202 :
203 451 : auto sync = [](auto & mesh)
204 : {
205 451 : mesh.getMesh().get_boundary_info().parallel_sync_side_ids();
206 451 : mesh.getMesh().get_boundary_info().parallel_sync_node_ids();
207 451 : mesh.getMesh().get_boundary_info().build_node_list_from_side_list();
208 451 : mesh.update();
209 451 : };
210 451 : sync(_mesh);
211 451 : if (_displaced_problem)
212 0 : sync(_displaced_problem->mesh());
213 :
214 : // Reinit equation systems
215 451 : _fe_problem.meshChanged(
216 : /*intermediate_change=*/false, /*contract_mesh=*/false, /*clean_refinement_flags=*/false);
217 451 : }
|