Skip to content

Added sliding boundary nodes to VariationalMeshSmoother #4216

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 30 commits into
base: devel
Choose a base branch
from

Conversation

pbehne
Copy link
Contributor

@pbehne pbehne commented Jul 17, 2025

Pull Request: Sliding Boundary Constraint Refinement and Dimensional Generalization

Summary

This pull request implements sliding external and subdomain boundary node constraints in the VariationalMeshSmoother
In addition to expanding test coverage to test sliding boundary nodes, 1D and 3D test cases were added to the unit test suite.

Highlights

  • Constraint Framework Refactor

    • Introduced PointConstraint, LineConstraint, and PlaneConstraint structs to represent fixed nodes, nodes constrained to a line, and nodes constrained to a plane
    • Implemented a unified intersect() interface for combining constraints using std::variant
    • Added robust geometric logic for line-line, plane-line, and plane-plane intersections
    • Fallback to PointConstraint if constraints fail to intersect cleanly
  • Sliding Boundary Enhancements

    • Implemented sliding boundary node constraints: previously, boundary and subdomain boundary nodes were fully fixed and not allowed to slide
    • Nodes on external boundaries internal subdomain boundaries now slide along planes and lines unless constrained by geometry
  • Expanded Tests and Validation

    • Added new smoother test cases in 1D and 3D
    • Replaced DistortSquare with DistortHypercube, supporting 1D, 2D, and 3D skewing
    • Boundary nodes are now distorted within the faces and edges they belong to (while preserving corner vertices)
    • Increased complexity of subdomain boundary test to cover more complex cases such a an element having neighbors of multiply different subdomain ids

References

Visualization of testVariationalHexMultipleSubdomains Test

The distorted mesh is on the left, smoothed mesh is on the right.
image

pbehne added 23 commits July 17, 2025 13:09
…re considered for sliding boundary constraints. This helps with adjacent corners nodes in triangular elements.
…ain tests to account for barely-moved subdomain boundary nodes that coincide with the mesh boundary.
…ks better, but both constaints should be conmbined for strict enforcement.
Implemented structs to represent Point, Line, and Plane constraints and
logic to combine (intersect) them. This is more robust than the previous
version and gives the correct constraints for nodes that are both
subdomain boundary nodes and external boundary nodes.
Ref libMesh#4082
Replaced DistortSquare class with the DistortHypercube class, which generalizes dimension and distorts boundary nodes within boundaries instead of leaving them unchanged. The helper also checks all applicable node dimensions instead of receiving the dimension to check as a parameter.

Renamed the `center_distortion_is` helper function to `distortion_is` and updated to check sliding boundary nodes for distortion.
Instead of looking for the boundary between sub_id2 and sub_id2, we now
look for the boundary between sub_id1 and "not sub_id1". This better
handles cases where multiple faces of an element have neighbors of
multiple different subdomain ids.
Copy link
Member

@roystgnr roystgnr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's surprisingly little for me to complain about, for such a large PR.

/// Query whether a point lies on the line.
/// @param p The point in question
/// @return bool indicating whether p lies on the line.
bool contains_point(const PointConstraint &p) const;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any chance we can get away with moving these struct definitions to the .C file?

If they're basically invisible to the rest of the library, then the code here is fine, great way to refactor stuff for internal use.

If not, then we may want to do things like change them into classes encapsulating the members, change TOLERANCE into an (optional, defaulting to TOLERANCE*TOLERANCE or whatever) tol argument on all the functions that rely on comparison to within a tolerance, etc. etc., before we start getting unexpected external uses of APIs we didn't intend to support directly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The determine_constraint and impose_constraint methods of VariationalSmootherConstraint use ConstraintVariant, so it doesn't seem like I can move the Point/Line/PlaneConstraint structs fully into src. I'll go ahead and lock them down.

bool LineConstraint::operator<(const LineConstraint &other) const {
if (!(dir.absolute_fuzzy_equals(other.dir, TOLERANCE)))
return dir < other.dir;
return (dir * r0) < (other.dir * other.r0) - TOLERANCE;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't an antisymmetric relation - is that intentional, to get set etc. to consider nearly-identical lines as identical and drop one of them? If so we should document that.

Copy link
Contributor Author

@pbehne pbehne Jul 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to get set etc. to consider nearly-identical lines as identical and drop one of them?

That was the AI's idea. Good point on the asymmetry. I'm taking that out and putting in a check for fuzzy equality prior to checking less than.

libmesh_error_msg_if(this->is_parallel(o),
"Lines are parallel and do not intersect.");

// Solve for t in the equation p1 + t·d1 = p2 + s·d2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thrilled with the idea of unleashing unicode in comments, and we've got it in a bunch of our contrib/ codes already, but I think this will be the first time it's in libMesh proper, so I want to make sure @jwpeterson is fine with it too.

If we can talk the C++ people into giving us operator× and operator⊗ then I'm stripping the library of cross() and outer_product() calls approximately five minutes after we upgrade.

}
catch (const std::exception & e)
{
// This will catch cases where constraints have no intersection
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two things:

This should probably be libmesh_try/libmesh_catch to compile on builds with exceptions disabled.

How are we going to hit this at all? Every constrant we're creating contains the node itself, right? So at the very least shouldn't we already get something within epsilon of PointConstraint(node) as the intersection?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the next comment regarding the other place I use try/catch. I included it here as well to avoid issues similar to what I explained below.

ConstraintVariant current = *it++;
for (; it != valid_planes.end(); ++it)
{
try
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same "how are we possibly getting an empty constraint" question here

Copy link
Contributor Author

@pbehne pbehne Jul 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great question. I asked myself the same thing when an error was thrown and crashed the program. This is from the testVariationalHexMultipleSubdomains test. First, I think it is work including a picture of the results. I'll update the PR description to do so, and will copy the result here:
image
Consider this view of the z=0 boundary of the distorted mesh:
image
Let's look at subdomain 0 only:
image
Zoom in on this element:
image
The top of this element, which forms part of the subdomain boundary is the union of two different planar surfaces. valid_planes, when determining the constraint for the front left node, ends up holding 3 planes: The two seen in the figure, plus their "average". The average plane does not intersect both of the first two planes, and we end up with the case of a line (the combination of two of the planes) being parallel but not coincident with the third plane. Thus, an exception is thrown and we fall back to fixing the node.

@moosebuild
Copy link

moosebuild commented Jul 18, 2025

Job Coverage, step Generate coverage on cf08059 wanted to post the following:

Coverage

5868ff #4216 cf0805
Total Total +/- New
Rate 64.28% 64.38% +0.10% 90.40%
Hits 75108 75466 +358 358
Misses 41736 41747 +11 38

Diff coverage report

Full coverage report

This comment will be updated on new commits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy