Skip to content

Conversation

@schnellerhase
Copy link
Collaborator

@schnellerhase schnellerhase commented Nov 7, 2025

Introduces the orientation function $o \in DG(\Omega)_0$ which encodes the orientation of the edge relative to the local storage order.

$$ o(e) = \begin{cases} 1, & \text{edge orientation in mesh aligns with direction in directed graph} \\ -1, & \text{else}. \end{cases} $$

A unit tangent oriented in the direction of the directed graph is given by

$$ \xi = o \frac{J}{||J||} $$

where

$$ J = \frac{\partial x}{\partial X} \in \mathbb{R}^{3 \times 1} $$

the Jacobian, i.e. ufl.Jacobian(mesh).

In general for a deformed configuration $x + u(x)$, a tangent would still be given by $\xi$ with the altered Jacobian of the configuration

$$ \hat{J} = \frac{\partial (x + u(x))}{\partial X} $$

Implementation wise this has the benefit of fitting into the abstraction of dolfinx.io.distribute_entity_data, which extends to parallel input.

@jorgensd
Copy link
Member

jorgensd commented Nov 7, 2025

@schnellerhase The tangent has to be oriented in the same way as the "orientation of the network". (i.e. what is an in-edge or out edge).
I previously had an implementation that did what you are trying to do (using dolfinx.fem.Expression), but that turned out to give the wrong results on grids where the network rotated along the axis. The diff of the commit that removed the old tangent implementation can be found at: 9b3b40c

@jorgensd
Copy link
Member

jorgensd commented Nov 8, 2025

Im not sure what you are trying to do here is the correct approach.

The key is that if we look at an edge of the graph, the orientation is decided by wether a node considers is as an in-edge or out edge.

Your orientation parameter seems to only look at the number of the original nodes of the graph edge (or am I mistaken)?

I also don’t get the reason for storing orientation rather than the normal.

@schnellerhase
Copy link
Collaborator Author

schnellerhase commented Nov 8, 2025

The key is that if we look at an edge of the graph, the orientation is decided by wether a node considers is as an in-edge or out edge.

The orientation variable $o$ (now should) carry $1$ on edges where the local orientation of the edge aligns with the orientation in the DiGraph and $-1$ otherwise. So it encodes the connectivity info of the graph.

Your orientation parameter seems to only look at the number of the original nodes of the graph edge (or am I mistaken)?

The check for in_order = global_input[e[:, 0]] < global_input[e[:, 1]] is just an introduction of order (it would equivalently work if we swapped the check here and below to $&gt;$). The idea is, we need some way of checking later on if the reordering during mesh construction affected the orientation of the edge, for that we need some kind of order (not necessarily aligning with the edge).

@schnellerhase
Copy link
Collaborator Author

schnellerhase commented Nov 8, 2025

I also don’t get the reason for storing orientation rather than the normal.

The orientation is not geometry dependant. If we transform the mesh the orientation will still carry the correct information as it is independent of the geometric information, while the tangent vector would no longer be correct.
For a deformed configuration we would need to compute anyways the orientation from the tangent vector and from this the shifted/true tangent vector. I think it is just hiding the fact that what we truly care about, on mesh level, is the traversal order of the element not necessarily the spacial direction this implies.

@schnellerhase schnellerhase marked this pull request as ready for review November 10, 2025 12:04
@schnellerhase schnellerhase changed the title Tangent as UFL expression Introduce orientation (replacing tangent) Nov 10, 2025
t = J[:, 0]
t /= ufl.sqrt(ufl.inner(t, t))

tangent = self._network_mesh.orientation * t
Copy link
Member

Choose a reason for hiding this comment

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

I guess as we are in 1D, we don't really worry about if UFL over-estimates quadrature for this.
And in the case of "curved" meshes, we could actually gain accuracy by this approach rather than encoding the tangent.

Co-authored-by: Jørgen Schartum Dokken <dokken92@gmail.com>
Copy link
Member

@jorgensd jorgensd left a comment

Choose a reason for hiding this comment

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

Minor (but important) things.

@schnellerhase
Copy link
Collaborator Author

Timings:

main tangent-as-ufl-expr
demo_perf_main demo_perf

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