Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 6 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
- [Input & Output (C++ and Python)](#input--output-c-and-python)
- [Minimal Python Example](#minimal-python-example)
- [Minimal C++ Example](#minimal-c-example)
- [Minimal PyTorch Example (Differentiable)](#minimal-pytorch-example-differentiable)
- [Installation](#installation)
- [With conda](#with-conda)
- [With pip](#with-pip)
Expand Down Expand Up @@ -233,51 +232,12 @@ Similarly to Python, the C++ implementation also provides mesh checking capabili
> [!TIP]
> For reference, have a look at [the main method](./src/main.cpp) of the C++ executable.

### Minimal PyTorch Example (Differentiable)

Besides the C++/pybind11 interface above, `polyhedral_gravity.torch` provides a pure
PyTorch re-implementation of the same Tsoulis line-integral formula. It is fully
differentiable (autograd) with respect to vertex positions and density, and runs on
both CPU and CUDA. On CPU it is slower than the compiled C++ implementation, but with
a CUDA GPU it can be faster when evaluating many points at once, depending on hardware
and problem size — see the [benchmark notebook](notebooks/polyhedral-gravity-torch-benchmark.ipynb).

It requires PyTorch, which is **not** a dependency of the base package and must be
installed separately:

```bash
pip install torch
```

```python
import torch
from polyhedral_gravity.torch import evaluate

cube_vertices = torch.tensor(
[[-1, -1, -1], [1, -1, -1], [1, 1, -1], [-1, 1, -1],
[-1, -1, 1], [1, -1, 1], [1, 1, 1], [-1, 1, 1]],
dtype=torch.float64, requires_grad=True,
)
cube_faces = torch.tensor(
[[1, 3, 2], [0, 3, 1], [0, 1, 5], [0, 5, 4], [0, 7, 3], [0, 4, 7],
[1, 2, 6], [1, 6, 5], [2, 3, 6], [3, 7, 6], [4, 5, 6], [4, 6, 7]],
)
cube_density = torch.tensor(1.0, requires_grad=True)
computation_points = torch.tensor([[0.0, 0.0, 2.0]])

potential, acceleration, tensor = evaluate(
cube_vertices, cube_faces, cube_density, computation_points,
)

# Gradients flow back through the analytic formula, e.g. for shape/density optimization
potential.sum().backward()
print(cube_vertices.grad, cube_density.grad)
```

> [!TIP]
> See the [PyTorch interface notebook](notebooks/polyhedral-gravity-torch.ipynb) for a
> worked example, and the [benchmark notebook](notebooks/polyhedral-gravity-torch-benchmark.ipynb)
> for a CPU/GPU performance comparison against the C++ implementation.
> [!NOTE]
> An optional, differentiable `polyhedral_gravity.torch` submodule is also available,
> useful if you need autograd gradients (e.g. for shape/density optimization) or want
> to run on a CUDA GPU — see the
> [PyTorch interface documentation](https://esa.github.io/polyhedral-gravity-model/api/python.html#pytorch-interface-differentiable)
> for details and examples.

## Installation

Expand Down
25 changes: 25 additions & 0 deletions docs/api/python.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,28 @@ Below is the list of the available attributes:
Specifies the logging level fixed at compile time.

This corresponds to the value defined by the ``POLYHEDRAL_GRAVITY_LOGGING_LEVEL`` C++ variable.


PyTorch Interface (Differentiable)
-----------------------------------

The optional :code:`polyhedral_gravity.torch` submodule provides a pure-PyTorch,
autograd-differentiable re-implementation of :code:`evaluate(..)`. It is not
imported by default and requires PyTorch to be installed separately
(:code:`pip install torch`). See :ref:`examples-python` for a usage example,
and the `PyTorch interface notebook <https://github.com/esa/polyhedral-gravity-model/blob/main/notebooks/polyhedral-gravity-torch.ipynb>`__
and `benchmark notebook <https://github.com/esa/polyhedral-gravity-model/blob/main/notebooks/polyhedral-gravity-torch-benchmark.ipynb>`__
for further details.

.. py:function:: polyhedral_gravity.torch.evaluate(vertices, faces, density, computation_points, gravitational_constant=6.67430e-11)

Gravitational potential, acceleration, and gradient tensor for a polyhedron,
differentiable w.r.t. vertex positions and density.

:param vertices: ``(N, 3)`` vertex positions [m] (``torch.Tensor``).
:param faces: ``(F, 3)`` triangle vertex indices, integer dtype (``torch.Tensor``).
:param density: Constant density [kg/m^3].
:param computation_points: ``(Q, 3)`` evaluation positions [m] (``torch.Tensor``).
:param gravitational_constant: Gravitational constant, defaults to ``6.67430e-11``.
:returns: Tuple of ``potential (Q,)``, ``acceleration (Q, 3)``, and gradient ``tensor (Q, 6)``
(ordered as ``[Vxx, Vyy, Vzz, Vxy, Vxz, Vyz]``).
37 changes: 37 additions & 0 deletions docs/quickstart/examples_python.rst
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,40 @@ Have a look at the example below to see how to use the :code:`GravityEvaluable`
# as fast as the following (find the runtime details below), which returns
# a list of triplets comprising potential, acceleration, tensor
results = evaluable(computation_points, parallel=True)


PyTorch Interface (Differentiable)
-----------------------------------

In addition to the C++-backed :code:`evaluate(..)`, the optional
:code:`polyhedral_gravity.torch` submodule provides a pure-PyTorch
re-implementation of the same Tsoulis (2012) line-integral formula. It is
differentiable with respect to both the polyhedron's vertex positions and its
density, and runs on CPU or CUDA. This is useful for gradient-based
optimization, e.g. recovering a shape or density distribution from gravity
measurements. It requires PyTorch to be installed separately
(:code:`pip install torch`); it is not a hard dependency of
:code:`polyhedral-gravity-model`.

.. code-block:: python

import torch
from polyhedral_gravity.torch import evaluate as torch_evaluate

vertices = torch.tensor(..., dtype=torch.float64, requires_grad=True) # (N, 3)
faces = torch.tensor(...) # (F, 3) int
density = torch.tensor(1.0, requires_grad=True)
computation_points = torch.tensor(...) # (Q, 3)

potential, acceleration, tensor = torch_evaluate(
vertices, faces, density, computation_points,
)

# Gradients flow back through the analytic formula, e.g. for shape/density optimization
potential.sum().backward()
print(vertices.grad, density.grad)

.. tip::
See the `PyTorch interface notebook <https://github.com/esa/polyhedral-gravity-model/blob/main/notebooks/polyhedral-gravity-torch.ipynb>`__
for a worked example, and the `benchmark notebook <https://github.com/esa/polyhedral-gravity-model/blob/main/notebooks/polyhedral-gravity-torch-benchmark.ipynb>`__
for a CPU/GPU performance comparison against the C++ implementation.
1 change: 1 addition & 0 deletions python/polyhedral_gravity/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from ._core import *
from ._core import __version__, __parallelization__, __commit__, __logging__
Loading
Loading