Skip to content
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

update py docs for testing and local build if CMake was used for compile #384

Merged
merged 6 commits into from
Dec 11, 2023
Merged
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
46 changes: 27 additions & 19 deletions docs/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -437,46 +437,54 @@ Building a python interface to a locally compiled library
-----------------------------------------------------------------------

Recall that the basic user may simply ``pip install finufft``,
then check it worked via::
then check it worked via either (if you have ``pytest`` installed)::

python3 python/test/run_accuracy_tests.py
pytest python/finufft/test

or the older-style eyeball check with::

python3 python/finufft/test/run_accuracy_tests.py

which should report errors around ``1e-6`` and throughputs around 1-10 million points/sec.

However, a user or developer may want to build a python wrapper to their locally
compiled FINUFFT library, perhaps for more speed. We now describe this,
for all OSes.
We assume python3 (hence pip3).
First make sure you have pip
installed, and that you can already compile the C++ library (eg via ``make test``).
Next make sure you have the required python packages::
We assume ``python3`` (hence ``pip3``; make sure you have that installed).

pip3 install numpy
First, compile the shared C++ library, via, eg ``make lib -j`` (using the old-style ``makefile``),
or via::

You may then::
make -p build
cd build
cmake ..
cmake --build . -j
cd ..

You may then run::

pip3 install -e python/finufft

make python
which builds the ``finufft`` Python module, linking to the ``.so``,
and installs (in editable mode) via pip.
You will see that the ``finufftc.*.so`` shared object appears in the ``python/finufft/finufft/`` directory.
You should then run the above tests. You could also run tests and examples via ``make python``.

which builds the ``finufft`` module,
installs (in editable mode) via pip, then runs some tests and examples.
You will see that the ``finufftc`` shared object appears in the ``python/finufft`` directory.
An additional performance test you could then do is::

python3 python/test/run_speed_tests.py
python3 python/finufft/test/run_speed_tests.py

.. note::

On OSX, if trouble with python with clang: we have found that the above may fail with an error about ``-lstdc++``, in which case you should try setting an environment variable like::

export MACOSX_DEPLOYMENT_TARGET=10.14

where you should replace 10.14 by your OSX number. We have also in the past found that running::

pip3 install ./python

in the command line can work even when ``make python`` does not (probably to do with environment variables).
where you should replace 10.14 by your OSX number.

.. note::

Our new (v2.0.1) python interface is quite different from Dan Foreman-Mackey's original repo that wrapped finufft: `python-finufft <https://github.com/dfm/python-finufft>`_, or Jeremy Magland's. The interface is simpler, and the existing library is linked to. Under the hood we now use ``ctypes`` instead of ``pybind11``.
As of v2.0.1, our python interface is quite different from Dan Foreman-Mackey's original repo that wrapped finufft: `python-finufft <https://github.com/dfm/python-finufft>`_, or Jeremy Magland's wrapper. The interface is simpler, and the existing shared binary is linked to (no recompilation). Under the hood we achieve this via ``ctypes`` instead of ``pybind11``.


A few words about python environments
Expand Down
29 changes: 21 additions & 8 deletions docs/python.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,24 @@ Python interface
Quick-start examples
--------------------

The easiest way to install is to run ``pip install finufft``, which downloads and installs the latest precompiled binaries from PyPI.
Please note that the ``finufftpy`` package is obsolete.
The easiest way to install is to run::

pip install finufft

which downloads and installs the latest precompiled binaries from PyPI.
If you have ``pytest`` installed, you can test it with::

pytest python/finufft/test

or, without having ``pytest`` you can run the older-style eyeball check::

python3 python/finufft/test/run_accuracy_tests.py

which should report errors around ``1e-6`` and throughputs around 1-10 million points/sec.
(Please note that the ``finufftpy`` package is obsolete.)
If you would like to compile from source, see :ref:`the Python installation instructions <install-python>`.

To calculate a 1D type 1 transform, from nonuniform to uniform points, we import ``finufft``, specify the nonuniform points ``x``, their strengths ``c``, and call ``nufft1d1``:
Once installed, to calculate a 1D type 1 transform from nonuniform to uniform points, we import ``finufft``, specify the nonuniform points ``x``, their strengths ``c``, and call ``nufft1d1``:

.. code-block:: python

Expand Down Expand Up @@ -41,7 +54,7 @@ It can be modified using the ``eps`` argument:
# calculate the transform to higher accuracy
f = finufft.nufft1d1(x, c, N, eps=1e-12)

