Skip to content

Commit fa53a65

Browse files
committed
ENH: Major reorganization and added 3D interface.
1 parent 73e4a14 commit fa53a65

25 files changed

+282
-27
lines changed

README.rst

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Python bindings to a subset of the `NUFFT algorithm
2-
<http://www.cims.nyu.edu/cmcl/nufft/nufft.html>`_. Only the 1D and 2D cases are
3-
implemented.
2+
<http://www.cims.nyu.edu/cmcl/nufft/nufft.html>`_. 1D, 2D, and 3D
3+
cases are implemented.
44

55
Usage
66
-----
@@ -21,7 +21,8 @@ You can specify your required precision using ``eps=1e-15``. The default is
2121
Authors and License
2222
-------------------
2323

24-
Python bindings by Dan Foreman-Mackey and Thomas Arildsen but the code that actually does the work
25-
is from the Greengard lab at NYU (see `the website
26-
<http://www.cims.nyu.edu/cmcl/nufft/nufft.html>`_). The Fortran code is BSD
27-
licensed and the Python bindings are MIT licensed.
24+
Python bindings by Dan Foreman-Mackey, Thomas Arildsen, and
25+
Marc T. Henry de Frahan but the code that actually does the work is
26+
from the Greengard lab at NYU (see `the website
27+
<http://www.cims.nyu.edu/cmcl/nufft/nufft.html>`_). The Fortran code
28+
is BSD licensed and the Python bindings are MIT licensed.

nufft/__init__.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@
88
__NUFFT_SETUP__ = False
99

1010
if not __NUFFT_SETUP__:
11-
__all__ = ["nufft1d1freqs", "nufft1d1", "nufft1d2", "nufft1d3",
12-
"nufft2d1", "nufft2d2", "nufft2d3"]
13-
from .nufft import nufft1d1freqs, nufft1d1, nufft1d2, nufft1d3, nufft2d1, nufft2d2, nufft2d3
11+
__all__ = ["nufft1d1freqs",
12+
"nufft1d1",
13+
"nufft1d2",
14+
"nufft1d3",
15+
"nufft2d1",
16+
"nufft2d2",
17+
"nufft2d3",
18+
"nufft3d1",
19+
"nufft3d2",
20+
"nufft3d3"]
21+
from .nufft import nufft1d1freqs, nufft1d1, nufft1d2, nufft1d3, nufft2d1, nufft2d2, nufft2d3, nufft3d1, nufft3d2, nufft3d3

nufft/nufft.py

Lines changed: 163 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,16 @@
22

33
from __future__ import division, print_function
44

5-
__all__ = ["nufft1d1freqs", "nufft1d1", "nufft1d2", "nufft1d3",
6-
"nufft2d1", "nufft2d2", "nufft2d3"]
5+
__all__ = ["nufft1d1freqs",
6+
"nufft1d1",
7+
"nufft1d2",
8+
"nufft1d3",
9+
"nufft2d1",
10+
"nufft2d2",
11+
"nufft2d3",
12+
"nufft3d1",
13+
"nufft3d2",
14+
"nufft3d3"]
715

816
import numpy as np
917
from ._nufft import (
@@ -13,6 +21,9 @@
1321
dirft2d1, nufft2d1f90,
1422
dirft2d2, nufft2d2f90,
1523
dirft2d3, nufft2d3f90,
24+
dirft3d1, nufft3d1f90,
25+
dirft3d2, nufft3d2f90,
26+
dirft3d3, nufft3d3f90,
1627
)
1728

1829

