Changes to C0 polyhedron tetrahedralization loops#4359
Changes to C0 polyhedron tetrahedralization loops#4359roystgnr merged 23 commits intolibMesh:develfrom
Conversation
5990f8c to
45a4142
Compare
| if (local_tet_quality[j2] == 0 || local_tet_quality[j2] == far_node) | ||
| { | ||
| nodes_by_geometry.erase(geometry_it); | ||
| has_skipped_adding_tets_and_retriangulating = true; |
There was a problem hiding this comment.
this is the saddest part of this PR. If we could still work with a valid surface mesh it would be a lot safer
unfortunately I seem to need this for every planar 4 node face, we always end up with an empty final tet
There was a problem hiding this comment.
unfortunately I seem to need this for every planar 4 node face, we always end up with an empty final tet
Oh, man - are we getting hit again by the nastiest open secret of tet meshing?
It is not always possible to generate a mesh that has only non-degenerate tets and conforms to an existing triangulation, unless we add at least one "Steiner point" on the volume interior! See this horrifyingly simple example: https://github.com/libMesh/libmesh/blob/devel/tests/geom/elem_test.h#L224-L240 I think this is probably why it's so hard to find a tet mesher that doesn't habitually add interior points and screw up Yaqi's plans: if you know you're sometimes going to need to add points just to make a mesh possible, why hesitate to add points to make a mesh better?
I fear the only completely robust solution for our polyhedra code may be to add a new element (C0IPPolyhedron? I'd hope to come up with a better name...) that adds a single Interior Point, after which getting a nice tetrahedralization becomes trivial.
But in the short run, if you're allowed to swap diagonals then I think you can generally fix the problem with some diagonal swapping.
Is this PR ready for review now that it's no longer marked WIP?
There was a problem hiding this comment.
Happy New Year!
But in the short run, if you're allowed to swap diagonals then I think you can generally fix the problem with some diagonal swapping.
I'm doing this to extrude polygons into prisms. On the sides I have quads. Are you saying I just need to do something to the diagonals of these (quad) polygons? There's no API for it right now right? It just comes from the ordering of the nodes in the polygon?
I fear the only completely robust solution for our polyhedra code may be to add a new element (C0IPPolyhedron? I'd hope to come up with a better name...) that adds a single Interior Point, after which getting a nice tetrahedralization becomes trivial.
Could we just use the centroid as the interior node? Seems like the tetrahedralization is trivial after doing that? (centroid to every triangle)
The thing is that I am doing this for finite volume sims, so I don't really need extra nodes. In fact I am not even sure I need a tetrahedralization (well except to compute the volume)
Is this PR ready for review now that it's no longer marked WIP?
Certainly ready for a look. if you use my MOOSE PR you can look at the current tetrahedralization of the hexagonal prism in exodus. You should see there is a non-matching edge inside, but is it a problem for the FE math? Certainly is a problem for me when converting the polyhedra to tets in some mesh generators
There was a problem hiding this comment.
the only completely robust solution for our polyhedra code may be to add a new element (C0IPPolyhedron
What about a C0PolygonalPrism element? We could always triangulate it as the union of triangular prisms, and we could possibly have custom FE that would be worth including in libmesh? "Tensor product" of the 1D line and the C0Polygon
EDIT: well except if we do the FE math with the tets, the 1D line won't really appear in one direction. We'd have to do something different. Maybe we would not use tets at all? Just triangular prism sub-elements
There was a problem hiding this comment.
Are you saying I just need to do something to the diagonals of these (quad) polygons? There's no API for it right now right? It just comes from the ordering of the nodes in the polygon?
Correct, correct, and correct (at construction time), I'm afraid. If you retriangulate() after construction time then we'll try to come up with a geometrically nicer triangulation, but you can't really control that without changing the geometry, a no-no in this context. The only way to assign the quad diagonals is to make use of knowing the default triangulation and then use that to choose which of the nodes of the quad you assign to node 0 after constructing it.
Could we just use the centroid as the interior node? Seems like the tetrahedralization is trivial after doing that?
In our mesh generators IMHO the vertex_average would be the best choice; the tetrahedralization for a convex polyhedron is trivial for any interior point choice.
In fact I am not even sure I need a tetrahedralization (well except to compute the volume)
Not directly, but we do use it in the Lagrange shape functions, so anything trying to compute a mapping will scream if it's not there. We might be able to get by without it thanks to having thrown up our hands at the idea of figuring out what a "master" element looks like for an arbitrary polyhedron, though...
What about a C0PolygonalPrism element?
Not crazy, but I think the IP polyhedron will end up being less new work.
There was a problem hiding this comment.
Pinging @jwpeterson since he's had opinions on these names in the original PRs.
Fine with C0PolyhedronP1Plus
There was a problem hiding this comment.
Ok I ll work on this. Don't think we have funding for this anymore though
I m planning to make it inherit from C0Polyedron. That makes sense right, adding interior points in the derived class
There was a problem hiding this comment.
or do you prefer an intermediate base class? C0PolyhedronBase and two derived children, the regular one and the P1Plus
There was a problem hiding this comment.
I have "Polyhedral/tetrahedral mesh enhancements" in my notes under "FY25-26 NEAMS Tasks"/"Named M2 Tasks", with "Polyhedra: very high priority" even, but I'll ping @lindsayad in case my meeting stenography skills failed me. The biggest goal there (IMHO - no notes on that) was I/O support, but if even a simple extrusion is giving us tetrahedralization problems then we probably can't hope to start reading arbitrary files until we've fixed that.
We probably want a C0PolyhedronBase here.
There was a problem hiding this comment.
Your notes are spot-on and perfectly timed with my slack NEAMS-MP posts today!
3f652d6 to
313097a
Compare
| // with no additional interior point | ||
| try | ||
| { | ||
| // In 3D, this will require nested loops: an outer loop to remove |
There was a problem hiding this comment.
prefer as is or with an indentation (and a big diff)
There was a problem hiding this comment.
comment goes line 400 now
|
Going to try unit tests on the FE / quadratures. |
156336b to
105e26c
Compare
c8b481b to
827a736
Compare
| @@ -93,6 +93,10 @@ Polyhedron::Polyhedron (const std::vector<std::shared_ptr<Polygon>> & sides, | |||
| } | |||
| } | |||
|
|
|||
| // Plan room for an extra node so we don't invalidate this->_nodes when we add to | |||
| // nodelinks_data in the derived class | |||
| _nodelinks_data.reserve(_nodelinks_data.size() + 1); | |||
There was a problem hiding this comment.
could also modify the derived class but this is cheaper?
GiudGiud
left a comment
There was a problem hiding this comment.
This grew but I think it's ready for a look now!
|
looks like we are not consistently getting the midnode with the cube poly. I ll try a few diagonal changes to see if it stabilizes on civet |
Add another error to catch for reverting to the mid-node creating algorithm
… instead in the generic projector
roystgnr
left a comment
There was a problem hiding this comment.
This looks practically ready.
| // Treat polyhedron midnode as a vertex | ||
| // NOTE: if we start having edge or side nodes on polyhedra, we need to use that +1 offset | ||
| // in the edge and side nodes code as well! | ||
| for (unsigned int v=0; v != n_vertices + has_poly_midnode; ++v) |
There was a problem hiding this comment.
Let's switch to a make_range() here? I think compilers are smart enough to realize we're not doing any const_cast tricks on n_vertices or has_poly_midnode and so we don't need to do that addition on every loop iteration, but nicer to be certain.
There was a problem hiding this comment.
Hmm... more importantly: treating the midnode as a vertex means we're going to be interpolating onto it regardless of FEType. That's actually what we want to do anyway for LAGRANGE variables, and the test of FEInterface::n_dofs_at_node(fe_type, elem, 0, add_p_level)) means we should be fine for MONOMIAL and XYZ too, but I could see this biting us in a very subtle way when we try to add higher order or more exotic continuous FE options. Could we add something like libmesh_assert(!has_poly_midnode || fe_type.family == LAGRANGE) above this loop?
| for (unsigned int v=0; v != n_vertices; ++v) | ||
| // Treat polyhedron midnode as a vertex | ||
| // NOTE: if we start having edge or side nodes on polyhedra, we need to use that +1 offset | ||
| // in the edge and side nodes code as well! |
There was a problem hiding this comment.
IMHO we'll want to number the midnode last (as we do with e.g. Quad9 and Hex27), but that's speculative; this comment is fine as-is and we definitely want some reminder of the issue.
| #include "libmesh/libmesh_common.h" | ||
| #include "libmesh/cell_polyhedron.h" | ||
| #include "libmesh/enum_order.h" | ||
| #include "libmesh/node.h" |
There was a problem hiding this comment.
Can we get away with a forward declaration of Node? No big deal if not.
There was a problem hiding this comment.
yeah we can. changed
| bool C0Polyhedron::is_vertex(const unsigned int i) const | ||
| { | ||
| libmesh_assert (i < this->n_nodes()); | ||
| libmesh_assert_less (i, this->n_vertices() + _has_mid_elem_node); |
There was a problem hiding this comment.
libmesh_assert_less (i, this->n_nodes()) should still work here, right?
| * | ||
| * Each subelement here is a tetrahedron | ||
| */ | ||
| virtual std::array<int, 4> subelement_sides_to_poly_sides(unsigned int i) const; |
There was a problem hiding this comment.
A little more doxygen here? I assume returnval[j] of subelement_sides_to_poly_sides(i) is the polyhedron-local index of the subtet-local index j of subtet i, but we should spell that out.
| std::array<int, 4> sides = {invalid_int, invalid_int, invalid_int, invalid_int}; | ||
| libmesh_assert(tri_i < this->n_subelements()); | ||
| const auto & tet_nodes = _triangulation[tri_i]; | ||
| for (const auto poly_side : make_range(n_sides())) |
There was a problem hiding this comment.
At some point we should document which of the "you'd think it'd be O(1)" polyhedron APIs is actually O(n_sides()), but I'm pretty sure I committed this sin before you did and we don't need to fix it in this PR.
| // This might not succeed, not every surface triangulation gives a tetrahedralization | ||
| // with no additional interior point | ||
| // But if it succeeds, it uses less tetrahedra to cut the polyhedron | ||
| try |
There was a problem hiding this comment.
We probably need something to fix --disable-exceptions builds; I'll add that recipe.
We could just do libmesh_try/libmesh_catch ... which basically ifdef's out the catch block, and gives you code that still works, but only in the cases where no exceptions are thrown.
Perhaps here we should be (manually) ifdef'ing out the try block instead? If a user doesn't have exceptions disabled for some reason, we just put a midpoint node in every poly so we always get a valid (albeit often less efficient) element.
There was a problem hiding this comment.
ok used that last solution
- add an assert in generic projector to avoid getting surprised with the midnode later - when disabling exceptions, always create the midnode as midnode need detection relies on exceptions - try a forward declare for Node
|
I can't tell for sure whether the |
|
Double-free in the |
|
I think the tests might be hardcoded for a given configuration. I ll amend that |
47ea3a9 to
8262bb7
Compare
based on top of the hexagon tiling PR, ignore that content for now! It's in another PR
see companion PR in MOOSE creating a bunch of polys with exodus viz of the tets:
idaholab/moose#32141