Note, however, that a lower tolerance (that is, a higher accuracy) results in a slower transform. See ``python/examples/simple1d1.py`` for the demo code that includes a basic math test (useful to check both the math and the indexing).
Note, however, that a lower tolerance (that is, a higher accuracy) results in a slower transform. See ``python/finufft/examples/simple1d1.py`` for the demo code that includes a basic math test (useful to check both the math and the indexing).

For higher dimensions, we would specify point locations in more than one dimension:

Expand All @@ -58,7 +71,7 @@ For higher dimensions, we would specify point locations in more than one dimensi
# the 2D transform outputs f array of shape (N1, N2)
f = finufft.nufft2d1(x, y, c, (N1, N2))

See ``python/examples/simple2d1.py`` for the demo code that includes a basic math test (useful to check both the math and the indexing).
See ``python/finufft/examples/simple2d1.py`` for the demo code that includes a basic math test (useful to check both the math and the indexing).

We can also go the other way, from uniform to non-uniform points, using a type 2 transform:

Expand Down Expand Up @@ -111,7 +124,7 @@ For the 2D type 1 vectorized interface, we would call
f = finufft.nufft2d1(x, y, c, (N1, N2))

The output array ``f`` would then have the shape ``(K, N1, N2)``.
See the complete demo in ``python/examples/many2d1.py``.
See the complete demo in ``python/finufft/examples/many2d1.py``.

More fine-grained control can be obtained using the plan (or `guru`) interface.
Instead of preparing the transform, setting the nonuniform points, and executing the transform all at once, these steps are seperated into different function calls.
Expand All @@ -133,7 +146,7 @@ To perform the call above using the plan interface, we would write
# execute the plan
f = plan.execute(c)

See the complete demo in ``python/examples/guru2d1.py``.
See the complete demo in ``python/finufft/examples/guru2d1.py``.
All interfaces support both single and double precision, but for the plan, this must be specified at initialization time using the ``dtype`` argument

.. code-block:: python
Expand All @@ -150,7 +163,7 @@ All interfaces support both single and double precision, but for the plan, this
# execute the plan, giving single-precision output
f = plan.execute(c)

See the complete demo, with math test, in ``python/examples/guru2d1f.py``.
See the complete demo, with math test, in ``python/finufft/examples/guru2d1f.py``.


Full documentation
Expand Down
22 changes: 11 additions & 11 deletions python/finufft/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,20 @@
# Set include and library paths relative to FINUFFT root directory.
inc_dir = os.path.join(finufft_dir, 'include')
lib_dir = os.path.join(finufft_dir, 'lib')
lib_dir_cmake = os.path.join(finufft_dir, 'build') # lib may be only here

# Read in long description from README.md.
with open(os.path.join(finufft_dir, 'python', 'finufft', 'README.md'), 'r') as f:
long_description = f.read()

# We specifically link to the dynamic library here through its absolute path
# (that is not through -lfinufft) to ensure that the absolute path of the
# library is encoded in the DT_NEEDED tag. This way, we won't need to have
# libfinufft.so in the LD_LIBRARY_PATH at runtime. The risk with this is that
# if the libfinufft.so is deleted or moved, the Python module will break
# unless LD_LIBRARY_PATH is updated.
if platform.system() == 'Windows':
finufft_dlib = 'finufft'
finufft_dlib = 'finufft'

# Windows does not have the concept of rpath and as a result, MSVC crashes if
# supplied with one.
if platform.system() != "Windows":
runtime_library_dirs = [lib_dir, lib_dir_cmake]
else:
finufft_dlib = os.path.join(lib_dir, 'finufft')
runtime_library_dirs = []

# For certain platforms (e.g. Ubuntu 20.04), we need to create a dummy source
# that calls one of the functions in the FINUFFT dynamic library. The reason
Expand Down Expand Up @@ -91,8 +90,9 @@
Extension(name='finufft.finufftc',
sources=[source_filename],
include_dirs=[inc_dir, '/usr/local/include'],
library_dirs=[lib_dir, '/usr/local/lib'],
libraries=[finufft_dlib])
library_dirs=[lib_dir, lib_dir_cmake, '/usr/local/lib'],
libraries=[finufft_dlib],
runtime_library_dirs=runtime_library_dirs)
]
)

Expand Down
Loading