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 14537 : SidesetAroundSubdomainUpdater::validParams()
21 : {
22 14537 : InputParameters params = DomainUserObject::validParams();
23 29074 : params.addClassDescription("Sets up a boundary between inner_subdomains and outer_subdomains");
24 58148 : params.addParam<std::vector<SubdomainName>>("inner_subdomains",
25 : "Subdomains that own the boundary");
26 58148 : params.addParam<std::vector<SubdomainName>>("outer_subdomains",
27 : "Subdomains on the outside of the boundary");
28 58148 : params.addParam<BoundaryName>("mask_side",
29 : "If specified, only add sides where this sideset exists.");
30 43611 : params.addParam<bool>("assign_outer_surface_sides",
31 29074 : true,
32 : "Assign sides of elements im `inner_subdomains` that have no neighbor.");
33 58148 : 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 87222 : params.renameParam(
37 : "update_sideset_name", "update_boundary_name", "The boundary name which is updated.");
38 58148 : 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 87222 : params.renameParam(
43 : "update_sideset_id", "update_boundary_id", "The boundary id which is updated.");
44 29074 : params.registerBase("MeshModifier");
45 43611 : params.addParam<bool>("verbose", false, "Whether to output some information during execution");
46 14537 : return params;
47 0 : }
48 :
49 141 : SidesetAroundSubdomainUpdater::SidesetAroundSubdomainUpdater(const InputParameters & parameters)
50 : : DomainUserObject(parameters),
51 282 : _pid(_communicator.rank()),
52 141 : _displaced_problem(_fe_problem.getDisplacedProblem().get()),
53 141 : _neighbor_side(_assembly.neighborSide()),
54 282 : _assign_outer_surface_sides(getParam<bool>("assign_outer_surface_sides")),
55 282 : _boundary_name(getParam<BoundaryName>("update_boundary_name")),
56 141 : _boundary_id(_mesh.getBoundaryID(_boundary_name)),
57 346 : _mask_side(isParamValid("mask_side") ? _mesh.getBoundaryID(getParam<BoundaryName>("mask_side"))
58 : : Moose::INVALID_BOUNDARY_ID),
59 141 : _boundary_info(_mesh.getMesh().get_boundary_info()),
60 141 : _displaced_boundary_info(
61 423 : _displaced_problem ? &_displaced_problem->mesh().getMesh().get_boundary_info() : nullptr)
62 : {
63 : // subdomains
64 282 : const auto & inner_subdomains = getParam<std::vector<SubdomainName>>("inner_subdomains");
65 282 : const auto & outer_subdomains = getParam<std::vector<SubdomainName>>("outer_subdomains");
66 282 : for (const auto id : MooseMeshUtils::getSubdomainIDs(_mesh.getMesh(), inner_subdomains))
67 282 : _inner_ids.insert(id);
68 282 : for (const auto id : MooseMeshUtils::getSubdomainIDs(_mesh.getMesh(), outer_subdomains))
69 282 : _outer_ids.insert(id);
70 141 : std::set<SubdomainID> mesh_subdomains = _mesh.meshSubdomains();
71 :
72 282 : for (const auto & id : _inner_ids)
73 141 : if (mesh_subdomains.find(id) == mesh_subdomains.end())
74 0 : paramError("inner_subdomains", "The block '", id, "' was not found in the mesh");
75 282 : for (const auto & id : _outer_ids)
76 141 : if (mesh_subdomains.find(id) == mesh_subdomains.end())
77 0 : paramError("outer_subdomains", "The block '", id, "' was not found in the mesh");
78 :
79 : // save boundary name
80 141 : _boundary_info.sideset_name(_boundary_id) = _boundary_name;
81 141 : _boundary_info.nodeset_name(_boundary_id) = _boundary_name;
82 141 : if (_displaced_boundary_info)
83 : {
84 0 : _displaced_boundary_info->sideset_name(_boundary_id) = _boundary_name;
85 0 : _displaced_boundary_info->nodeset_name(_boundary_id) = _boundary_name;
86 : }
87 141 : if (!_mesh.getConstructNodeListFromSideList())
88 4 : mooseDoOnce(
89 : mooseWarning("The user has selected 'construct_node_list_from_side_list' as false, but "
90 : "SidesetAroundSubdomainUpdate is building node lists from the side lists."));
91 137 : }
92 :
93 : void
94 6056 : SidesetAroundSubdomainUpdater::executeOnExternalSide(const Elem * elem, unsigned int side)
95 : {
96 : // we should add the sideset only of the current element is in the "inner" set _and_ the user set
97 : // assign_surface_sides
98 6056 : if (_inner_ids.count(elem->subdomain_id()))
99 : {
100 8437 : if (_assign_outer_surface_sides && !_boundary_info.has_boundary_id(elem, side, _boundary_id) &&
101 3565 : (_mask_side == Moose::INVALID_BOUNDARY_ID ||
102 2034 : _boundary_info.has_boundary_id(elem, side, _mask_side)))
103 1603 : _add[_pid].emplace_back(elem->id(), side);
104 : }
105 : else
106 : {
107 1184 : if (_boundary_info.has_boundary_id(elem, side, _boundary_id))
108 229 : _remove[_pid].emplace_back(elem->id(), side);
109 : }
110 6056 : }
111 :
112 : void
113 10452 : SidesetAroundSubdomainUpdater::executeOnInternalSide()
114 : {
115 10452 : processSide(_current_elem, _current_side, _neighbor_elem);
116 10452 : processSide(_neighbor_elem, _neighbor_side, _current_elem);
117 10452 : }
118 :
119 : void
120 20904 : SidesetAroundSubdomainUpdater::processSide(const Elem * primary_elem,
121 : unsigned short int primary_side,
122 : const Elem * secondary_elem)
123 : {
124 : // undisplaced mesh
125 37216 : if (_inner_ids.count(primary_elem->subdomain_id()) &&
126 37216 : _outer_ids.count(secondary_elem->subdomain_id()))
127 : {
128 :
129 : // we are on an inner element facing an outer element->add boundary
130 22208 : if ((!_boundary_info.has_boundary_id(primary_elem, primary_side, _boundary_id)) &&
131 11092 : (_mask_side == Moose::INVALID_BOUNDARY_ID ||
132 1168 : _boundary_info.has_boundary_id(primary_elem, primary_side, _mask_side)))
133 9924 : _add[primary_elem->processor_id()].emplace_back(primary_elem->id(), primary_side);
134 : }
135 : else
136 : {
137 : // we are on an outer, between inner elements, or other elements etc., delete
138 : // the boundary for sure
139 9788 : if (_boundary_info.has_boundary_id(primary_elem, primary_side, _boundary_id))
140 144 : _remove[primary_elem->processor_id()].emplace_back(primary_elem->id(), primary_side);
141 : }
142 20904 : }
143 :
144 : void
145 529 : SidesetAroundSubdomainUpdater::initialize()
146 : {
147 529 : _add.clear();
148 529 : _remove.clear();
149 529 : }
150 :
151 : void
152 41 : SidesetAroundSubdomainUpdater::threadJoin(const UserObject & uo)
153 : {
154 41 : const auto & sas = static_cast<const SidesetAroundSubdomainUpdater &>(uo);
155 :
156 59 : for (const auto & [pid, list] : sas._add)
157 18 : _add[pid].insert(_add[pid].end(), list.begin(), list.end());
158 :
159 55 : for (const auto & [pid, list] : sas._remove)
160 14 : _remove[pid].insert(_remove[pid].end(), list.begin(), list.end());
161 41 : }
162 :
163 : void
164 488 : SidesetAroundSubdomainUpdater::finalize()
165 : {
166 488 : const auto & mesh = _mesh.getMesh();
167 : const auto * displaced_mesh =
168 488 : _displaced_problem ? &_displaced_problem->mesh().getMesh() : nullptr;
169 1464 : if (getParam<bool>("verbose"))
170 : {
171 0 : unsigned int total_remove = 0, total_add = 0;
172 0 : for (const auto & [pid, list] : _remove)
173 0 : total_remove += _remove[pid].size();
174 0 : for (const auto & [pid, list] : _add)
175 0 : total_add += _add[pid].size();
176 0 : comm().sum(total_remove);
177 0 : comm().sum(total_add);
178 :
179 0 : if (total_remove)
180 0 : _console << "Removing " << total_remove << " sides from sideset " << _boundary_id
181 0 : << std::endl;
182 0 : if (total_add)
183 0 : _console << "Adding " << total_add << " sides to sideset " << _boundary_id << std::endl;
184 : }
185 :
186 196 : auto add_functor = [this, &mesh, &displaced_mesh](const processor_id_type, const auto & sent_data)
187 : {
188 11723 : for (auto & [elem_id, side] : sent_data)
189 : {
190 11527 : _boundary_info.add_side(mesh.elem_ptr(elem_id), side, _boundary_id);
191 11527 : if (_displaced_boundary_info)
192 0 : _displaced_boundary_info->add_side(displaced_mesh->elem_ptr(elem_id), side, _boundary_id);
193 : }
194 196 : };
195 :
196 : auto remove_functor =
197 130 : [this, &mesh, &displaced_mesh](const processor_id_type, const SideList & sent_data)
198 : {
199 503 : for (const auto & [elem_id, side] : sent_data)
200 : {
201 373 : const auto elem = mesh.elem_ptr(elem_id);
202 373 : _boundary_info.remove_side(elem, side, _boundary_id);
203 1119 : for (const auto local_node_id : elem->nodes_on_side(side))
204 1119 : _boundary_info.remove_node(elem->node_ptr(local_node_id), _boundary_id);
205 373 : if (_displaced_boundary_info)
206 : {
207 0 : const auto displaced_elem = displaced_mesh->elem_ptr(elem_id);
208 0 : _displaced_boundary_info->remove_side(displaced_elem, side, _boundary_id);
209 0 : for (const auto local_node_id : displaced_elem->nodes_on_side(side))
210 0 : _displaced_boundary_info->remove_node(displaced_elem->node_ptr(local_node_id),
211 0 : _boundary_id);
212 : }
213 : }
214 130 : };
215 :
216 : // communicate and act on remote and local changes
217 488 : TIMPI::push_parallel_vector_data(_communicator, _remove, remove_functor);
218 488 : TIMPI::push_parallel_vector_data(_communicator, _add, add_functor);
219 :
220 488 : auto sync = [](auto & mesh)
221 : {
222 488 : mesh.getMesh().get_boundary_info().parallel_sync_side_ids();
223 488 : mesh.getMesh().get_boundary_info().parallel_sync_node_ids();
224 488 : mesh.getMesh().get_boundary_info().build_node_list_from_side_list();
225 488 : mesh.update();
226 488 : };
227 488 : sync(_mesh);
228 488 : if (_displaced_problem)
229 0 : sync(_displaced_problem->mesh());
230 :
231 : // Reinit equation systems
232 488 : _fe_problem.meshChanged(
233 : /*intermediate_change=*/false, /*contract_mesh=*/false, /*clean_refinement_flags=*/false);
234 488 : }
|