@@ -151,8 +162,10 @@ def nufft2d1(x, y, z, ms, mt, df=1.0, eps=1e-15, iflag=1, direct=False):
151162
:type y: array
152163
:param z: non-equispaced function values
153164
:type z: array
154-
:param ms: number of frequencies
165+
:param ms: number of frequencies (x-direction)
155166
:type ms: int
167+
:param mt: number of frequencies (y-direction)
168+
:type mt: int
156169
:param df: frequency spacing
157170
:type df: double
158171
:param eps: tolerance for NUFFT
@@ -231,8 +244,10 @@ def nufft2d3(x, y, z, f, g, eps=1e-15, iflag=1, direct=False):
231244
:type y: array
232245
:param z: non-equispaced function values
233246
:type z: array
234-
:param f: non-equispaced frequencies
247+
:param f: non-equispaced frequencies (x-direction)
235248
:type f: array
249+
:param g: non-equispaced frequencies (y-direction)
250+
:type g: array
236251
:param eps: tolerance for NUFFT
237252
:type eps: double
238253
:param iflag: sign for the exponential (0 means :math:`-i`, greater than 0 means :math:`+i`)
@@ -264,3 +279,147 @@ def nufft2d3(x, y, z, f, g, eps=1e-15, iflag=1, direct=False):
264279
if flag:
265280
raise RuntimeError("nufft2d3 failed with code {0}".format(flag))
266281
return p / len(x)
282+
283+
284+
def nufft3d1(x, y, z, c, ms, mt, mu, df=1.0, eps=1e-15, iflag=1, direct=False):
285+
"""
286+
NUFFT type 1 in three dimensions
287+
288+
:param x: non-equispaced locations
289+
:type x: array
290+
:param y: non-equispaced locations
291+
:type y: array
292+
:param z: non-equispaced locations
293+
:type z: array
294+
:param c: non-equispaced function values
295+
:type c: array
296+
:param ms: number of frequencies (x-direction)
297+
:type ms: int
298+
:param mt: number of frequencies (y-direction)
299+
:type mt: int
300+
:param mu: number of frequencies (z-direction)
301+
:type mu: int
302+
:param df: frequency spacing
303+
:type df: double
304+
:param eps: tolerance for NUFFT
305+
:type eps: double
306+
:param iflag: sign for the exponential (0 means :math:`-i`, greater than 0 means :math:`+i`)
307+
:type iflag: int
308+
:param direct: use direct NUFFT methods
309+
:type direct: bool
310+
:return: function in integer frequency space
311+
:rtype: array
312+
"""
313+
# Make sure that the data are properly formatted.
314+
x = np.ascontiguousarray(x, dtype=np.float64)
315+
y = np.ascontiguousarray(y, dtype=np.float64)
316+
z = np.ascontiguousarray(z, dtype=np.float64)
317+
c = np.ascontiguousarray(c, dtype=np.complex128)
318+
if len(x) != len(y) or len(y) != len(z) or len(z) != len(c):
319+
raise ValueError("Dimension mismatch")
320+
321+
# Run the Fortran code.
322+
if direct:
323+
p = dirft3d1(x * df, y * df, z * df, c, iflag, ms, mt, mu)
324+
else:
325+
p, flag = nufft3d1f90(x * df, y * df, z * df,
326+
c, iflag, eps, ms, mt, mu)
327+
# Check the output and return.
328+
if flag:
329+
raise RuntimeError("nufft3d1 failed with code {0}".format(flag))
330+
return p
331+
332+
333+
def nufft3d2(x, y, z, p, df=1.0, eps=1e-15, iflag=1, direct=False):
334+
"""
335+
NUFFT type 2 in three dimensions
336+
337+
:param x: non-equispaced locations
338+
:type x: array
339+
:param y: non-equispaced locations
340+
:type y: array
341+
:param z: non-equispaced locations
342+
:type z: array
343+
:param p: function in integer frequency space
344+
:type p: array
345+
:param df: frequency spacing
346+
:type df: double
347+
:param eps: tolerance for NUFFT
348+
:type eps: double
349+
:param iflag: sign for the exponential (0 means :math:`-i`, greater than 0 means :math:`+i`)
350+
:type iflag: int
351+
:param direct: use direct NUFFT methods
352+
:type direct: bool
353+
:return: function evaluated at non-equispaced locations
354+
:rtype: array
355+
"""
356+
# Make sure that the data are properly formatted.
357+
x = np.ascontiguousarray(x, dtype=np.float64)
358+
y = np.ascontiguousarray(y, dtype=np.float64)
359+
z = np.ascontiguousarray(z, dtype=np.float64)
360+
p = np.ascontiguousarray(p, dtype=np.complex128)
361+
if len(x) != len(y) or len(y) != len(z):
362+
raise ValueError("Dimension mismatch")
363+
364+
# Run the Fortran code.
365+
if direct:
366+
c = dirft3d2(x * df, y * df, z * df, iflag, p)
367+
else:
368+
c, flag = nufft3d2f90(x * df, y * df, z * df, iflag, eps, p)
369+
# Check the output and return.
370+
if flag:
371+
raise RuntimeError("nufft3d2 failed with code {0}".format(flag))
372+
return c
373+
374+
375+
def nufft3d3(x, y, z, c, f, g, h, eps=1e-15, iflag=1, direct=False):
376+
"""
377+
NUFFT type 3 in three dimensions
378+
379+
:param x: non-equispaced locations
380+
:type x: array
381+
:param y: non-equispaced locations
382+
:type y: array
383+
:param z: non-equispaced locations
384+
:type z: array
385+
:param c: non-equispaced function values
386+
:type c: array
387+
:param f: non-equispaced frequencies (x-direction)
388+
:type f: array
389+
:param g: non-equispaced frequencies (y-direction)
390+
:type g: array
391+
:param h: non-equispaced frequencies (z-direction)
392+
:type h: array
393+
:param eps: tolerance for NUFFT
394+
:type eps: double
395+
:param iflag: sign for the exponential (0 means :math:`-i`, greater than 0 means :math:`+i`)
396+
:type iflag: int
397+
:param direct: use direct NUFFT methods
398+
:type direct: bool
399+
:return: function in non-equispaced frequency space
400+
:rtype: array
401+
"""
402+
# Make sure that the data are properly formatted.
403+
x = np.ascontiguousarray(x, dtype=np.float64)
404+
y = np.ascontiguousarray(y, dtype=np.float64)
405+
z = np.ascontiguousarray(z, dtype=np.float64)
406+
c = np.ascontiguousarray(c, dtype=np.complex128)
407+
if len(x) != len(y) or len(y) != len(z) or len(z) != len(c):
408+
raise ValueError("Dimension mismatch")
409+
410+
# Make sure that the frequencies are of the right type.
411+
f = np.ascontiguousarray(f, dtype=np.float64)
412+
g = np.ascontiguousarray(g, dtype=np.float64)
413+
h = np.ascontiguousarray(h, dtype=np.float64)
414+
if len(f) != len(g) or len(g) != len(h):
415+
raise ValueError("Dimension mismatch")
416+
417+
# Run the Fortran code.
418+
if direct:
419+
p = dirft3d3(x, y, z, c, iflag, f, g, h)
420+
else:
421+
p, flag = nufft3d3f90(x, y, z, c, iflag, eps, f, g, h)
422+
# Check the output and return.
423+
if flag:
424+
raise RuntimeError("nufft3d3 failed with code {0}".format(flag))
425+
return p / len(x)

0 commit comments

Comments
 (0)