diff --git a/docs/install.rst b/docs/install.rst index c8d980652..c657501ca 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -437,30 +437,42 @@ 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:: @@ -468,15 +480,11 @@ An additional performance test you could then do is:: 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 `_, 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 `_, 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 diff --git a/docs/python.rst b/docs/python.rst index 6f194c09a..828c0fe44 100644 --- a/docs/python.rst +++ b/docs/python.rst @@ -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 `. -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 @@ -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: @@ -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: @@ -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. @@ -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 @@ -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 diff --git a/python/finufft/setup.py b/python/finufft/setup.py index acd0daae0..11fd32196 100644 --- a/python/finufft/setup.py +++ b/python/finufft/setup.py @@ -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 @@ -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) ] )