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