Skip to content

Commit c789ab2

Browse files
committed
Tangent as UFL expression
1 parent 4a7b843 commit c789ab2

File tree

3 files changed

+7
-72
lines changed

3 files changed

+7
-72
lines changed

demos/demo_perf.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ def eval(self, x):
4949
G = None
5050
network_mesh = NetworkMesh(G, cfg)
5151
del G
52-
network_mesh.export_tangent()
5352
export_submeshes(network_mesh, cfg.outdir / f"n{n}")
5453
assembler = HydraulicNetworkAssembler(cfg, network_mesh)
5554
# Compute forms

src/networks_fenicsx/assembly.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,11 @@ def compute_forms(
218218
P1_e = fem.functionspace(network_mesh.mesh, ("Lagrange", 1))
219219
p_bc = fem.Function(P1_e)
220220
p_bc.interpolate(p_bc_ex.eval)
221-
tangent = self._network_mesh.tangent
221+
222+
tangent = ufl.Jacobian(self._network_mesh.mesh)
223+
tangent = tangent[:, 0]
224+
tangent /= ufl.sqrt(ufl.inner(tangent, tangent))
225+
222226
for i, (submesh, entity_map, facet_marker) in enumerate(
223227
zip(
224228
network_mesh.submeshes,

src/networks_fenicsx/mesh.py

Lines changed: 2 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
https://github.com/IngeborgGjerde/fenics-networks by Ingeborg Gjerde.
99
"""
1010

11-
from typing import Any, Callable, Iterable
11+
from typing import Callable, Iterable
1212

1313
from mpi4py import MPI
1414

@@ -18,9 +18,9 @@
1818

1919
import basix.ufl
2020
import ufl
21-
from dolfinx import fem, mesh
2221
from dolfinx import graph as _graph
2322
from dolfinx import io as _io
23+
from dolfinx import mesh
2424
from networks_fenicsx import config
2525

2626
__all__ = ["NetworkMesh"]
@@ -70,7 +70,6 @@ class NetworkMesh:
7070
_submesh_facet_markers: list[mesh.MeshTags]
7171
_edge_meshes: list[mesh.Mesh]
7272
_edge_entity_maps: list[mesh.EntityMap]
73-
_tangent: fem.Function
7473
_bifurcation_values: npt.NDArray[np.int32]
7574
_boundary_values: npt.NDArray[np.int32]
7675
_lm_mesh: mesh.Mesh | None
@@ -223,7 +222,6 @@ def _build_mesh(
223222
self._bifurcation_out_color = bifurcation_out_color
224223

225224
# Generate mesh
226-
tangents: npt.NDArray[np.float64] = np.empty((0, self._geom_dim), dtype=np.float64)
227225
if comm.rank == graph_rank:
228226
assert isinstance(graph, nx.DiGraph), (
229227
f"No directional graph present on rank {comm.rank}"
@@ -235,24 +233,17 @@ def _build_mesh(
235233
mesh_nodes = vertex_coords.copy()
236234
cells = []
237235
cell_markers = []
238-
local_tangents = []
239236
if len(line_weights) == 0:
240237
for segment in cells_array:
241238
cells.append(np.array([segment[0], segment[1]], dtype=np.int64))
242239
cell_markers.append(edge_coloring[(segment[0], segment[1])])
243-
start = vertex_coords[segment[0]]
244-
end = vertex_coords[segment[1]]
245-
local_tangents.append(_compute_tangent(start, end))
246240
else:
247241
for segment in cells_array:
248242
start_coord_pos = mesh_nodes.shape[0]
249243
start = vertex_coords[segment[0]]
250244
end = vertex_coords[segment[1]]
251245
internal_line_coords = start * (1 - line_weights) + end * line_weights
252246

253-
tangent = _compute_tangent(start, end)
254-
local_tangents.append(np.tile(tangent, (internal_line_coords.shape[0] + 1, 1)))
255-
256247
mesh_nodes = np.vstack((mesh_nodes, internal_line_coords))
257248
cells.append(np.array([segment[0], start_coord_pos], dtype=np.int64))
258249
segment_connectivity = (
@@ -280,12 +271,10 @@ def _build_mesh(
280271
)
281272
cells_ = np.vstack(cells).astype(np.int64)
282273
cell_markers_ = np.array(cell_markers, dtype=np.int32)
283-
tangents = np.vstack(local_tangents).astype(np.float64)
284274
else:
285275
cells_ = np.empty((0, 2), dtype=np.int64)
286276
mesh_nodes = np.empty((0, self._geom_dim), dtype=np.float64)
287277
cell_markers_ = np.empty((0,), dtype=np.int32)
288-
tangents = tangents[:, : self._geom_dim].copy()
289278
partitioner = mesh.create_cell_partitioner(mesh.GhostMode.shared_facet)
290279
graph_mesh = mesh.create_mesh(
291280
comm,
@@ -304,10 +293,6 @@ def _build_mesh(
304293
cell_markers_,
305294
)
306295

307-
# Distribute tangents
308-
tangent_space = fem.functionspace(graph_mesh, ("DG", 0, (self._geom_dim,)))
309-
self._tangent = fem.Function(tangent_space)
310-
311296
# Which cells from the input mesh (rank 0) correspond to the local cells on this rank
312297
original_cell_indices = self.mesh.topology.original_cell_index[
313298
: self.mesh.topology.index_map(self.mesh.topology.dim).size_local
@@ -320,26 +305,6 @@ def _build_mesh(
320305
assert isinstance(recv_counts, Iterable)
321306
assert sum(recv_counts) == cells_.shape[0]
322307

323-
# Send to rank 0 which tangents that we need
324-
recv_buffer: None | list[npt.NDArray[np.int64] | list[Any] | MPI.Datatype] = None
325-
if comm.rank == graph_rank:
326-
assert recv_counts is not None
327-
recv_buffer = [np.empty(cells_.shape[0], dtype=np.int64), recv_counts, MPI.INT64_T]
328-
329-
comm.Gatherv(sendbuf=original_cell_indices, recvbuf=recv_buffer, root=graph_rank)
330-
send_t_buffer = None
331-
if comm.rank == graph_rank:
332-
assert recv_buffer is not None
333-
recv_data = recv_buffer[0]
334-
assert isinstance(recv_data, np.ndarray)
335-
send_t_buffer = [
336-
tangents[recv_data].flatten(),
337-
np.array(recv_counts) * self._geom_dim,
338-
]
339-
340-
comm.Scatterv(sendbuf=send_t_buffer, recvbuf=self.tangent.x.array, root=graph_rank)
341-
self.tangent.x.scatter_forward()
342-
343308
self._subdomains = mesh.meshtags_from_entities(
344309
self.mesh,
345310
self.mesh.topology.dim,
@@ -459,19 +424,6 @@ def entity_maps(self):
459424
)
460425
return self._edge_entity_maps
461426

462-
@property
463-
def tangent(self):
464-
"""Return DG-0 field containing the tangent vector of the graph."""
465-
return self._tangent
466-
467-
def export_tangent(self):
468-
if self.cfg.export:
469-
with _io.XDMFFile(self.comm, self.cfg.outdir / "mesh/tangent.xdmf", "w") as file:
470-
file.write_mesh(self.mesh)
471-
file.write_function(self.tangent)
472-
else:
473-
print("Export of tangent skipped as cfg.export is set to False.")
474-
475427
@property
476428
def bifurcation_values(self) -> npt.NDArray[np.int32]:
477429
return self._bifurcation_values
@@ -485,23 +437,3 @@ def in_edges(self, bifurcation: int) -> list[int]:
485437

486438
def out_edges(self, bifurcation: int) -> list[int]:
487439
return self._bifurcation_out_color[bifurcation]
488-
489-
490-
def _compute_tangent(
491-
start: npt.NDArray[np.float64], end: npt.NDArray[np.float64]
492-
) -> npt.NDArray[np.float64]:
493-
"""Compute the tangent vector from start to end points.
494-
495-
Tangent is oriented according to positive y-axis.
496-
If perpendicular to y-axis, align with x-axis.
497-
498-
Args:
499-
start: Starting point coordinates.
500-
end: Ending point coordinates.
501-
502-
Returns:
503-
Normalized tangent vector from start to end.
504-
"""
505-
tangent = end - start
506-
tangent /= np.linalg.norm(tangent, axis=-1)
507-
return tangent

0 commit comments

Comments
 (0)