Line data Source code
1 : // The libMesh Finite Element Library.
2 : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 :
4 : // This library is free software; you can redistribute it and/or
5 : // modify it under the terms of the GNU Lesser General Public
6 : // License as published by the Free Software Foundation; either
7 : // version 2.1 of the License, or (at your option) any later version.
8 :
9 : // This library is distributed in the hope that it will be useful,
10 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : // Lesser General Public License for more details.
13 :
14 : // You should have received a copy of the GNU Lesser General Public
15 : // License along with this library; if not, write to the Free Software
16 : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 :
18 :
19 :
20 : #ifndef LIBMESH_UNSTRUCTURED_MESH_H
21 : #define LIBMESH_UNSTRUCTURED_MESH_H
22 :
23 : // Local Includes
24 : #include "libmesh/mesh_base.h"
25 :
26 : // C++ Includes
27 : #include <cstddef>
28 :
29 : namespace libMesh
30 : {
31 :
32 : /**
33 : * The \p UnstructuredMesh class is derived from the \p MeshBase class. The
34 : * user will typically want to instantiate and use the
35 : * Mesh class in her applications, which is currently a simple
36 : * derived class of UnstructuredMesh.
37 : * In order to use the adaptive mesh refinement capabilities
38 : * of the library, first instantiate a MeshRefinement object
39 : * with a reference to this class. Then call the appropriate
40 : * refinement functions from that object. To interact with the
41 : * boundary, instantiate a BoundaryMesh with a reference to
42 : * this class, and then use that object's functionality.
43 : *
44 : * \author Roy Stogner
45 : * \date 2007
46 : * \brief Base class for Replicated and Distributed meshes.
47 : */
48 24 : class UnstructuredMesh : public MeshBase
49 : {
50 : public:
51 :
52 : /**
53 : * Constructor. Takes \p dim, the dimension of the mesh.
54 : * The mesh dimension can be changed (and may automatically be
55 : * changed by mesh generation/loading) later.
56 : */
57 : explicit
58 : UnstructuredMesh (const Parallel::Communicator & comm_in,
59 : unsigned char dim=1);
60 :
61 : /**
62 : * UnstructuredMesh uses a defaulted copy constructor.
63 : */
64 : UnstructuredMesh(const UnstructuredMesh &) = default;
65 :
66 : /**
67 : * UnstructuredMesh constructor from arbitrary (e.g. Cartesian
68 : * someday?) meshes
69 : */
70 : UnstructuredMesh(const MeshBase &);
71 :
72 : /**
73 : * Move-constructor deleted in MeshBase.
74 : */
75 : UnstructuredMesh(UnstructuredMesh &&) = delete;
76 :
77 : /**
78 : * Copy assignment is not allowed.
79 : */
80 : UnstructuredMesh & operator= (const UnstructuredMesh &) = delete;
81 :
82 : /**
83 : * Move assignment is allowed, by subclasses who handle
84 : * post_dofobject_moves()
85 : */
86 402 : UnstructuredMesh & operator= (UnstructuredMesh && other_mesh) = default;
87 :
88 : virtual MeshBase & assign(MeshBase && other_mesh) override = 0;
89 :
90 : /**
91 : * Destructor.
92 : */
93 : virtual ~UnstructuredMesh();
94 :
95 : /**
96 : * Reads the file specified by \p name. Attempts to figure out the
97 : * proper method by the file extension. This is now the only
98 : * way to read a mesh. The \p UnstructuredMesh then initializes its data
99 : * structures and is ready for use.
100 : *
101 : * The skip_renumber_nodes_and_elements argument is now deprecated -
102 : * to disallow renumbering, set \p MeshBase::allow_renumbering(false).
103 : *
104 : * Set skip_find_neighbors=true to skip the find-neighbors operation
105 : * during prepare_for_use. This operation isn't always necessary
106 : * and it can be time-consuming, which is why we provide an option to
107 : * skip it.
108 : */
109 : virtual void read (const std::string & name,
110 : void * mesh_data=nullptr,
111 : bool skip_renumber_nodes_and_elements=false,
112 : bool skip_find_neighbors=false) override;
113 : /**
114 : * Write the file specified by \p name. Attempts to figure out the
115 : * proper method by the file extension.
116 : */
117 : virtual void write (const std::string & name) const override;
118 :
119 : /**
120 : * Write to the file specified by \p name. Attempts to figure out the
121 : * proper method by the file extension. Also writes data.
122 : */
123 : void write (const std::string & name,
124 : const std::vector<Number> & values,
125 : const std::vector<std::string> & variable_names) const;
126 :
127 : /**
128 : * Converts a mesh with higher-order
129 : * elements into a mesh with linear elements. For
130 : * example, a mesh consisting of \p Tet10 will be converted
131 : * to a mesh with \p Tet4 etc.
132 : */
133 : virtual void all_first_order () override;
134 :
135 : /**
136 : * Converts a (conforming, non-refined) mesh with linear elements
137 : * into a mesh with second-order elements. For example, a mesh
138 : * consisting of \p Tet4 will be converted to a mesh with \p Tet10
139 : * etc.
140 : *
141 : * \note For some elements like \p Hex8 there exist two higher order
142 : * equivalents, \p Hex20 and \p Hex27. When \p full_ordered is \p
143 : * true (default), then \p Hex27 is built. Otherwise, \p Hex20 is
144 : * built. The same holds obviously for \p Quad4, \p Prism6, etc.
145 : */
146 : virtual void all_second_order_range (const SimpleRange<element_iterator> & range,
147 : const bool full_ordered=true) override;
148 :
149 : /**
150 : * Converts a (conforming, non-refined) mesh with linear elements
151 : * into a mesh with "complete" order elements, i.e. elements which
152 : * can store degrees of freedom on any vertex, edge, or face. For
153 : * example, a mesh consisting of \p Tet4 or \p Tet10 will be
154 : * converted to a mesh with \p Tet14 etc.
155 : */
156 : virtual void all_complete_order_range (const SimpleRange<element_iterator> & range) override;
157 :
158 : /**
159 : * Generates a new mesh containing all the elements which
160 : * are assigned to processor \p pid. This mesh is written
161 : * to the pid_mesh reference which you must create and pass
162 : * to the function.
163 : */
164 : void create_pid_mesh (UnstructuredMesh & pid_mesh,
165 : const processor_id_type pid) const;
166 :
167 : /**
168 : * Constructs a mesh called "new_mesh" from the current mesh by
169 : * iterating over the elements between it and it_end and adding
170 : * them to the new mesh.
171 : */
172 : void create_submesh (UnstructuredMesh & new_mesh,
173 : const const_element_iterator & it,
174 : const const_element_iterator & it_end) const;
175 :
176 : /**
177 : * Stitch \p other_mesh to this mesh so that this mesh is the union of the two meshes.
178 : * \p this_mesh_boundary and \p other_mesh_boundary are used to specify a dim-1 dimensional
179 : * surface on which we seek to merge any "overlapping" nodes, where we use the parameter
180 : * \p tol as a relative tolerance (relative to the smallest edge length on the surfaces
181 : * being stitched) to determine whether or not nodes are overlapping.
182 : * If \p clear_stitched_boundary_ids==true, this function clears boundary_info IDs in this
183 : * mesh associated \p this_mesh_boundary and \p other_mesh_boundary.
184 : * If \p use_binary_search is true, we use an optimized "sort then binary search" algorithm
185 : * for finding matching nodes. Otherwise we use a N^2 algorithm (which can be more reliable
186 : * at dealing with slightly misaligned meshes).
187 : * If \p enforce_all_nodes_match_on_boundaries is true, we throw an error if the number of
188 : * nodes on the specified boundaries don't match the number of nodes that were merged.
189 : * This is a helpful error check in some cases. If this is true, it overrides the value of
190 : * \p merge_boundary_nodes_all_or_nothing.
191 : * If \p skip_find_neighbors is true, a faster stitching method is used, where the lists of
192 : * neighbors for each elements are copied as well and patched, without calling the time-consuming
193 : * find_neighbors() function. This option is now hard-coded to true.
194 : * If \p merge_boundary_nodes_all_or_nothing is true, instead of throwing an error
195 : * like \p enforce_all_nodes_match_on_boundaries, the meshes are combined anyway but coincident
196 : * nodes are not merged into single nodes. This is useful in cases where you are not sure if the
197 : * boundaries are fully conforming beforehand and you want to handle the non-conforming cases
198 : * differently.
199 : *
200 : * Note that the element IDs for elements in the stitched mesh corresponding to "this" mesh
201 : * will be unchanged. The IDs for elements corresponding to \p other_mesh will be incremented
202 : * by this->max_elem_id().
203 : *
204 : * There is no simple a priori relationship between node IDs in "this" mesh
205 : * and other_mesh and node IDs in the stitched mesh because the number of nodes (and hence
206 : * the node IDs) in the stitched mesh depend on how many nodes are stitched.
207 : *
208 : * If \p remap_subdomain_ids is true then we assume that some
209 : * subdomain ids might have been autogenerated, so we remap them as
210 : * necessary, treating subdomain names as the important thing for
211 : * consistency; if we have missing names and cannot infer a
212 : * consistent resolution to an id conflict then we exit with an
213 : * error. If \p remap_subdomain_ids is false then we revert to the
214 : * older libMesh behavior: leave all subdomain ids alone and woe
215 : * unto you if you weren't keeping track of them.
216 : *
217 : * \returns the count of how many nodes were merged between the two meshes.
218 : * This can be zero in the case of no matching nodes or if
219 : * \p merge_boundary_nodes_all_or_nothing was active and relevant.
220 : */
221 : std::size_t stitch_meshes (const MeshBase & other_mesh,
222 : boundary_id_type this_mesh_boundary,
223 : boundary_id_type other_mesh_boundary,
224 : Real tol=TOLERANCE,
225 : bool clear_stitched_boundary_ids=false,
226 : bool verbose=true,
227 : bool use_binary_search=true,
228 : bool enforce_all_nodes_match_on_boundaries=false,
229 : bool merge_boundary_nodes_all_or_nothing=false,
230 : bool remap_subdomain_ids=false);
231 :
232 : /**
233 : * Similar to stitch_meshes, except that we stitch two adjacent surfaces within this mesh.
234 : */
235 : std::size_t stitch_surfaces (boundary_id_type boundary_id_1,
236 : boundary_id_type boundary_id_2,
237 : Real tol=TOLERANCE,
238 : bool clear_stitched_boundary_ids=false,
239 : bool verbose=true,
240 : bool use_binary_search=true,
241 : bool enforce_all_nodes_match_on_boundaries=false,
242 : bool merge_boundary_nodes_all_or_nothing=false);
243 :
244 : /**
245 : * Deep copy of nodes and elements from another mesh object (used by
246 : * subclass copy constructors and by mesh merging operations)
247 : *
248 : * This will not copy most "high level" data in the mesh; that is
249 : * done separately by constructors. An exception is that, if the
250 : * \p other_mesh has element or node extra_integer data, any names
251 : * for that data which do not already exist on \p this mesh are
252 : * added so that all such data can be copied.
253 : *
254 : * If an \p id_remapping map is provided, then element subdomain ids
255 : * in \p other_mesh will be converted using it before adding them to
256 : * \p this mesh.
257 : */
258 : virtual void copy_nodes_and_elements (const MeshBase & other_mesh,
259 : const bool skip_find_neighbors = false,
260 : dof_id_type element_id_offset = 0,
261 : dof_id_type node_id_offset = 0,
262 : unique_id_type unique_id_offset = 0,
263 : std::unordered_map<subdomain_id_type, subdomain_id_type> *
264 : id_remapping = nullptr);
265 :
266 : /**
267 : * Move node and elements from other_mesh to this mesh.
268 : */
269 : virtual void move_nodes_and_elements(MeshBase && other_mesh) = 0;
270 :
271 :
272 : /**
273 : * Other functions from MeshBase requiring re-definition.
274 : */
275 : virtual void find_neighbors (const bool reset_remote_elements = false,
276 : const bool reset_current_list = true) override;
277 :
278 : #ifdef LIBMESH_ENABLE_AMR
279 : /**
280 : * Delete subactive (i.e. children of coarsened) elements.
281 : * This removes all elements descended from currently active
282 : * elements in the mesh.
283 : */
284 : virtual bool contract () override;
285 : #endif // #ifdef LIBMESH_ENABLE_AMR
286 :
287 : private:
288 :
289 : /**
290 : * Helper function for stitch_meshes and stitch_surfaces
291 : * that does the mesh stitching.
292 : */
293 : std::size_t stitching_helper (const MeshBase * other_mesh,
294 : boundary_id_type boundary_id_1,
295 : boundary_id_type boundary_id_2,
296 : Real tol,
297 : bool clear_stitched_boundary_ids,
298 : bool verbose,
299 : bool use_binary_search,
300 : bool enforce_all_nodes_match_on_boundaries,
301 : bool skip_find_neighbors,
302 : bool merge_boundary_nodes_all_or_nothing,
303 : bool remap_subdomain_ids);
304 : };
305 :
306 :
307 : } // namespace libMesh
308 :
309 : #endif // LIBMESH_UNSTRUCTURED_MESH_H
|