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 : #pragma once
11 :
12 : #include "libmesh/replicated_mesh.h"
13 : #include "libmesh/boundary_info.h"
14 :
15 : #include "MooseUtils.h"
16 : #include "MooseTypes.h"
17 : #include "FaceInfo.h"
18 :
19 : namespace MooseMeshUtils
20 : {
21 :
22 : /**
23 : * Merges the boundary IDs of boundaries that have the same names
24 : * but different IDs.
25 : * @param mesh The input mesh whose boundaries we will modify
26 : */
27 : void mergeBoundaryIDsWithSameName(MeshBase & mesh);
28 :
29 : /**
30 : * Changes the old boundary ID to a new ID in the mesh
31 : *
32 : * @param mesh the mesh
33 : * @param old_id the old boundary id
34 : * @param new_id the new boundary id
35 : * @param delete_prev whether to delete the previous boundary id from the mesh
36 : */
37 : void changeBoundaryId(MeshBase & mesh,
38 : const libMesh::boundary_id_type old_id,
39 : const libMesh::boundary_id_type new_id,
40 : bool delete_prev);
41 :
42 : /**
43 : * Changes the old subdomain ID to a new ID in the mesh
44 : *
45 : * @param mesh the mesh
46 : * @param old_id the old subdomain id
47 : * @param new_id the new subdomain id
48 : */
49 : void
50 : changeSubdomainId(MeshBase & mesh, const subdomain_id_type old_id, const subdomain_id_type new_id);
51 :
52 : /**
53 : * Gets the boundary IDs with their names.
54 : *
55 : * The ordering of the returned boundary ID vector matches the vector of the boundary
56 : * names in \p boundary_name.
57 : * When a boundary name is not available in the mesh, if \p generate_unknown is true
58 : * a non-existant boundary ID will be returned, otherwise a BoundaryInfo::invalid_id
59 : * will be returned.
60 : */
61 : std::vector<BoundaryID> getBoundaryIDs(const libMesh::MeshBase & mesh,
62 : const std::vector<BoundaryName> & boundary_name,
63 : bool generate_unknown,
64 : const std::set<BoundaryID> & mesh_boundary_ids);
65 :
66 : /**
67 : * Gets the boundary IDs with their names.
68 : *
69 : * The ordering of the returned boundary ID vector matches the vector of the boundary
70 : * names in \p boundary_name.
71 : * When a boundary name is not available in the mesh, if \p generate_unknown is true
72 : * a non-existant boundary ID will be returned, otherwise a BoundaryInfo::invalid_id
73 : * will be returned.
74 : */
75 : std::vector<BoundaryID> getBoundaryIDs(const libMesh::MeshBase & mesh,
76 : const std::vector<BoundaryName> & boundary_name,
77 : bool generate_unknown);
78 :
79 : /**
80 : * Gets the boundary IDs into a set with their names.
81 : *
82 : * Because libMesh allows the same boundary to have multiple different boundary names,
83 : * the size of the returned boundary ID set may be smaller than the size of the bounndary
84 : * name vector.
85 : * When a boundary name is not available in the mesh, if \p generate_unknown is true
86 : * a non-existant boundary ID will be returned, otherwise a BoundaryInfo::invalid_id
87 : * will be returned.
88 : */
89 : std::set<BoundaryID> getBoundaryIDSet(const libMesh::MeshBase & mesh,
90 : const std::vector<BoundaryName> & boundary_name,
91 : bool generate_unknown);
92 :
93 : /**
94 : * Gets the boundary ID associated with the given BoundaryName.
95 : *
96 : * This is needed because the BoundaryName can be either an ID or a name.
97 : * If it is a name, the mesh is queried for the ID associated with said name.
98 : */
99 : BoundaryID getBoundaryID(const BoundaryName & boundary_name, const MeshBase & mesh);
100 :
101 : /**
102 : * Gets the subdomain ID associated with the given SubdomainName.
103 : *
104 : * This is needed because the SubdomainName can be either an ID or a name.
105 : * If it is a name, the mesh is queried for the ID associated with said name.
106 : */
107 : SubdomainID getSubdomainID(const SubdomainName & subdomain_name, const MeshBase & mesh);
108 :
109 : /**
110 : * Get the associated subdomainIDs for the subdomain names that are passed in.
111 : *
112 : * @param mesh The mesh
113 : * @param subdomain_name The names of the subdomains
114 : * @return The subdomain ids from the passed subdomain names.
115 : */
116 : std::vector<subdomain_id_type> getSubdomainIDs(const libMesh::MeshBase & mesh,
117 : const std::vector<SubdomainName> & subdomain_name);
118 : std::set<subdomain_id_type> getSubdomainIDs(const libMesh::MeshBase & mesh,
119 : const std::set<SubdomainName> & subdomain_name);
120 :
121 : /**
122 : * Calculates the centroid of a MeshBase.
123 : * @param mesh input mesh whose centroid needs to be calculated
124 : * @return a Point data containing the mesh centroid
125 : */
126 : Point meshCentroidCalculator(const MeshBase & mesh);
127 :
128 : /**
129 : * compute a coordinate transformation factor
130 : * @param point The libMesh \p Point in space where we are evaluating the factor
131 : * @param factor The output of this function. Would be 1 for cartesian coordinate systems, 2*pi*r
132 : * for cylindrical coordinate systems, and 4*pi*r^2 for spherical coordinate systems
133 : * @param coord_type The coordinate system type, e.g. cartesian (COORD_XYZ), cylindrical (COORD_RZ),
134 : * or spherical (COORD_RSPHERICAL)
135 : * @param rz_radial_coord The index at which to index \p point for the radial coordinate when in a
136 : * cylindrical coordinate system
137 : */
138 : template <typename P, typename C>
139 : void
140 1922743983 : coordTransformFactor(const P & point,
141 : C & factor,
142 : const Moose::CoordinateSystemType coord_type,
143 : const unsigned int rz_radial_coord = libMesh::invalid_uint)
144 : {
145 1922743983 : switch (coord_type)
146 : {
147 1919771576 : case Moose::COORD_XYZ:
148 1919771576 : factor = 1.0;
149 1919771576 : break;
150 2934621 : case Moose::COORD_RZ:
151 : {
152 : mooseAssert(rz_radial_coord != libMesh::invalid_uint,
153 : "Must pass in a valid rz radial coordinate");
154 2934621 : factor = 2 * M_PI * point(rz_radial_coord);
155 2934621 : break;
156 : }
157 37786 : case Moose::COORD_RSPHERICAL:
158 37786 : factor = 4 * M_PI * point(0) * point(0);
159 37786 : break;
160 0 : default:
161 0 : mooseError("Unknown coordinate system");
162 : }
163 1922743983 : }
164 :
165 : /**
166 : * Computes the distance to a general axis
167 : *
168 : * @param[in] point Point for which to compute distance from axis
169 : * @param[in] origin Axis starting point
170 : * @param[in] direction Axis direction
171 : */
172 : template <typename P, typename C>
173 : C
174 1065929 : computeDistanceToAxis(const P & point, const Point & origin, const RealVectorValue & direction)
175 : {
176 1065929 : return (point - origin).cross(direction).norm();
177 : }
178 :
179 : /**
180 : * Computes a coordinate transformation factor for a general axisymmetric axis
181 : *
182 : * @param[in] point The libMesh \p Point in space where we are evaluating the factor
183 : * @param[in] axis The pair of values defining the general axisymmetric axis.
184 : * Respectively, the values are the axis starting point and direction.
185 : * @param[out] factor The coordinate transformation factor
186 : */
187 : template <typename P, typename C>
188 : void
189 1065929 : coordTransformFactorRZGeneral(const P & point,
190 : const std::pair<Point, RealVectorValue> & axis,
191 : C & factor)
192 : {
193 1065929 : factor = 2 * M_PI * computeDistanceToAxis<P, C>(point, axis.first, axis.second);
194 1065929 : }
195 :
196 : inline void
197 : computeFiniteVolumeCoords(FaceInfo & fi,
198 : const Moose::CoordinateSystemType coord_type,
199 : const unsigned int rz_radial_coord = libMesh::invalid_uint)
200 : {
201 : coordTransformFactor(fi.faceCentroid(), fi.faceCoord(), coord_type, rz_radial_coord);
202 : }
203 :
204 : /**
205 : * Crate a new set of element-wise IDs by finding unique combinations of existing extra ID values
206 : *
207 : * This function finds the unique combinations by recursively calling itself for extra ID inputs. In
208 : * the recursive calling, the new unique combinations is determined by combining the extra ID value
209 : * of current level and the unique combination determined in the previous level in recursion. In the
210 : * lowest level of recursion, the base combination is set by the unique ID values of the
211 : * corresponding extra ID.
212 : *
213 : * @param mesh input mesh
214 : * @param block_ids block ids
215 : * @param extra_ids extra ids
216 : * @return map of element id to new extra id
217 : **/
218 : std::unordered_map<dof_id_type, dof_id_type>
219 : getExtraIDUniqueCombinationMap(const MeshBase & mesh,
220 : const std::set<SubdomainID> & block_ids,
221 : std::vector<ExtraElementIDName> extra_ids);
222 :
223 : /**
224 : * Decides whether all the Points of a vector of Points are in a plane that is defined by a normal
225 : * vector and an inplane Point
226 : * @param vec_pts vector of points to be examined
227 : * @param plane_nvec normal vector of the plane
228 : * @param fixed_pt a Point in the plane
229 : * @return whether all the Points are in the given plane
230 : */
231 : bool isCoPlanar(const std::vector<Point> vec_pts, const Point plane_nvec, const Point fixed_pt);
232 :
233 : /**
234 : * Decides whether all the Points of a vector of Points are in a plane with a given normal vector
235 : * @param vec_pts vector of points to be examined
236 : * @param plane_nvec normal vector of the plane
237 : * @return whether all the Points are in the same plane with the given normal vector
238 : */
239 : bool isCoPlanar(const std::vector<Point> vec_pts, const Point plane_nvec);
240 :
241 : /**
242 : * Decides whether all the Points of a vector of Points are coplanar
243 : * @param vec_pts vector of points to be examined
244 : * @return whether all the Points are in a same plane
245 : */
246 : bool isCoPlanar(const std::vector<Point> vec_pts);
247 :
248 : /**
249 : * Checks input mesh and returns max(block ID) + 1, which represents
250 : * a block ID that is not currently in use in the mesh
251 : * @param input mesh over which to compute the next free block id
252 : */
253 : SubdomainID getNextFreeSubdomainID(MeshBase & input_mesh);
254 :
255 : /**
256 : * Checks input mesh and returns the largest boundary ID in the mesh plus one, which is
257 : * a boundary ID in the mesh that is not currently in use
258 : * @param input mesh over which to compute the next free boundary ID
259 : */
260 :
261 : BoundaryID getNextFreeBoundaryID(MeshBase & input_mesh);
262 : /**
263 : * Whether a particular subdomain ID exists in the mesh
264 : * @param input mesh over which to determine subdomain IDs
265 : * @param subdomain ID
266 : */
267 : bool hasSubdomainID(const MeshBase & input_mesh, const SubdomainID & id);
268 :
269 : /**
270 : * Whether a particular subdomain name exists in the mesh
271 : * @param input mesh over which to determine subdomain names
272 : * @param subdomain name
273 : */
274 : bool hasSubdomainName(const MeshBase & input_mesh, const SubdomainName & name);
275 :
276 : /**
277 : * Whether a particular boundary ID exists in the mesh
278 : * @param input mesh over which to determine boundary IDs
279 : * @param boundary ID
280 : */
281 : bool hasBoundaryID(const MeshBase & input_mesh, const BoundaryID id);
282 :
283 : /**
284 : * Whether a particular boundary name exists in the mesh
285 : * @param input mesh over which to determine boundary names
286 : * @param boundary name
287 : */
288 : bool hasBoundaryName(const MeshBase & input_mesh, const BoundaryName & name);
289 :
290 : /**
291 : * Convert a list of sides in the form of a vector of pairs of node ids into a list of ordered nodes
292 : * based on connectivity
293 : * @param node_assm vector of pairs of node ids that represent the sides
294 : * @param elem_id_list vector of element ids that represent the elements that contain the sides
295 : * @param midpoint_node_list vector of node ids that represent the midpoints of the sides for
296 : * quadratic sides
297 : * @param ordered_node_list vector of node ids that represent the ordered nodes
298 : * @param ordered_elem_id_list vector of element corresponding to the ordered nodes
299 : * */
300 : void makeOrderedNodeList(std::vector<std::pair<dof_id_type, dof_id_type>> & node_assm,
301 : std::vector<dof_id_type> & elem_id_list,
302 : std::vector<dof_id_type> & midpoint_node_list,
303 : std::vector<dof_id_type> & ordered_node_list,
304 : std::vector<dof_id_type> & ordered_elem_id_list);
305 :
306 : /**
307 : * Convert a list of sides in the form of a vector of pairs of node ids into a list of ordered nodes
308 : * based on connectivity
309 : * @param node_assm vector of pairs of node ids that represent the sides
310 : * @param elem_id_list vector of element ids that represent the elements that contain the sides
311 : * @param ordered_node_list vector of node ids that represent the ordered nodes
312 : * @param ordered_elem_id_list vector of element corresponding to the ordered nodes
313 : * */
314 : void makeOrderedNodeList(std::vector<std::pair<dof_id_type, dof_id_type>> & node_assm,
315 : std::vector<dof_id_type> & elem_id_list,
316 : std::vector<dof_id_type> & ordered_node_list,
317 : std::vector<dof_id_type> & ordered_elem_id_list);
318 :
319 : /**
320 : * Converts a given name (BoundaryName or SubdomainName) that is known to only contain digits into a
321 : * corresponding ID (BoundaryID or SubdomainID) and performs bounds checking to ensure that overflow
322 : * doesn't happen.
323 : * @param name Name that is to be converted into an ID.
324 : * @return ID type corresponding to the type of name.
325 : */
326 : template <typename T, typename Q>
327 : Q
328 476081 : getIDFromName(const T & name)
329 : {
330 476081 : if (!MooseUtils::isDigits(name))
331 0 : mooseError(
332 : "'name' ", name, " should only contain digits that can be converted to a numerical type.");
333 476081 : long long id = std::stoll(name);
334 476081 : Q id_Q = Q(id);
335 476081 : if (id < std::numeric_limits<Q>::min() || id > std::numeric_limits<Q>::max())
336 4 : mooseError(MooseUtils::prettyCppType<T>(&name),
337 : " ",
338 : name,
339 : " is not within the numeric limits of the expected ID type ",
340 : MooseUtils::prettyCppType<Q>(&id_Q),
341 : ".");
342 :
343 476077 : return id_Q;
344 : }
345 :
346 : /**
347 : * Swap two nodes within an element
348 : * @param elem element whose nodes need to be swapped
349 : * @param nd1 index of the first node to be swapped
350 : * @param nd2 index of the second node to be swapped
351 : */
352 : void swapNodesInElem(Elem & elem, const unsigned int nd1, const unsigned int nd2);
353 :
354 : /**
355 : * Reprocess the swap related input parameters to make pairs out of them to ease further processing
356 : * @param class_name name of the mesh generator class used for exception messages
357 : * @param id_name name of the parameter to be swapped used for exception messages
358 : * @param id_swaps vector of vectors of the ids to be swapped
359 : * @param id_swap_pairs vector of maps of the swapped pairs
360 : * @param row_index_shift shift to be applied to the row index in the exception messages (useful
361 : * when this method is utilized to process a fraction of a long vector)
362 : */
363 : template <typename T>
364 : void
365 418 : idSwapParametersProcessor(const std::string & class_name,
366 : const std::string & id_name,
367 : const std::vector<std::vector<T>> & id_swaps,
368 : std::vector<std::unordered_map<T, T>> & id_swap_pairs,
369 : const unsigned int row_index_shift = 0)
370 : {
371 418 : id_swap_pairs.resize(id_swaps.size());
372 850 : for (const auto i : index_range(id_swaps))
373 : {
374 432 : const auto & swaps = id_swaps[i];
375 432 : auto & swap_pairs = id_swap_pairs[i];
376 :
377 432 : if (swaps.size() % 2)
378 0 : throw MooseException("Row ",
379 0 : row_index_shift + i + 1,
380 : " of ",
381 : id_name,
382 : " in ",
383 : class_name,
384 : " does not contain an even number of entries! Num entries: ",
385 0 : swaps.size());
386 :
387 432 : swap_pairs.reserve(swaps.size() / 2);
388 1178 : for (unsigned int j = 0; j < swaps.size(); j += 2)
389 746 : swap_pairs[swaps[j]] = swaps[j + 1];
390 : }
391 418 : }
392 :
393 : /**
394 : * Reprocess the elem_integers_swaps into maps so they are easier to use
395 : * @param class_name name of the mesh generator class used for exception messages
396 : * @param num_sections number of sections in the mesh
397 : * @param num_integers number of extra element integers in the mesh
398 : * @param elem_integers_swaps vector of vectors of vectors of extra element ids to be swapped
399 : * @param elem_integers_swap_pairs vector of maps of the swapped pairs
400 : */
401 : void extraElemIntegerSwapParametersProcessor(
402 : const std::string & class_name,
403 : const unsigned int num_sections,
404 : const unsigned int num_integers,
405 : const std::vector<std::vector<std::vector<dof_id_type>>> & elem_integers_swaps,
406 : std::vector<std::unordered_map<dof_id_type, dof_id_type>> & elem_integers_swap_pairs);
407 :
408 : /**
409 : * Build a lower-dimensional mesh from a boundary of an input mesh
410 : * Note: The lower-dimensional mesh will only have one subdomain and one boundary.
411 : * Error will be thrown if the mesh does not have the boundary.
412 : * This function works only with replicated mesh, for similar functionality with
413 : * distributed meshes, please refer to LowerDBlockFromSidesetGenerator generator.
414 : * @param input_mesh The input mesh
415 : * @param boundary_id The boundary id
416 : */
417 : std::unique_ptr<ReplicatedMesh> buildBoundaryMesh(const ReplicatedMesh & input_mesh,
418 : const boundary_id_type boundary_id);
419 : }
|