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 "SideSetsBetweenSubdomainsGenerator.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/remote_elem.h"
18 :
19 : registerMooseObject("MooseApp", SideSetsBetweenSubdomainsGenerator);
20 :
21 : InputParameters
22 9663 : SideSetsBetweenSubdomainsGenerator::validParams()
23 : {
24 9663 : InputParameters params = SideSetsGeneratorBase::validParams();
25 :
26 57978 : params.renameParam("included_subdomains",
27 : "primary_block",
28 : "The primary set of blocks for which to draw a sideset between");
29 19326 : params.makeParamRequired<std::vector<SubdomainName>>("primary_block");
30 57978 : params.renameParam("included_neighbors",
31 : "paired_block",
32 : "The paired set of blocks for which to draw a sideset between");
33 19326 : params.makeParamRequired<std::vector<SubdomainName>>("paired_block");
34 19326 : params.addClassDescription("MeshGenerator that creates a sideset composed of the nodes located "
35 : "between two or more subdomains.");
36 :
37 : // TODO: Implement each of these in the generate() routine using utilities in SidesetGeneratorBase
38 19326 : params.suppressParameter<bool>("fixed_normal");
39 9663 : params.suppressParameter<bool>("include_only_external_sides");
40 :
41 9663 : return params;
42 0 : }
43 :
44 3298 : SideSetsBetweenSubdomainsGenerator::SideSetsBetweenSubdomainsGenerator(
45 3298 : const InputParameters & parameters)
46 3298 : : SideSetsGeneratorBase(parameters)
47 : {
48 3298 : }
49 :
50 : std::unique_ptr<MeshBase>
51 3150 : SideSetsBetweenSubdomainsGenerator::generate()
52 : {
53 3150 : std::unique_ptr<MeshBase> mesh = std::move(_input);
54 :
55 : // construct the FE object so we can compute normals of faces
56 3150 : setup(*mesh);
57 :
58 : std::vector<boundary_id_type> boundary_ids =
59 3144 : MooseMeshUtils::getBoundaryIDs(*mesh, _boundary_names, true);
60 :
61 : // Get a reference to our BoundaryInfo object for later use
62 3144 : 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 3144 : const processor_id_type my_n_proc = mesh->n_processors();
67 3144 : const processor_id_type my_proc_id = mesh->processor_id();
68 : typedef std::vector<std::pair<dof_id_type, unsigned int>> vec_type;
69 3144 : std::vector<vec_type> queries(my_n_proc);
70 :
71 : // Request to compute normal vectors
72 3144 : const std::vector<Point> & face_normals = _fe_face->get_normals();
73 :
74 309303 : for (const auto & elem : mesh->active_element_ptr_range())
75 : {
76 : // We only need to loop over elements in the primary subdomain
77 612318 : if (_check_subdomains &&
78 306159 : !MeshTraversingUtils::elementSubdomainIdInList(elem, _included_subdomain_ids))
79 155465 : continue;
80 :
81 923464 : for (const auto & side : make_range(elem->n_sides()))
82 : {
83 772770 : 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 772770 : if (neighbor == remote_elem)
89 : {
90 1470 : queries[elem->processor_id()].push_back(std::make_pair(elem->id(), side));
91 : }
92 771300 : else if (neighbor != NULL)
93 : {
94 654937 : _fe_face->reinit(elem, side);
95 : // We'll just use the normal of the first qp
96 654937 : const Point & face_normal = face_normals[0];
97 : // Add the boundaries, if appropriate
98 654937 : if (elemSideSatisfiesRequirements(elem, side, *mesh, _normal, face_normal))
99 : {
100 : // Add the boundaries
101 38900 : if (_replace)
102 0 : boundary_info.remove_side(elem, side);
103 77800 : for (const auto & boundary_id : boundary_ids)
104 38900 : boundary_info.add_side(elem, side, boundary_id);
105 : }
106 : }
107 : }
108 3144 : }
109 :
110 3144 : if (!mesh->is_serial())
111 : {
112 326 : const auto queries_tag = mesh->comm().get_unique_tag(),
113 326 : replies_tag = mesh->comm().get_unique_tag();
114 :
115 978 : std::vector<Parallel::Request> side_requests(my_n_proc - 1), reply_requests(my_n_proc - 1);
116 :
117 : // Make all requests
118 906 : for (const auto & p : make_range(my_n_proc))
119 : {
120 580 : if (p == my_proc_id)
121 326 : continue;
122 :
123 254 : Parallel::Request & request = side_requests[p - (p > my_proc_id)];
124 :
125 254 : mesh->comm().send(p, queries[p], request, queries_tag);
126 : }
127 :
128 : // Reply to all requests
129 326 : std::vector<vec_type> responses(my_n_proc - 1);
130 :
131 580 : for (const auto & p : make_range(uint(1), my_n_proc))
132 : {
133 254 : vec_type query;
134 :
135 254 : Parallel::Status status(mesh->comm().probe(Parallel::any_source, queries_tag));
136 254 : const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
137 :
138 254 : mesh->comm().receive(source_pid, query, queries_tag);
139 :
140 254 : Parallel::Request & request = reply_requests[p - 1];
141 :
142 1724 : for (const auto & q : query)
143 : {
144 1470 : const Elem * elem = mesh->elem_ptr(q.first);
145 1470 : const unsigned int side = q.second;
146 1470 : const Elem * neighbor = elem->neighbor_ptr(side);
147 :
148 1470 : if (neighbor != NULL)
149 : {
150 1470 : _fe_face->reinit(elem, side);
151 : // We'll just use the normal of the first qp
152 1470 : const Point & face_normal = _fe_face->get_normals()[0];
153 : // Add the boundaries, if appropriate
154 1470 : if (elemSideSatisfiesRequirements(elem, side, *mesh, _normal, face_normal))
155 114 : responses[p - 1].push_back(std::make_pair(elem->id(), side));
156 : }
157 : }
158 :
159 254 : mesh->comm().send(source_pid, responses[p - 1], request, replies_tag);
160 254 : }
161 :
162 : // Process all incoming replies
163 580 : for (processor_id_type p = 1; p != my_n_proc; ++p)
164 : {
165 254 : Parallel::Status status(this->comm().probe(Parallel::any_source, replies_tag));
166 254 : const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
167 :
168 254 : vec_type response;
169 :
170 254 : this->comm().receive(source_pid, response, replies_tag);
171 :
172 368 : for (const auto & r : response)
173 : {
174 114 : const Elem * elem = mesh->elem_ptr(r.first);
175 114 : const unsigned int side = r.second;
176 :
177 114 : if (_replace)
178 0 : boundary_info.remove_side(elem, side);
179 228 : for (const auto & boundary_id : boundary_ids)
180 114 : boundary_info.add_side(elem, side, boundary_id);
181 : }
182 254 : }
183 :
184 326 : Parallel::wait(side_requests);
185 326 : Parallel::wait(reply_requests);
186 326 : }
187 :
188 6288 : for (const auto & i : make_range(boundary_ids.size()))
189 3144 : boundary_info.sideset_name(boundary_ids[i]) = _boundary_names[i];
190 :
191 3144 : mesh->unset_is_prepared();
192 6288 : return dynamic_pointer_cast<MeshBase>(mesh);
193 3144 : }
|