diff --git a/differt/src/differt/geometry/paths.py b/differt/src/differt/geometry/paths.py index b914cd7e..5fb0be19 100644 --- a/differt/src/differt/geometry/paths.py +++ b/differt/src/differt/geometry/paths.py @@ -20,7 +20,7 @@ @jax.jit @jaxtyped(typechecker=typechecker) -def _cluster_ids(array: Shaped[Array, "batch n"]) -> Int[Array, " batch"]: +def _cell_ids(array: Shaped[Array, "batch n"]) -> Int[Array, " batch"]: @jaxtyped(typechecker=typechecker) def scan_fun( indices: Int[Array, " batch"], @@ -40,15 +40,15 @@ def scan_fun( @jax.jit @jaxtyped(typechecker=typechecker) -def merge_cluster_ids( - cluster_ids_a: Int[Array, " *batch"], - cluster_ids_b: Int[Array, " *batch"], +def merge_cell_ids( + cell_ids_a: Int[Array, " *batch"], + cell_ids_b: Int[Array, " *batch"], ) -> Int[Array, " *batch"]: """ - Merge two arrays of cluster indices as returned by :meth:`Paths.multipath_clusters`. + Merge two arrays of cell indices as returned by :meth:`Paths.multipath_cells`. - Let the returned array be ``cluster_ids``, - then ``cluster_ids[i] == cluster_ids[j]`` for all ``i``, + Let the returned array be ``cell_ids``, + then ``cell_ids[i] == cell_ids[j]`` for all ``i``, ``j`` indices if ``(groups_a[i], groups_b[i]) == (groups_a[j], groups_b[j])``, granted that arrays have been reshaped to uni-dimensional @@ -60,15 +60,15 @@ def merge_cluster_ids( do with the ones used in individual arrays. Args: - cluster_ids_a: The first array of cluster indices. - cluster_ids_b: The second array of cluster indices. + cell_ids_a: The first array of cell indices. + cell_ids_b: The second array of cell indices. Returns: The new array group indices. """ - batch = cluster_ids_a.shape - return _cluster_ids( - jnp.stack((cluster_ids_a, cluster_ids_b), axis=-1).reshape(-1, 2), + batch = cell_ids_a.shape + return _cell_ids( + jnp.stack((cell_ids_a, cell_ids_b), axis=-1).reshape(-1, 2), ).reshape(batch) @@ -175,15 +175,15 @@ def masked_objects( @eqx.filter_jit @jaxtyped(typechecker=typechecker) - def multipath_clusters( + def multipath_cells( self, axis: int = -1, ) -> Int[Array, " *partial_batch"]: """ - Return an array of same multipath cluster indices. + Return an array of same multipath cell indices. - Let the returned array be ``cluster_ids``, - then ``cluster_ids[i] == cluster_ids[j]`` for all ``i``, + Let the returned array be ``cell_ids``, + then ``cell_ids[i] == cell_ids[j]`` for all ``i``, ``j`` indices if ``self.mask[i, :] == self.mask[j, :]``, granted that each array has been reshaped to a two-dimensional array and that ``axis`` is the last dimension. Of course, this @@ -218,13 +218,13 @@ def multipath_clusters( ValueError: If :attr:`mask` is None. """ if self.mask is None: - msg = "Cannot create multiplath clusters from non-existing mask!" + msg = "Cannot create multiplath cells from non-existing mask!" raise ValueError(msg) mask = jnp.moveaxis(self.mask, axis, -1) *partial_batch, last_axis = mask.shape - return _cluster_ids(mask.reshape(-1, last_axis)).reshape(partial_batch) + return _cell_ids(mask.reshape(-1, last_axis)).reshape(partial_batch) @jax.jit @jaxtyped(typechecker=typechecker) @@ -236,7 +236,7 @@ def group_by_objects(self) -> Int[Array, " *batch"]: undergo the same types of interactions. Internally, it uses the same logic as - :meth:`multipath_clusters`, but applied to object indices + :meth:`multipath_cells`, but applied to object indices rather than on mask. Returns: @@ -277,7 +277,7 @@ def group_by_objects(self) -> Int[Array, " *batch"]: *batch, path_length = self.objects.shape objects = self.objects.reshape((-1, path_length)) - return _cluster_ids(objects).reshape(batch) + return _cell_ids(objects).reshape(batch) def __iter__(self) -> Iterator[Self]: """Return an iterator over masked paths. diff --git a/differt/src/differt/geometry/utils.py b/differt/src/differt/geometry/utils.py index d0b9694d..4a1f90db 100644 --- a/differt/src/differt/geometry/utils.py +++ b/differt/src/differt/geometry/utils.py @@ -439,19 +439,19 @@ def assemble_paths( @jax.jit @jaxtyped(typechecker=typechecker) -def min_distance_between_clusters( - cluster_vertices: Float[Array, "*batch 3"], - cluster_ids: Int[Array, "*batch"], +def min_distance_between_cells( + cell_vertices: Float[Array, "*batch 3"], + cell_ids: Int[Array, "*batch"], ) -> Float[Array, "*batch"]: """ - Compute the minimal (Euclidean) distance between vertices in different clusters. + Compute the minimal (Euclidean) distance between vertices in different cells. For every vertex, the minimum distance to another vertex that is not is the same - cluster is computed. + cell is computed. Args: - cluster_vertices: The array of vertex coordinates. - cluster_ids: The array of corresponding cluster indices. + cell_vertices: The array of vertex coordinates. + cell_ids: The array of corresponding cell indices. Returns: The array of minimal distances. @@ -459,16 +459,16 @@ def min_distance_between_clusters( @jaxtyped(typechecker=typechecker) def scan_fun( - _: None, vertex_and_cluster_id: tuple[Float[Array, "3"], Int[Array, " "]] + _: None, vertex_and_cell_id: tuple[Float[Array, "3"], Int[Array, " "]] ) -> tuple[None, Float[Array, " "]]: - vertex, cluster_id = vertex_and_cluster_id + vertex, cell_id = vertex_and_cell_id min_dist = jnp.min( jnp.linalg.norm( - cluster_vertices - vertex, + cell_vertices - vertex, axis=-1, ), initial=jnp.inf, - where=(cluster_id != cluster_ids), + where=(cell_id != cell_ids), ) return None, min_dist @@ -476,7 +476,7 @@ def scan_fun( scan_fun, init=None, xs=( - cluster_vertices.reshape(-1, 3), - cluster_ids.reshape(-1), + cell_vertices.reshape(-1, 3), + cell_ids.reshape(-1), ), - )[1].reshape(cluster_ids.shape) + )[1].reshape(cell_ids.shape) diff --git a/docs/source/notebooks/multipath.ipynb b/docs/source/notebooks/multipath.ipynb index 64cf3498..355a6ff6 100644 --- a/docs/source/notebooks/multipath.ipynb +++ b/docs/source/notebooks/multipath.ipynb @@ -32,17 +32,31 @@ "\n", "This notebook aims at being a tutorial to reproduce the results presented in the paper\n", "*Comparing Differentiable and Dynamic Ray\n", - "Tracing: Introducing the Multipath Lifetime Map*.\n", + "Tracing: Introducing the Multipath Lifetime Map*, and assumes you are familiar with its content.\n", + "\n", + "**You can run it locally or with Google Colab** by cliking on the rocket\n", + "at the top of this page!\n", + "\n", + ":::{tip}\n", + "On Google Colab, make sure to select a GPU or TPU runtime for a faster experience.\n", + ":::\n", "\n", "If you find this tutorial useful and plan on using this tool for your publications,\n", "please cite our work, see {ref}`citing`.\n", "\n", "## Summary\n", "\n", - "In our work, we present the {abbr}`MLM (Multipath Lifetime Map)`, a visual tool, along with two metrics,\n", - "to help determining the range of application of the Dynamic {abbr}`RT (Ray Tracing)` method. For further details, please refer to the paper.\n", + "In our work, we present the Multipath Lifetime Map (MLM), a visual tool, along with two metrics,\n", + "to help determining the scope of application of the Dynamic Ray Tracing (RT) method. For further details, please refer to the paper.\n", "\n", - "The below implementation is far from being the most efficient, as it first aims at providing a nice visual output.\n", + ":::{important}\n", + "The below implementation is far from being the most efficient, as it first aims at providing a nice visual output,\n", + "and it is tailored for users moving on a 2D grid.\n", + "\n", + "While our method extends to any number and kind of dynamic objects,\n", + "it may become extremily hard to provide a visual representation of the MLM,\n", + "especially for higher dimensions.\n", + ":::\n", "\n", "## Imports\n", "\n", @@ -69,9 +83,9 @@ "from plotly.colors import convert_to_RGB_255\n", "from plotly.subplots import make_subplots\n", "\n", - "from differt.geometry.paths import merge_cluster_ids\n", + "from differt.geometry.paths import merge_cell_ids\n", "from differt.geometry.triangle_mesh import TriangleMesh\n", - "from differt.geometry.utils import min_distance_between_clusters, path_lengths\n", + "from differt.geometry.utils import min_distance_between_cells, path_lengths\n", "from differt.plotting import draw_image, draw_markers, reuse, set_defaults\n", "from differt.scene.sionna import download_sionna_scenes, get_sionna_scene\n", "from differt.scene.triangle_scene import TriangleScene" @@ -87,7 +101,11 @@ "Street canyons are probably one of the most common types of scenarios studied in RT,\n", "due to their simplicity to model, but also important presence in big cities.\n", "\n", - "Because we provide a compatibility layer with Sionna scenes, we will simply load the `'simple_street_canyon'` scene." + "As we provide a compatibility layer with Sionna scenes, we will simply load the `'simple_street_canyon'` scene.\n", + "\n", + "You can download all the scenes from the Sionna repository with\n", + "{func}`download_sionna_scenes`.\n", + "By default, they will be placed in a subfolder of the `differt` Python module." ] }, { @@ -1845,9 +1863,9 @@ } }, "text/html": [ - "