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