18 #include "libmesh/libmesh_config.h" 19 #ifdef LIBMESH_HAVE_NETGEN 26 #include "libmesh/mesh_netgen_interface.h" 28 #include "libmesh/boundary_info.h" 29 #include "libmesh/cell_tet4.h" 30 #include "libmesh/face_tri3.h" 31 #include "libmesh/libmesh_logging.h" 32 #include "libmesh/mesh_communication.h" 33 #include "libmesh/threads.h" 34 #include "libmesh/unstructured_mesh.h" 35 #include "libmesh/utility.h" 38 #include "netgen/nglib/nglib.h" 48 _ngmesh = nglib::Ng_NewMesh();
52 nglib::Ng_DeleteMesh(_ngmesh);
56 nglib::Ng_DeleteMesh(_ngmesh);
57 _ngmesh = nglib::Ng_NewMesh();
60 operator nglib::Ng_Mesh* () {
65 nglib::Ng_Mesh * _ngmesh;
85 using namespace nglib;
87 LOG_SCOPE(
"triangulate()",
"NetGenMeshInterface");
96 std::vector<MeshSerializer> hole_serializers;
98 for (std::unique_ptr<UnstructuredMesh> & hole : *
_holes)
105 "Found hole with bounding box " << hole_bb <<
106 "\nextending outside of mesh bounding box " << mesh_bb);
108 hole_serializers.emplace_back
125 hole_serializers.clear();
136 "NetGen failed to generate any tetrahedra");
142 Ng_Meshing_Parameters params;
148 params.uselocalh =
false;
150 params.elementsperedge = 1;
151 params.elementspercurve = 1;
152 params.closeedgeenable =
false;
153 params.closeedgefact = 0;
154 params.minedgelenenable =
false;
155 params.minedgelen = 0;
165 params.maxh = std::numeric_limits<double>::max();
171 params.optsteps_3d = 0;
178 std::unordered_map<int, dof_id_type> ng_to_libmesh_id;
180 auto handle_ng_result = [](Ng_Result result) {
181 static const std::vector<std::string> result_types =
182 {
"Netgen error",
"Netgen success",
"Netgen surface input error",
183 "Netgen volume failure",
"Netgen STL input error",
184 "Netgen surface failure",
"Netgen file not found"};
187 std::size_t(result+1) < result_types.size())
189 (result,
"Ng_GenerateVolumeMesh failed: " <<
190 result_types[result+1]);
193 (
"Ng_GenerateVolumeMesh failed with an unknown error code");
200 std::unordered_map<std::array<dof_id_type,3>,
204 (std::array<dof_id_type,3> & array,
209 while (array[i] < n_id)
212 std::swap(array[i++], n_id);
215 WrappedNgMesh ngmesh;
224 auto create_surface_component =
225 [
this, &ng_id, &ng_to_libmesh_id, &ngmesh, &side_boundary_id, &insert_id]
229 LOG_SCOPE(
"create_surface_component()",
"NetGenMeshInterface");
236 std::unordered_map<dof_id_type, int> libmesh_to_ng_id;
240 std::unordered_map<dof_id_type, dof_id_type> hole_to_main_mesh_id;
244 std::array<double, 3> point_val;
247 std::array<int, 3> elem_nodes;
249 for (
const auto * elem : srcmesh.element_ptr_range())
253 if (elem->type() ==
TRI6 ||
254 elem->type() ==
TRI7)
255 libmesh_not_implemented_msg
256 (
"Netgen tetrahedralization currently only supports TRI3 boundaries");
259 if (elem->type() !=
TRI3)
262 std::array<dof_id_type,3> sorted_ids =
271 auto & elem_node = hole_mesh ? elem_nodes[2-ni] : elem_nodes[ni];
273 const Node & n = elem->node_ref(ni);
277 if (
auto it = hole_to_main_mesh_id.find(n_id);
278 it != hole_to_main_mesh_id.end())
286 hole_to_main_mesh_id.emplace(n_id, n_new_id);
291 if (
auto it = libmesh_to_ng_id.find(n_id);
292 it != libmesh_to_ng_id.end())
294 const int existing_ng_id = it->second;
295 elem_node = existing_ng_id;
300 point_val[i] =
double(n(i));
302 Ng_AddPoint(ngmesh, point_val.data());
304 ng_to_libmesh_id[ng_id] = n_id;
305 libmesh_to_ng_id[n_id] = ng_id;
310 insert_id(sorted_ids, n_id);
313 side_boundary_id[sorted_ids] = bcid;
315 Ng_AddSurfaceElement(ngmesh, NG_TRIG, elem_nodes.data());
322 create_surface_component(this->
_mesh,
false, bcid);
325 for (
const std::unique_ptr<UnstructuredMesh> & h : *
_holes)
326 create_surface_component(*h,
true, ++bcid);
330 LOG_SCOPE(
"Ng_GenerateVolumeMesh()",
"NetGenMeshInterface");
332 auto result = Ng_GenerateVolumeMesh(ngmesh, ¶ms);
333 handle_ng_result(result);
336 const int n_elem = Ng_GetNE(ngmesh);
347 libmesh_error_msg (
"NetGen failed to generate any tetrahedra");
354 if (n_points != old_nodes)
356 std::array<double, 3> point_val;
362 "NetGen output " << n_points <<
363 " points when we gave it " <<
364 old_nodes <<
" and disabled refinement\n" <<
365 "If new interior points are acceptable in your mesh, please set\n" <<
366 "a non-zero desired_volume to indicate that. If new interior\n" <<
367 "points are not acceptable in your mesh, you may need a different\n" <<
368 "(non-advancing-front?) mesh generator." << std::endl;
372 for (
auto i :
make_range(old_nodes, n_points))
375 Ng_GetPoint (ngmesh, i+1, point_val.data());
376 const Point p(point_val[0], point_val[1], point_val[2]);
379 ng_to_libmesh_id[i+1] = n_new_id;
383 for (
auto * elem : this->
_mesh.element_ptr_range())
395 Ng_Volume_Element_Type ngtype =
396 Ng_GetVolumeElement(ngmesh, i+1, ngnodes);
406 libmesh_map_find(ng_to_libmesh_id, ngnodes[n]);
415 std::array<dof_id_type,3> sorted_ids =
419 std::vector<unsigned int> nos = elem->nodes_on_side(s);
421 insert_id(sorted_ids, elem->node_id(n));
423 if (
auto it = side_boundary_id.find(sorted_ids);
424 it != side_boundary_id.end())
431 hole_serializers.clear();
445 #endif // #ifdef LIBMESH_HAVE_NETGEN NetGenMeshInterface(UnstructuredMesh &mesh)
Constructor.
std::unique_ptr< std::vector< std::unique_ptr< UnstructuredMesh > > > _holes
A pointer to a vector of meshes each defining a hole.
A Node is like a Point, but with more information.
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
Prepare a newly created (or read) mesh for use.
void process_hull_integrity_result(const std::set< SurfaceIntegrity > &result) const
This function prints an informative message and throws an exception based on the output of the check_...
virtual void triangulate() override
Method invokes NetGen library to compute a tetrahedralization.
The libMesh namespace provides an interface to certain functionality in the library.
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
Add a new Node at Point p to the end of the vertex array, with processor_id procid.
void libmesh_ignore(const Args &...)
virtual void delete_elem(Elem *e)=0
Removes element e from the mesh.
This is the MeshCommunication class.
static constexpr dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
The UnstructuredMesh class is derived from the MeshBase class.
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
The BoundaryInfo class contains information relevant to boundary conditions including storing faces...
static BoundingBox volume_to_surface_mesh(UnstructuredMesh &mesh)
Remove volume elements from the given mesh, after converting their outer boundary faces to surface el...
virtual void clear()
Deletes all the element and node data that is currently stored.
Defines a Cartesian bounding box by the two corner extremum.
Real _desired_volume
The desired volume for the elements in the resulting mesh.
static std::unique_ptr< Elem > build_with_id(const ElemType type, dof_id_type id)
Calls the build() method above with a nullptr parent, and additionally sets the newly-created Elem's ...
void broadcast(MeshBase &) const
Finds all the processors that may contain elements that neighbor my elements.
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
Add side side of element number elem with boundary id id to the boundary information data structure...
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
std::set< SurfaceIntegrity > improve_hull_integrity()
This function checks the integrity of the current set of elements in the Mesh, and corrects what it c...
bool contains(const BoundingBox &) const
virtual dof_id_type n_elem() const =0
virtual const Node * node_ptr(const dof_id_type i) const =0
processor_id_type processor_id() const
UnstructuredMesh & _mesh
Local reference to the mesh we are working with.
A Point defines a location in LIBMESH_DIM dimensional Real space.
virtual dof_id_type n_nodes() const =0
Class MeshTetInterface provides an abstract interface for tetrahedralization of meshes by subclasses...