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 "SideSetsAroundSubdomainGenerator.h"
11 : #include "InputParameters.h"
12 : #include "MooseTypes.h"
13 : #include "MeshTraversingUtils.h"
14 : #include "MooseMeshUtils.h"
15 : #include "CastUniquePointer.h"
16 :
17 : #include "libmesh/mesh.h"
18 : #include "libmesh/remote_elem.h"
19 : #include "libmesh/point.h"
20 : #include "libmesh/fe_base.h"
21 :
22 : registerMooseObject("MooseApp", SideSetsAroundSubdomainGenerator);
23 :
24 : InputParameters
25 5143 : SideSetsAroundSubdomainGenerator::validParams()
26 : {
27 5143 : InputParameters params = SideSetsGeneratorBase::validParams();
28 :
29 30858 : params.renameParam("included_subdomains", "block", "The blocks around which to create sidesets");
30 10286 : params.makeParamRequired<std::vector<SubdomainName>>("block");
31 :
32 : // Not implemented, but could be implemented
33 10286 : params.suppressParameter<std::vector<BoundaryName>>("included_boundaries");
34 10286 : params.suppressParameter<std::vector<BoundaryName>>("excluded_boundaries");
35 10286 : params.suppressParameter<std::vector<SubdomainName>>("included_neighbors");
36 :
37 5143 : params.addClassDescription(
38 : "Adds element faces that are on the exterior of the given block to the sidesets specified");
39 :
40 5143 : return params;
41 0 : }
42 :
43 1038 : SideSetsAroundSubdomainGenerator::SideSetsAroundSubdomainGenerator(
44 1038 : const InputParameters & parameters)
45 1038 : : SideSetsGeneratorBase(parameters)
46 : {
47 1038 : }
48 :
49 : std::unique_ptr<MeshBase>
50 969 : SideSetsAroundSubdomainGenerator::generate()
51 : {
52 969 : std::unique_ptr<MeshBase> mesh = std::move(_input);
53 :
54 : // construct the FE object so we can compute normals of faces
55 969 : setup(*mesh);
56 :
57 : // Create the boundary IDs from the list of names provided (the true flag creates ids from unknown
58 : // names)
59 : std::vector<boundary_id_type> boundary_ids =
60 966 : MooseMeshUtils::getBoundaryIDs(*mesh, _boundary_names, true);
61 :
62 : // Get a reference to our BoundaryInfo object for later use
63 966 : BoundaryInfo & boundary_info = mesh->get_boundary_info();
64 :
65 : // Prepare to query about sides adjacent to remote elements if we're
66 : // on a distributed mesh
67 966 : const processor_id_type my_n_proc = mesh->n_processors();
68 966 : const processor_id_type my_proc_id = mesh->processor_id();
69 : typedef std::vector<std::pair<dof_id_type, unsigned int>> vec_type;
70 966 : std::vector<vec_type> queries(my_n_proc);
71 :
72 : // Request to compute normal vectors
73 966 : const std::vector<Point> & face_normals = _fe_face->get_normals();
74 :
75 : // Loop over the elements
76 91315 : for (const auto & elem : mesh->active_element_ptr_range())
77 : {
78 : // We only need to loop over elements in the source subdomain
79 180698 : if (_check_subdomains &&
80 90349 : !MeshTraversingUtils::elementSubdomainIdInList(elem, _included_subdomain_ids))
81 48187 : continue;
82 :
83 214840 : for (const auto side : make_range(elem->n_sides()))
84 : {
85 172678 : const auto * neighbor = elem->neighbor_ptr(side);
86 :
87 : // On a replicated mesh, we add all subdomain sides ourselves.
88 : // On a distributed mesh, we may have missed sides which
89 : // neighbor remote elements. We should query any such cases.
90 172678 : if (neighbor == remote_elem)
91 : {
92 126 : queries[elem->processor_id()].push_back(std::make_pair(elem->id(), side));
93 : }
94 172552 : else if (elemSideOnBoundary(elem, side))
95 : {
96 32832 : _fe_face->reinit(elem, side);
97 : // We'll just use the normal of the first qp
98 32832 : const Point & face_normal = face_normals[0];
99 : // Add the boundaries, if appropriate
100 32832 : if (elemSideSatisfiesRequirements(elem, side, *mesh, _normal, face_normal))
101 : {
102 9540 : if (_replace)
103 0 : boundary_info.remove_side(elem, side);
104 19080 : for (const auto & boundary_id : boundary_ids)
105 9540 : boundary_info.add_side(elem, side, boundary_id);
106 : }
107 : }
108 : }
109 966 : }
110 :
111 966 : if (!mesh->is_serial())
112 : {
113 40 : const auto queries_tag = mesh->comm().get_unique_tag(),
114 40 : replies_tag = mesh->comm().get_unique_tag();
115 :
116 120 : std::vector<Parallel::Request> side_requests(my_n_proc - 1), reply_requests(my_n_proc - 1);
117 :
118 : // Make all requests
119 180 : for (processor_id_type p = 0; p != my_n_proc; ++p)
120 : {
121 140 : if (p == my_proc_id)
122 40 : continue;
123 :
124 100 : Parallel::Request & request = side_requests[p - (p > my_proc_id)];
125 :
126 100 : mesh->comm().send(p, queries[p], request, queries_tag);
127 : }
128 :
129 : // Reply to all requests
130 40 : std::vector<vec_type> responses(my_n_proc - 1);
131 :
132 140 : for (processor_id_type p = 1; p != my_n_proc; ++p)
133 : {
134 100 : vec_type query;
135 :
136 100 : Parallel::Status status(mesh->comm().probe(Parallel::any_source, queries_tag));
137 100 : const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
138 :
139 100 : mesh->comm().receive(source_pid, query, queries_tag);
140 :
141 100 : Parallel::Request & request = reply_requests[p - 1];
142 :
143 226 : for (const auto & q : query)
144 : {
145 126 : const Elem * elem = mesh->elem_ptr(q.first);
146 126 : const unsigned int side = q.second;
147 :
148 126 : _fe_face->reinit(elem, side);
149 : // We'll just use the normal of the first qp
150 126 : const Point & face_normal = _fe_face->get_normals()[0];
151 138 : if (elemSideOnBoundary(elem, side) &&
152 12 : elemSideSatisfiesRequirements(elem, side, *mesh, _normal, face_normal))
153 3 : responses[p - 1].push_back(std::make_pair(elem->id(), side));
154 : }
155 :
156 100 : mesh->comm().send(source_pid, responses[p - 1], request, replies_tag);
157 100 : }
158 :
159 : // Process all incoming replies
160 140 : for (processor_id_type p = 1; p != my_n_proc; ++p)
161 : {
162 100 : Parallel::Status status(this->comm().probe(Parallel::any_source, replies_tag));
163 100 : const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
164 :
165 100 : vec_type response;
166 :
167 100 : this->comm().receive(source_pid, response, replies_tag);
168 :
169 103 : for (const auto & r : response)
170 : {
171 3 : const Elem * elem = mesh->elem_ptr(r.first);
172 3 : const unsigned int side = r.second;
173 :
174 3 : if (_replace)
175 0 : boundary_info.remove_side(elem, side);
176 6 : for (const auto & boundary_id : boundary_ids)
177 3 : boundary_info.add_side(elem, side, boundary_id);
178 : }
179 100 : }
180 :
181 40 : Parallel::wait(side_requests);
182 40 : Parallel::wait(reply_requests);
183 40 : }
184 :
185 : // Assign the supplied names to the newly created side sets
186 1932 : for (unsigned int i = 0; i < boundary_ids.size(); ++i)
187 966 : boundary_info.sideset_name(boundary_ids[i]) = _boundary_names[i];
188 :
189 966 : mesh->unset_is_prepared();
190 1932 : return dynamic_pointer_cast<MeshBase>(mesh);
191 966 : }
192 :
193 : bool
194 172678 : SideSetsAroundSubdomainGenerator::elemSideOnBoundary(const Elem * const elem,
195 : const unsigned int side) const
196 : {
197 172678 : const auto neighbor = elem->neighbor_ptr(side);
198 172678 : return (neighbor == nullptr) || (elem->subdomain_id() != neighbor->subdomain_id());
199 : }
|