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