├── .coveragerc ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.rst ├── docs ├── Makefile ├── conf.py ├── index.rst ├── make.bat └── source │ └── developer │ ├── apidocs │ └── nufft.rst │ ├── code.rst │ ├── index.rst │ └── testing.rst ├── nufft ├── __init__.py ├── nufft.py └── nufft.pyf ├── requirements-test.txt ├── requirements.txt ├── setup.py ├── src └── nufft │ ├── README │ ├── dfftpack.f │ ├── dirft1d.f │ ├── dirft2d.f │ ├── dirft3d.f │ ├── license.txt │ ├── next235.f │ ├── nufft1d_demof77.f │ ├── nufft1d_demof90.f │ ├── nufft1df77.f │ ├── nufft1df90.f │ ├── nufft2d_demof77.f │ ├── nufft2d_demof90.f │ ├── nufft2df77.f │ ├── nufft2df90.f │ ├── nufft2df90fftw.f │ ├── nufft3d_demof77.f │ ├── nufft3d_demof90.f │ ├── nufft3df77.f │ └── nufft3df90.f └── tests ├── __init.py__ ├── test_nufft1d.py ├── test_nufft1d_dft.py ├── test_nufft2d.py └── test_nufft3d.py /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | omit = 3 | */python?.?/* 4 | */lib-python/?.?/*.py 5 | */lib_pypy/_*.py 6 | */site-packages/ordereddict.py 7 | */site-packages/nose/* 8 | */unittest2/* 9 | test*.py 10 | 11 | [report] 12 | exclude_lines = 13 | raise NotImplementedError 14 | raise ValueError 15 | raise RuntimeError 16 | if __name__ == .__main__.: 17 | 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | _build 3 | *.pyc 4 | *.so 5 | nufft/_*.c 6 | *.DS_Store 7 | _nufft.cpython* 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | - "3.6" 5 | 6 | # command to install tools 7 | before_install: 8 | - sudo apt-get -qq update 9 | - sudo apt-get install gfortran 10 | 11 | # command to install dependencies 12 | install: 13 | - pip install -r requirements.txt 14 | - pip install -r requirements-test.txt 15 | - pip install coveralls 16 | - python setup.py build_src build_ext --inplace 17 | 18 | # command to run the tests 19 | script: 20 | - nosetests --with-coverage 21 | 22 | # command after a successful test 23 | after_success: 24 | - coveralls 25 | 26 | # branches to build 27 | branches: 28 | only: 29 | - master 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Original work Copyright (c) 2014 Daniel Foreman-Mackey 4 | Modified work Copyright 2016 Thomas Arildsen 5 | Modified work Copyright 2017 Marc T. Henry de Frahan 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Python-NUFFT 2 | ============ 3 | 4 | .. image:: https://travis-ci.org/ThomasA/python-nufft.svg?branch=master 5 | :target: https://travis-ci.org/ThomasA/python-nufft 6 | 7 | .. image:: https://coveralls.io/repos/github/ThomasA/python-nufft/badge.svg?branch=master 8 | :target: https://coveralls.io/github/ThomasA/python-nufft?branch=master 9 | 10 | .. image:: https://readthedocs.org/projects/python-nufft/badge/?version=latest 11 | :target: http://python-nufft.readthedocs.io/en/latest/?badge=latest 12 | :alt: Documentation Status 13 | 14 | Python bindings to a subset of the `NUFFT algorithm 15 | `_. 1D, 2D, and 3D 16 | cases are implemented. 17 | 18 | Usage 19 | ----- 20 | 21 | The documentation can be found on `ReadTheDocs 22 | `_. 23 | 24 | To install, run ``python setup.py install``. Then, to evaluate a 25 | type-3 FT in 1D, use ``nufft.nufft1d3``. Assuming that you have a time 26 | series in ``t`` and ``y`` and you want to evaluate it at (angular) 27 | frequencies ``f``: 28 | 29 | .. code-block:: python 30 | 31 | import nufft 32 | ft = nufft.nufft1d3(t, y, f) 33 | 34 | You can specify your required precision using ``eps=1e-15``. The 35 | default is ``1e-15``. 36 | 37 | Authors and License 38 | ------------------- 39 | 40 | Python bindings by Dan Foreman-Mackey, Thomas Arildsen, and 41 | Marc T. Henry de Frahan but the code that actually does the work is 42 | from the Greengard lab at NYU (see `the website 43 | `_). The Fortran code 44 | is BSD licensed and the Python bindings are MIT licensed. 45 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS ?= 6 | SPHINXBUILD ?= sphinx-build 7 | PAPER ?= 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_elements.papersize=a4 12 | PAPEROPT_letter = -D latex_elements.papersize=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 16 | 17 | .PHONY: help 18 | help: 19 | @echo "Please use \`make ' where is one of" 20 | @echo " html to make standalone HTML files" 21 | @echo " dirhtml to make HTML files named index.html in directories" 22 | @echo " singlehtml to make a single large HTML file" 23 | @echo " pickle to make pickle files" 24 | @echo " json to make JSON files" 25 | @echo " htmlhelp to make HTML files and an HTML help project" 26 | @echo " qthelp to make HTML files and a qthelp project" 27 | @echo " applehelp to make an Apple Help Book" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " epub3 to make an epub3" 31 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 32 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 33 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 34 | @echo " lualatexpdf to make LaTeX files and run them through lualatex" 35 | @echo " xelatexpdf to make LaTeX files and run them through xelatex" 36 | @echo " text to make text files" 37 | @echo " man to make manual pages" 38 | @echo " texinfo to make Texinfo files" 39 | @echo " info to make Texinfo files and run them through makeinfo" 40 | @echo " gettext to make PO message catalogs" 41 | @echo " changes to make an overview of all changed/added/deprecated items" 42 | @echo " xml to make Docutils-native XML files" 43 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 44 | @echo " linkcheck to check all external links for integrity" 45 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 46 | @echo " coverage to run coverage check of the documentation (if enabled)" 47 | @echo " dummy to check syntax errors of document sources" 48 | 49 | .PHONY: clean 50 | clean: 51 | rm -rf $(BUILDDIR)/* 52 | 53 | .PHONY: html 54 | html: 55 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 56 | @echo 57 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 58 | 59 | .PHONY: dirhtml 60 | dirhtml: 61 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 62 | @echo 63 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 64 | 65 | .PHONY: singlehtml 66 | singlehtml: 67 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 68 | @echo 69 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 70 | 71 | .PHONY: pickle 72 | pickle: 73 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 74 | @echo 75 | @echo "Build finished; now you can process the pickle files." 76 | 77 | .PHONY: json 78 | json: 79 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 80 | @echo 81 | @echo "Build finished; now you can process the JSON files." 82 | 83 | .PHONY: htmlhelp 84 | htmlhelp: 85 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 86 | @echo 87 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 88 | ".hhp project file in $(BUILDDIR)/htmlhelp." 89 | 90 | .PHONY: qthelp 91 | qthelp: 92 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 93 | @echo 94 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 95 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 96 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/python-nufft.qhcp" 97 | @echo "To view the help file:" 98 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/python-nufft.qhc" 99 | 100 | .PHONY: applehelp 101 | applehelp: 102 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 103 | @echo 104 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 105 | @echo "N.B. You won't be able to view it unless you put it in" \ 106 | "~/Library/Documentation/Help or install it in your application" \ 107 | "bundle." 108 | 109 | .PHONY: devhelp 110 | devhelp: 111 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 112 | @echo 113 | @echo "Build finished." 114 | @echo "To view the help file:" 115 | @echo "# mkdir -p $$HOME/.local/share/devhelp/python-nufft" 116 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/python-nufft" 117 | @echo "# devhelp" 118 | 119 | .PHONY: epub 120 | epub: 121 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 122 | @echo 123 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 124 | 125 | .PHONY: epub3 126 | epub3: 127 | $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 128 | @echo 129 | @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." 130 | 131 | .PHONY: latex 132 | latex: 133 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 134 | @echo 135 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 136 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 137 | "(use \`make latexpdf' here to do that automatically)." 138 | 139 | .PHONY: latexpdf 140 | latexpdf: 141 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 142 | @echo "Running LaTeX files through pdflatex..." 143 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 144 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 145 | 146 | .PHONY: latexpdfja 147 | latexpdfja: 148 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 149 | @echo "Running LaTeX files through platex and dvipdfmx..." 150 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 151 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 152 | 153 | .PHONY: lualatexpdf 154 | lualatexpdf: 155 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 156 | @echo "Running LaTeX files through lualatex..." 157 | $(MAKE) PDFLATEX=lualatex -C $(BUILDDIR)/latex all-pdf 158 | @echo "lualatex finished; the PDF files are in $(BUILDDIR)/latex." 159 | 160 | .PHONY: xelatexpdf 161 | xelatexpdf: 162 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 163 | @echo "Running LaTeX files through xelatex..." 164 | $(MAKE) PDFLATEX=xelatex -C $(BUILDDIR)/latex all-pdf 165 | @echo "xelatex finished; the PDF files are in $(BUILDDIR)/latex." 166 | 167 | .PHONY: text 168 | text: 169 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 170 | @echo 171 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 172 | 173 | .PHONY: man 174 | man: 175 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 176 | @echo 177 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 178 | 179 | .PHONY: texinfo 180 | texinfo: 181 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 182 | @echo 183 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 184 | @echo "Run \`make' in that directory to run these through makeinfo" \ 185 | "(use \`make info' here to do that automatically)." 186 | 187 | .PHONY: info 188 | info: 189 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 190 | @echo "Running Texinfo files through makeinfo..." 191 | make -C $(BUILDDIR)/texinfo info 192 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 193 | 194 | .PHONY: gettext 195 | gettext: 196 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 197 | @echo 198 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 199 | 200 | .PHONY: changes 201 | changes: 202 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 203 | @echo 204 | @echo "The overview file is in $(BUILDDIR)/changes." 205 | 206 | .PHONY: linkcheck 207 | linkcheck: 208 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 209 | @echo 210 | @echo "Link check complete; look for any errors in the above output " \ 211 | "or in $(BUILDDIR)/linkcheck/output.txt." 212 | 213 | .PHONY: doctest 214 | doctest: 215 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 216 | @echo "Testing of doctests in the sources finished, look at the " \ 217 | "results in $(BUILDDIR)/doctest/output.txt." 218 | 219 | .PHONY: coverage 220 | coverage: 221 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 222 | @echo "Testing of coverage in the sources finished, look at the " \ 223 | "results in $(BUILDDIR)/coverage/python.txt." 224 | 225 | .PHONY: xml 226 | xml: 227 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 228 | @echo 229 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 230 | 231 | .PHONY: pseudoxml 232 | pseudoxml: 233 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 234 | @echo 235 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 236 | 237 | .PHONY: dummy 238 | dummy: 239 | $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy 240 | @echo 241 | @echo "Build finished. Dummy builder generates no files." 242 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # python-nufft documentation build configuration file, created by 5 | # sphinx-quickstart on Fri Dec 15 10:16:39 2017. 6 | # 7 | # This file is execfile()d with the current directory set to its 8 | # containing dir. 9 | # 10 | # Note that not all possible configuration values are present in this 11 | # autogenerated file. 12 | # 13 | # All configuration values have a default; values that are commented out 14 | # serve to show the default. 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | # 20 | import os 21 | import sys 22 | sys.path.append(os.path.abspath('../')) 23 | sys.path.append(os.path.abspath('../nufft/')) 24 | 25 | 26 | # -- General configuration ------------------------------------------------ 27 | 28 | # If your documentation needs a minimal Sphinx version, state it here. 29 | # 30 | # needs_sphinx = '1.0' 31 | 32 | # Add any Sphinx extension module names here, as strings. They can be 33 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 34 | # ones. 35 | extensions = ['sphinx.ext.autodoc', 36 | 'sphinx.ext.mathjax', 37 | 'sphinx.ext.todo', 38 | 'sphinx.ext.viewcode'] 39 | 40 | # Add any paths that contain templates here, relative to this directory. 41 | templates_path = ['_templates'] 42 | 43 | # The suffix(es) of source filenames. 44 | # You can specify multiple suffix as a list of string: 45 | # 46 | # source_suffix = ['.rst', '.md'] 47 | source_suffix = '.rst' 48 | 49 | # The master toctree document. 50 | master_doc = 'index' 51 | 52 | # General information about the project. 53 | project = 'python-nufft' 54 | copyright = '2017, Daniel Foreman-Mackey, Thomas Arildsen, Marc T. Henry de Frahan' 55 | author = 'Daniel Foreman-Mackey, Thomas Arildsen, Marc T. Henry de Frahan' 56 | 57 | # The version info for the project you're documenting, acts as replacement for 58 | # |version| and |release|, also used in various other places throughout the 59 | # built documents. 60 | # 61 | # The short X.Y version. 62 | version = '0.0.1-dev' 63 | # The full version, including alpha/beta/rc tags. 64 | release = '0.0.1-dev' 65 | 66 | # The language for content autogenerated by Sphinx. Refer to documentation 67 | # for a list of supported languages. 68 | # 69 | # This is also used if you do content translation via gettext catalogs. 70 | # Usually you set "language" from the command line for these cases. 71 | language = 'en' 72 | 73 | # List of patterns, relative to source directory, that match files and 74 | # directories to ignore when looking for source files. 75 | # This patterns also effect to html_static_path and html_extra_path 76 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 77 | 78 | # The name of the Pygments (syntax highlighting) style to use. 79 | pygments_style = 'sphinx' 80 | 81 | # If true, `todo` and `todoList` produce output, else they produce nothing. 82 | todo_include_todos = True 83 | 84 | 85 | # -- Options for HTML output ---------------------------------------------- 86 | 87 | # The theme to use for HTML and HTML Help pages. See the documentation for 88 | # a list of builtin themes. 89 | # 90 | html_theme = 'sphinx_rtd_theme' 91 | 92 | # Theme options are theme-specific and customize the look and feel of a theme 93 | # further. For a list of options available for each theme, see the 94 | # documentation. 95 | # 96 | # html_theme_options = {} 97 | 98 | # Add any paths that contain custom static files (such as style sheets) here, 99 | # relative to this directory. They are copied after the builtin static files, 100 | # so a file named "default.css" will overwrite the builtin "default.css". 101 | html_static_path = ['_static'] 102 | 103 | # Custom sidebar templates, must be a dictionary that maps document names 104 | # to template names. 105 | # 106 | # This is required for the alabaster theme 107 | # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars 108 | html_sidebars = { 109 | '**': [ 110 | 'relations.html', # needs 'show_related': True theme option to display 111 | 'searchbox.html', 112 | ] 113 | } 114 | 115 | 116 | # -- Options for HTMLHelp output ------------------------------------------ 117 | 118 | # Output file base name for HTML help builder. 119 | htmlhelp_basename = 'python-nufftdoc' 120 | 121 | 122 | # -- Options for LaTeX output --------------------------------------------- 123 | 124 | latex_elements = { 125 | # The paper size ('letterpaper' or 'a4paper'). 126 | # 127 | # 'papersize': 'letterpaper', 128 | 129 | # The font size ('10pt', '11pt' or '12pt'). 130 | # 131 | # 'pointsize': '10pt', 132 | 133 | # Additional stuff for the LaTeX preamble. 134 | # 135 | # 'preamble': '', 136 | 137 | # Latex figure (float) alignment 138 | # 139 | # 'figure_align': 'htbp', 140 | } 141 | 142 | # Grouping the document tree into LaTeX files. List of tuples 143 | # (source start file, target name, title, 144 | # author, documentclass [howto, manual, or own class]). 145 | latex_documents = [ 146 | (master_doc, 'python-nufft.tex', 'python-nufft Documentation', 147 | 'Daniel Foreman-Mackey, Thomas Arildsen, Marc T. Henry de Frahan', 'manual'), 148 | ] 149 | 150 | 151 | # -- Options for manual page output --------------------------------------- 152 | 153 | # One entry per manual page. List of tuples 154 | # (source start file, name, description, authors, manual section). 155 | man_pages = [ 156 | (master_doc, 'python-nufft', 'python-nufft Documentation', 157 | [author], 1) 158 | ] 159 | 160 | 161 | # -- Options for Texinfo output ------------------------------------------- 162 | 163 | # Grouping the document tree into Texinfo files. List of tuples 164 | # (source start file, target name, title, author, 165 | # dir menu entry, description, category) 166 | texinfo_documents = [ 167 | (master_doc, 'python-nufft', 'python-nufft Documentation', 168 | author, 'python-nufft', 'One line description of project.', 169 | 'Miscellaneous'), 170 | ] 171 | 172 | 173 | # -- Options for Epub output ---------------------------------------------- 174 | 175 | # Bibliographic Dublin Core info. 176 | epub_title = project 177 | epub_author = author 178 | epub_publisher = author 179 | epub_copyright = copyright 180 | 181 | # The unique identifier of the text. This can be a ISBN number 182 | # or the project homepage. 183 | # 184 | # epub_identifier = '' 185 | 186 | # A unique identification for the text. 187 | # 188 | # epub_uid = '' 189 | 190 | # A list of files that should not be packed into the epub file. 191 | epub_exclude_files = ['search.html'] 192 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. python-nufft documentation master file, created by 2 | sphinx-quickstart on Fri Dec 15 10:16:39 2017. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to python-nufft's documentation! 7 | ======================================== 8 | 9 | .. toctree:: 10 | :maxdepth: 4 11 | :caption: Contents: 12 | 13 | Developer Manual 14 | 15 | 16 | Indices and tables 17 | ================== 18 | 19 | * :ref:`genindex` 20 | * :ref:`modindex` 21 | * :ref:`search` 22 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | pushd %~dp0 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set BUILDDIR=_build 11 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 12 | set I18NSPHINXOPTS=%SPHINXOPTS% . 13 | if NOT "%PAPER%" == "" ( 14 | set ALLSPHINXOPTS=-D latex_elements.papersize=%PAPER% %ALLSPHINXOPTS% 15 | set I18NSPHINXOPTS=-D latex_elements.papersize=%PAPER% %I18NSPHINXOPTS% 16 | ) 17 | 18 | if "%1" == "" goto help 19 | 20 | if "%1" == "help" ( 21 | :help 22 | echo.Please use `make ^` where ^ is one of 23 | echo. html to make standalone HTML files 24 | echo. dirhtml to make HTML files named index.html in directories 25 | echo. singlehtml to make a single large HTML file 26 | echo. pickle to make pickle files 27 | echo. json to make JSON files 28 | echo. htmlhelp to make HTML files and an HTML help project 29 | echo. qthelp to make HTML files and a qthelp project 30 | echo. devhelp to make HTML files and a Devhelp project 31 | echo. epub to make an epub 32 | echo. epub3 to make an epub3 33 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 34 | echo. text to make text files 35 | echo. man to make manual pages 36 | echo. texinfo to make Texinfo files 37 | echo. gettext to make PO message catalogs 38 | echo. changes to make an overview over all changed/added/deprecated items 39 | echo. xml to make Docutils-native XML files 40 | echo. pseudoxml to make pseudoxml-XML files for display purposes 41 | echo. linkcheck to check all external links for integrity 42 | echo. doctest to run all doctests embedded in the documentation if enabled 43 | echo. coverage to run coverage check of the documentation if enabled 44 | echo. dummy to check syntax errors of document sources 45 | goto end 46 | ) 47 | 48 | if "%1" == "clean" ( 49 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 50 | del /q /s %BUILDDIR%\* 51 | goto end 52 | ) 53 | 54 | 55 | REM Check if sphinx-build is available and fallback to Python version if any 56 | %SPHINXBUILD% 1>NUL 2>NUL 57 | if errorlevel 9009 goto sphinx_python 58 | goto sphinx_ok 59 | 60 | :sphinx_python 61 | 62 | set SPHINXBUILD=python -m sphinx.__init__ 63 | %SPHINXBUILD% 2> nul 64 | if errorlevel 9009 ( 65 | echo. 66 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 67 | echo.installed, then set the SPHINXBUILD environment variable to point 68 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 69 | echo.may add the Sphinx directory to PATH. 70 | echo. 71 | echo.If you don't have Sphinx installed, grab it from 72 | echo.http://sphinx-doc.org/ 73 | exit /b 1 74 | ) 75 | 76 | :sphinx_ok 77 | 78 | 79 | if "%1" == "html" ( 80 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 84 | goto end 85 | ) 86 | 87 | if "%1" == "dirhtml" ( 88 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 92 | goto end 93 | ) 94 | 95 | if "%1" == "singlehtml" ( 96 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 97 | if errorlevel 1 exit /b 1 98 | echo. 99 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 100 | goto end 101 | ) 102 | 103 | if "%1" == "pickle" ( 104 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 105 | if errorlevel 1 exit /b 1 106 | echo. 107 | echo.Build finished; now you can process the pickle files. 108 | goto end 109 | ) 110 | 111 | if "%1" == "json" ( 112 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 113 | if errorlevel 1 exit /b 1 114 | echo. 115 | echo.Build finished; now you can process the JSON files. 116 | goto end 117 | ) 118 | 119 | if "%1" == "htmlhelp" ( 120 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 121 | if errorlevel 1 exit /b 1 122 | echo. 123 | echo.Build finished; now you can run HTML Help Workshop with the ^ 124 | .hhp project file in %BUILDDIR%/htmlhelp. 125 | goto end 126 | ) 127 | 128 | if "%1" == "qthelp" ( 129 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 130 | if errorlevel 1 exit /b 1 131 | echo. 132 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 133 | .qhcp project file in %BUILDDIR%/qthelp, like this: 134 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\python-nufft.qhcp 135 | echo.To view the help file: 136 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\python-nufft.ghc 137 | goto end 138 | ) 139 | 140 | if "%1" == "devhelp" ( 141 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished. 145 | goto end 146 | ) 147 | 148 | if "%1" == "epub" ( 149 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 150 | if errorlevel 1 exit /b 1 151 | echo. 152 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 153 | goto end 154 | ) 155 | 156 | if "%1" == "epub3" ( 157 | %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3 158 | if errorlevel 1 exit /b 1 159 | echo. 160 | echo.Build finished. The epub3 file is in %BUILDDIR%/epub3. 161 | goto end 162 | ) 163 | 164 | if "%1" == "latex" ( 165 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 166 | if errorlevel 1 exit /b 1 167 | echo. 168 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 169 | goto end 170 | ) 171 | 172 | if "%1" == "latexpdf" ( 173 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 174 | cd %BUILDDIR%/latex 175 | make all-pdf 176 | cd %~dp0 177 | echo. 178 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 179 | goto end 180 | ) 181 | 182 | if "%1" == "latexpdfja" ( 183 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 184 | cd %BUILDDIR%/latex 185 | make all-pdf-ja 186 | cd %~dp0 187 | echo. 188 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 189 | goto end 190 | ) 191 | 192 | if "%1" == "text" ( 193 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 194 | if errorlevel 1 exit /b 1 195 | echo. 196 | echo.Build finished. The text files are in %BUILDDIR%/text. 197 | goto end 198 | ) 199 | 200 | if "%1" == "man" ( 201 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 202 | if errorlevel 1 exit /b 1 203 | echo. 204 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 205 | goto end 206 | ) 207 | 208 | if "%1" == "texinfo" ( 209 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 210 | if errorlevel 1 exit /b 1 211 | echo. 212 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 213 | goto end 214 | ) 215 | 216 | if "%1" == "gettext" ( 217 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 218 | if errorlevel 1 exit /b 1 219 | echo. 220 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 221 | goto end 222 | ) 223 | 224 | if "%1" == "changes" ( 225 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 226 | if errorlevel 1 exit /b 1 227 | echo. 228 | echo.The overview file is in %BUILDDIR%/changes. 229 | goto end 230 | ) 231 | 232 | if "%1" == "linkcheck" ( 233 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 234 | if errorlevel 1 exit /b 1 235 | echo. 236 | echo.Link check complete; look for any errors in the above output ^ 237 | or in %BUILDDIR%/linkcheck/output.txt. 238 | goto end 239 | ) 240 | 241 | if "%1" == "doctest" ( 242 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 243 | if errorlevel 1 exit /b 1 244 | echo. 245 | echo.Testing of doctests in the sources finished, look at the ^ 246 | results in %BUILDDIR%/doctest/output.txt. 247 | goto end 248 | ) 249 | 250 | if "%1" == "coverage" ( 251 | %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage 252 | if errorlevel 1 exit /b 1 253 | echo. 254 | echo.Testing of coverage in the sources finished, look at the ^ 255 | results in %BUILDDIR%/coverage/python.txt. 256 | goto end 257 | ) 258 | 259 | if "%1" == "xml" ( 260 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 261 | if errorlevel 1 exit /b 1 262 | echo. 263 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 264 | goto end 265 | ) 266 | 267 | if "%1" == "pseudoxml" ( 268 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 269 | if errorlevel 1 exit /b 1 270 | echo. 271 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 272 | goto end 273 | ) 274 | 275 | if "%1" == "dummy" ( 276 | %SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy 277 | if errorlevel 1 exit /b 1 278 | echo. 279 | echo.Build finished. Dummy builder generates no files. 280 | goto end 281 | ) 282 | 283 | :end 284 | popd 285 | -------------------------------------------------------------------------------- /docs/source/developer/apidocs/nufft.rst: -------------------------------------------------------------------------------- 1 | nufft package 2 | ============= 3 | 4 | Submodules 5 | ---------- 6 | 7 | nufft\.nufft module 8 | ------------------- 9 | 10 | .. automodule:: nufft.nufft 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | 16 | Module contents 17 | --------------- 18 | 19 | .. automodule:: nufft 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | -------------------------------------------------------------------------------- /docs/source/developer/code.rst: -------------------------------------------------------------------------------- 1 | Source Code Documentation 2 | ========================= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | apidocs/nufft 8 | -------------------------------------------------------------------------------- /docs/source/developer/index.rst: -------------------------------------------------------------------------------- 1 | Developer Manual 2 | ================ 3 | .. toctree:: 4 | :maxdepth: 2 5 | 6 | Testing 7 | Source Code Documentation 8 | -------------------------------------------------------------------------------- /docs/source/developer/testing.rst: -------------------------------------------------------------------------------- 1 | Testing 2 | ======= 3 | 4 | Testing is done with the `unittest` framework. In the parent directory, build the source files 5 | 6 | .. code-block:: bash 7 | 8 | $ python setup.py build_src build_ext --inplace 9 | 10 | and run the testing utility 11 | 12 | .. code-block:: bash 13 | 14 | $ nosetests 15 | -------------------------------------------------------------------------------- /nufft/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | __version__ = "0.0.1-dev" 4 | 5 | try: 6 | __NUFFT_SETUP__ 7 | except NameError: 8 | __NUFFT_SETUP__ = False 9 | 10 | if not __NUFFT_SETUP__: 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 22 | -------------------------------------------------------------------------------- /nufft/nufft.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from __future__ import division, print_function 4 | 5 | __all__ = ["nufft1d1freqs", 6 | "nufft1d1", 7 | "nufft1d2", 8 | "nufft1d3", 9 | "nufft2d1", 10 | "nufft2d2", 11 | "nufft2d3", 12 | "nufft3d1", 13 | "nufft3d2", 14 | "nufft3d3"] 15 | import os 16 | import numpy as np 17 | if not os.environ.get('READTHEDOCS', None) == 'True': 18 | from ._nufft import ( 19 | dirft1d1, nufft1d1f90, 20 | dirft1d2, nufft1d2f90, 21 | dirft1d3, nufft1d3f90, 22 | dirft2d1, nufft2d1f90, 23 | dirft2d2, nufft2d2f90, 24 | dirft2d3, nufft2d3f90, 25 | dirft3d1, nufft3d1f90, 26 | dirft3d2, nufft3d2f90, 27 | dirft3d3, nufft3d3f90, 28 | ) 29 | 30 | 31 | def nufft1d1freqs(ms, df=1.0): 32 | """ 33 | Calculates 1D frequencies 34 | 35 | :param ms: number of frequencies 36 | :type ms: int 37 | :param df: frequency spacing 38 | :type df: double 39 | :return: frequencies 40 | :rtype: array 41 | """ 42 | return df * (np.arange(-ms // 2, ms // 2) + ms % 2) 43 | 44 | 45 | def nufft1d1(x, y, ms, df=1.0, eps=1e-15, iflag=1, direct=False): 46 | """ 47 | NUFFT type 1 in one dimension 48 | 49 | :param x: non-equispaced locations 50 | :type x: array 51 | :param y: non-equispaced function values 52 | :type y: array 53 | :param ms: number of frequencies 54 | :type ms: int 55 | :param df: frequency spacing 56 | :type df: double 57 | :param eps: tolerance for NUFFT 58 | :type eps: double 59 | :param iflag: sign for the exponential (0 means :math:`-i`, greater than 0 means :math:`+i`) 60 | :type iflag: int 61 | :param direct: use direct NUFFT methods 62 | :type direct: bool 63 | :return: function in integer frequency space 64 | :rtype: array 65 | """ 66 | # Make sure that the data are properly formatted. 67 | x = np.ascontiguousarray(x, dtype=np.float64) 68 | y = np.ascontiguousarray(y, dtype=np.complex128) 69 | if len(x) != len(y): 70 | raise ValueError("Dimension mismatch") 71 | 72 | # Run the Fortran code. 73 | if direct: 74 | p = dirft1d1(x * df, y, iflag, ms) 75 | else: 76 | p, flag = nufft1d1f90(x * df, y, iflag, eps, ms) 77 | # Check the output and return. 78 | if flag: 79 | raise RuntimeError("nufft1d1 failed with code {0}".format(flag)) 80 | return p 81 | 82 | 83 | def nufft1d2(x, p, df=1.0, eps=1e-15, iflag=1, direct=False): 84 | """ 85 | NUFFT type 2 in one dimension 86 | 87 | :param x: non-equispaced locations 88 | :type x: array 89 | :param p: function in integer frequency space 90 | :type p: array 91 | :param df: frequency spacing 92 | :type df: double 93 | :param eps: tolerance for NUFFT 94 | :type eps: double 95 | :param iflag: sign for the exponential (0 means :math:`-i`, greater than 0 means :math:`+i`) 96 | :type iflag: int 97 | :param direct: use direct NUFFT methods 98 | :type direct: bool 99 | :return: function evaluated at non-equispaced locations 100 | :rtype: array 101 | """ 102 | # Make sure that the data are properly formatted. 103 | x = np.ascontiguousarray(x, dtype=np.float64) 104 | p = np.ascontiguousarray(p, dtype=np.complex128) 105 | 106 | # Run the Fortran code. 107 | if direct: 108 | y = dirft1d2(x * df, iflag, p) 109 | else: 110 | y, flag = nufft1d2f90(x * df, iflag, eps, p) 111 | # Check the output and return. 112 | if flag: 113 | raise RuntimeError("nufft1d2 failed with code {0}".format(flag)) 114 | return y 115 | 116 | 117 | def nufft1d3(x, y, f, eps=1e-15, iflag=1, direct=False): 118 | """ 119 | NUFFT type 3 in one dimension 120 | 121 | :param x: non-equispaced locations 122 | :type x: array 123 | :param y: non-equispaced function values 124 | :type y: array 125 | :param f: non-equispaced frequencies 126 | :type f: array 127 | :param eps: tolerance for NUFFT 128 | :type eps: double 129 | :param iflag: sign for the exponential (0 means :math:`-i`, greater than 0 means :math:`+i`) 130 | :type iflag: int 131 | :param direct: use direct NUFFT methods 132 | :type direct: bool 133 | :return: function in non-equispaced frequency space 134 | :rtype: array 135 | """ 136 | # Make sure that the data are properly formatted. 137 | x = np.ascontiguousarray(x, dtype=np.float64) 138 | y = np.ascontiguousarray(y, dtype=np.complex128) 139 | if len(x) != len(y): 140 | raise ValueError("Dimension mismatch") 141 | 142 | # Make sure that the frequencies are of the right type. 143 | f = np.ascontiguousarray(f, dtype=np.float64) 144 | 145 | # Run the Fortran code. 146 | if direct: 147 | p = dirft1d3(x, y, iflag, f) 148 | else: 149 | p, flag = nufft1d3f90(x, y, iflag, eps, f) 150 | # Check the output and return. 151 | if flag: 152 | raise RuntimeError("nufft1d3 failed with code {0}".format(flag)) 153 | return p / len(x) 154 | 155 | 156 | def nufft2d1(x, y, z, ms, mt, df=1.0, eps=1e-15, iflag=1, direct=False): 157 | """ 158 | NUFFT type 1 in two dimensions 159 | 160 | :param x: non-equispaced locations 161 | :type x: array 162 | :param y: non-equispaced locations 163 | :type y: array 164 | :param z: non-equispaced function values 165 | :type z: array 166 | :param ms: number of frequencies (x-direction) 167 | :type ms: int 168 | :param mt: number of frequencies (y-direction) 169 | :type mt: int 170 | :param df: frequency spacing 171 | :type df: double 172 | :param eps: tolerance for NUFFT 173 | :type eps: double 174 | :param iflag: sign for the exponential (0 means :math:`-i`, greater than 0 means :math:`+i`) 175 | :type iflag: int 176 | :param direct: use direct NUFFT methods 177 | :type direct: bool 178 | :return: function in integer frequency space 179 | :rtype: array 180 | """ 181 | # Make sure that the data are properly formatted. 182 | x = np.ascontiguousarray(x, dtype=np.float64) 183 | y = np.ascontiguousarray(y, dtype=np.float64) 184 | z = np.ascontiguousarray(z, dtype=np.complex128) 185 | if len(x) != len(y) or len(y) != len(z): 186 | raise ValueError("Dimension mismatch") 187 | 188 | # Run the Fortran code. 189 | if direct: 190 | p = dirft2d1(x * df, y * df, z, iflag, ms, mt) 191 | else: 192 | p, flag = nufft2d1f90(x * df, y * df, z, iflag, eps, ms, mt) 193 | # Check the output and return. 194 | if flag: 195 | raise RuntimeError("nufft2d1 failed with code {0}".format(flag)) 196 | return p 197 | 198 | 199 | def nufft2d2(x, y, p, df=1.0, eps=1e-15, iflag=1, direct=False): 200 | """ 201 | NUFFT type 2 in two dimensions 202 | 203 | :param x: non-equispaced locations 204 | :type x: array 205 | :param y: non-equispaced locations 206 | :type y: array 207 | :param p: function in integer frequency space 208 | :type p: array 209 | :param df: frequency spacing 210 | :type df: double 211 | :param eps: tolerance for NUFFT 212 | :type eps: double 213 | :param iflag: sign for the exponential (0 means :math:`-i`, greater than 0 means :math:`+i`) 214 | :type iflag: int 215 | :param direct: use direct NUFFT methods 216 | :type direct: bool 217 | :return: function evaluated at non-equispaced locations 218 | :rtype: array 219 | """ 220 | # Make sure that the data are properly formatted. 221 | x = np.ascontiguousarray(x, dtype=np.float64) 222 | y = np.ascontiguousarray(y, dtype=np.float64) 223 | p = np.ascontiguousarray(p, dtype=np.complex128) 224 | if len(x) != len(y): 225 | raise ValueError("Dimension mismatch") 226 | 227 | # Run the Fortran code. 228 | if direct: 229 | z = dirft2d2(x * df, y * df, iflag, p) 230 | else: 231 | z, flag = nufft2d2f90(x * df, y * df, iflag, eps, p) 232 | # Check the output and return. 233 | if flag: 234 | raise RuntimeError("nufft2d2 failed with code {0}".format(flag)) 235 | return z 236 | 237 | 238 | def nufft2d3(x, y, z, f, g, eps=1e-15, iflag=1, direct=False): 239 | """ 240 | NUFFT type 3 in two dimensions 241 | 242 | :param x: non-equispaced locations 243 | :type x: array 244 | :param y: non-equispaced locations 245 | :type y: array 246 | :param z: non-equispaced function values 247 | :type z: array 248 | :param f: non-equispaced frequencies (x-direction) 249 | :type f: array 250 | :param g: non-equispaced frequencies (y-direction) 251 | :type g: array 252 | :param eps: tolerance for NUFFT 253 | :type eps: double 254 | :param iflag: sign for the exponential (0 means :math:`-i`, greater than 0 means :math:`+i`) 255 | :type iflag: int 256 | :param direct: use direct NUFFT methods 257 | :type direct: bool 258 | :return: function in non-equispaced frequency space 259 | :rtype: array 260 | """ 261 | # Make sure that the data are properly formatted. 262 | x = np.ascontiguousarray(x, dtype=np.float64) 263 | y = np.ascontiguousarray(y, dtype=np.float64) 264 | z = np.ascontiguousarray(z, dtype=np.complex128) 265 | if len(x) != len(y) or len(y) != len(z): 266 | raise ValueError("Dimension mismatch") 267 | 268 | # Make sure that the frequencies are of the right type. 269 | f = np.ascontiguousarray(f, dtype=np.float64) 270 | g = np.ascontiguousarray(g, dtype=np.float64) 271 | if len(f) != len(g): 272 | raise ValueError("Dimension mismatch") 273 | 274 | # Run the Fortran code. 275 | if direct: 276 | p = dirft2d3(x, y, z, iflag, f, g) 277 | else: 278 | p, flag = nufft2d3f90(x, y, z, iflag, eps, f, g) 279 | # Check the output and return. 280 | if flag: 281 | raise RuntimeError("nufft2d3 failed with code {0}".format(flag)) 282 | return p / len(x) 283 | 284 | 285 | def nufft3d1(x, y, z, c, ms, mt, mu, df=1.0, eps=1e-15, iflag=1, direct=False): 286 | """ 287 | NUFFT type 1 in three dimensions 288 | 289 | :param x: non-equispaced locations 290 | :type x: array 291 | :param y: non-equispaced locations 292 | :type y: array 293 | :param z: non-equispaced locations 294 | :type z: array 295 | :param c: non-equispaced function values 296 | :type c: array 297 | :param ms: number of frequencies (x-direction) 298 | :type ms: int 299 | :param mt: number of frequencies (y-direction) 300 | :type mt: int 301 | :param mu: number of frequencies (z-direction) 302 | :type mu: int 303 | :param df: frequency spacing 304 | :type df: double 305 | :param eps: tolerance for NUFFT 306 | :type eps: double 307 | :param iflag: sign for the exponential (0 means :math:`-i`, greater than 0 means :math:`+i`) 308 | :type iflag: int 309 | :param direct: use direct NUFFT methods 310 | :type direct: bool 311 | :return: function in integer frequency space 312 | :rtype: array 313 | """ 314 | # Make sure that the data are properly formatted. 315 | x = np.ascontiguousarray(x, dtype=np.float64) 316 | y = np.ascontiguousarray(y, dtype=np.float64) 317 | z = np.ascontiguousarray(z, dtype=np.float64) 318 | c = np.ascontiguousarray(c, dtype=np.complex128) 319 | if len(x) != len(y) or len(y) != len(z) or len(z) != len(c): 320 | raise ValueError("Dimension mismatch") 321 | 322 | # Run the Fortran code. 323 | if direct: 324 | p = dirft3d1(x * df, y * df, z * df, c, iflag, ms, mt, mu) 325 | else: 326 | p, flag = nufft3d1f90(x * df, y * df, z * df, 327 | c, iflag, eps, ms, mt, mu) 328 | # Check the output and return. 329 | if flag: 330 | raise RuntimeError("nufft3d1 failed with code {0}".format(flag)) 331 | return p 332 | 333 | 334 | def nufft3d2(x, y, z, p, df=1.0, eps=1e-15, iflag=1, direct=False): 335 | """ 336 | NUFFT type 2 in three dimensions 337 | 338 | :param x: non-equispaced locations 339 | :type x: array 340 | :param y: non-equispaced locations 341 | :type y: array 342 | :param z: non-equispaced locations 343 | :type z: array 344 | :param p: function in integer frequency space 345 | :type p: array 346 | :param df: frequency spacing 347 | :type df: double 348 | :param eps: tolerance for NUFFT 349 | :type eps: double 350 | :param iflag: sign for the exponential (0 means :math:`-i`, greater than 0 means :math:`+i`) 351 | :type iflag: int 352 | :param direct: use direct NUFFT methods 353 | :type direct: bool 354 | :return: function evaluated at non-equispaced locations 355 | :rtype: array 356 | """ 357 | # Make sure that the data are properly formatted. 358 | x = np.ascontiguousarray(x, dtype=np.float64) 359 | y = np.ascontiguousarray(y, dtype=np.float64) 360 | z = np.ascontiguousarray(z, dtype=np.float64) 361 | p = np.ascontiguousarray(p, dtype=np.complex128) 362 | if len(x) != len(y) or len(y) != len(z): 363 | raise ValueError("Dimension mismatch") 364 | 365 | # Run the Fortran code. 366 | if direct: 367 | c = dirft3d2(x * df, y * df, z * df, iflag, p) 368 | else: 369 | c, flag = nufft3d2f90(x * df, y * df, z * df, iflag, eps, p) 370 | # Check the output and return. 371 | if flag: 372 | raise RuntimeError("nufft3d2 failed with code {0}".format(flag)) 373 | return c 374 | 375 | 376 | def nufft3d3(x, y, z, c, f, g, h, eps=1e-15, iflag=1, direct=False): 377 | """ 378 | NUFFT type 3 in three dimensions 379 | 380 | :param x: non-equispaced locations 381 | :type x: array 382 | :param y: non-equispaced locations 383 | :type y: array 384 | :param z: non-equispaced locations 385 | :type z: array 386 | :param c: non-equispaced function values 387 | :type c: array 388 | :param f: non-equispaced frequencies (x-direction) 389 | :type f: array 390 | :param g: non-equispaced frequencies (y-direction) 391 | :type g: array 392 | :param h: non-equispaced frequencies (z-direction) 393 | :type h: array 394 | :param eps: tolerance for NUFFT 395 | :type eps: double 396 | :param iflag: sign for the exponential (0 means :math:`-i`, greater than 0 means :math:`+i`) 397 | :type iflag: int 398 | :param direct: use direct NUFFT methods 399 | :type direct: bool 400 | :return: function in non-equispaced frequency space 401 | :rtype: array 402 | """ 403 | # Make sure that the data are properly formatted. 404 | x = np.ascontiguousarray(x, dtype=np.float64) 405 | y = np.ascontiguousarray(y, dtype=np.float64) 406 | z = np.ascontiguousarray(z, dtype=np.float64) 407 | c = np.ascontiguousarray(c, dtype=np.complex128) 408 | if len(x) != len(y) or len(y) != len(z) or len(z) != len(c): 409 | raise ValueError("Dimension mismatch") 410 | 411 | # Make sure that the frequencies are of the right type. 412 | f = np.ascontiguousarray(f, dtype=np.float64) 413 | g = np.ascontiguousarray(g, dtype=np.float64) 414 | h = np.ascontiguousarray(h, dtype=np.float64) 415 | if len(f) != len(g) or len(g) != len(h): 416 | raise ValueError("Dimension mismatch") 417 | 418 | # Run the Fortran code. 419 | if direct: 420 | p = dirft3d3(x, y, z, c, iflag, f, g, h) 421 | else: 422 | p, flag = nufft3d3f90(x, y, z, c, iflag, eps, f, g, h) 423 | # Check the output and return. 424 | if flag: 425 | raise RuntimeError("nufft3d3 failed with code {0}".format(flag)) 426 | return p / len(x) 427 | -------------------------------------------------------------------------------- /nufft/nufft.pyf: -------------------------------------------------------------------------------- 1 | ! -*- f90 -*- 2 | 3 | python module _nufft ! in 4 | interface ! in :_nufft 5 | 6 | subroutine nufft1d1f90(nj,xj,cj,iflag,eps,ms,fk,ier) ! in :_nufft:src/nufft/nufft1df90.f 7 | integer, optional,check(len(xj)>=nj),depend(xj) :: nj=len(xj) 8 | real*8 dimension(nj) :: xj 9 | complex*16 dimension(nj),depend(nj) :: cj 10 | integer :: iflag 11 | real*8 :: eps 12 | integer :: ms 13 | complex*16 dimension(ms),intent(out),depend(ms) :: fk 14 | integer,intent(out) :: ier 15 | end subroutine nufft1d1f90 16 | 17 | subroutine nufft1d2f90(nj,xj,cj,iflag,eps,ms,fk,ier) ! in :_nufft:src/nufft/nufft1df90.f 18 | integer, optional,check(len(xj)>=nj),depend(xj) :: nj=len(xj) 19 | real*8 dimension(nj) :: xj 20 | complex*16 dimension(nj),intent(out),depend(nj) :: cj 21 | integer :: iflag 22 | real*8 :: eps 23 | integer, optional,check(len(fk)>=ms),depend(fk) :: ms=len(fk) 24 | complex*16 dimension(ms) :: fk 25 | integer,intent(out) :: ier 26 | end subroutine nufft1d2f90 27 | 28 | subroutine nufft1d3f90(nj,xj,cj,iflag,eps,nk,sk,fk,ier) ! in :_nufft:src/nufft/nufft1df90.f 29 | integer, optional,check(len(xj)>=nj),depend(xj) :: nj=len(xj) 30 | real*8 dimension(nj) :: xj 31 | complex*16 dimension(nj),depend(nj) :: cj 32 | integer :: iflag 33 | real*8 :: eps 34 | integer, optional,check(len(sk)>=nk),depend(sk) :: nk=len(sk) 35 | real*8 dimension(nk) :: sk 36 | complex*16 dimension(nk),intent(out),depend(nk) :: fk 37 | integer,intent(out) :: ier 38 | end subroutine nufft1d3f90 39 | 40 | subroutine dirft1d1(nj,xj,cj,iflag,ms,fk) ! in :_nufft:src/nufft/dirft1d.f 41 | integer, optional,check(len(xj)>=nj),depend(xj) :: nj=len(xj) 42 | real*8 dimension(nj) :: xj 43 | complex*16 dimension(nj),depend(nj) :: cj 44 | integer :: iflag 45 | integer :: ms 46 | complex*16 dimension(ms),intent(out),depend(ms) :: fk 47 | end subroutine dirft1d1 48 | 49 | subroutine dirft1d2(nj,xj,cj,iflag,ms,fk) ! in :_nufft:src/nufft/dirft1d.f 50 | integer, optional,check(len(xj)>=nj),depend(xj) :: nj=len(xj) 51 | real*8 dimension(nj) :: xj 52 | complex*16 dimension(nj),intent(out),depend(nj) :: cj 53 | integer :: iflag 54 | integer, optional,check(len(fk)>=ms),depend(fk) :: ms=len(fk) 55 | complex*16 dimension(ms) :: fk 56 | end subroutine dirft1d2 57 | 58 | subroutine dirft1d3(nj,xj,cj,iflag,nk,sk,fk) ! in :_nufft:src/nufft/dirft1d.f 59 | integer, optional,check(len(xj)>=nj),depend(xj) :: nj=len(xj) 60 | real*8 dimension(nj) :: xj 61 | complex*16 dimension(nj),depend(nj) :: cj 62 | integer :: iflag 63 | integer, optional,check(len(sk)>=nk),depend(sk) :: nk=len(sk) 64 | real*8 dimension(nk) :: sk 65 | complex*16 dimension(nk),intent(out),depend(nk) :: fk 66 | end subroutine dirft1d3 67 | 68 | subroutine nufft2d1f90(nj,xj,yj,cj, iflag,eps, ms,mt,fk,ier) ! in :_nufft:src/nufft/nufft2df90.f 69 | integer, optional,check(len(xj)>=nj && len(xj)==len(yj)),depend(xj,yj) :: nj=len(xj) 70 | real*8 dimension(nj) :: xj 71 | real*8 dimension(nj) :: yj 72 | complex*16 dimension(nj),depend(nj) :: cj 73 | integer :: iflag 74 | real*8 :: eps 75 | integer :: ms 76 | integer :: mt 77 | complex*16 dimension(ms, mt),intent(out),depend(ms, mt) :: fk 78 | integer,intent(out) :: ier 79 | end subroutine nufft2d1f90 80 | 81 | subroutine nufft2d2f90(nj,xj,yj,cj, iflag,eps, ms,mt,fk,ier) ! in :_nufft:src/nufft/nufft2df90.f 82 | integer, optional,check(len(xj)>=nj && len(xj)==len(yj)),depend(xj, yj) :: nj=len(xj) 83 | real*8 dimension(nj) :: xj 84 | real*8 dimension(nj) :: yj 85 | complex*16 dimension(nj),intent(out),depend(nj) :: cj 86 | integer :: iflag 87 | real*8 :: eps 88 | integer, optional,check(size(fk, 1)>=ms),depend(fk) :: ms=size(fk, 1) 89 | integer, optional,check(size(fk, 2)>=mt),depend(fk) :: mt=size(fk, 2) 90 | complex*16 dimension(ms, mt) :: fk 91 | integer,intent(out) :: ier 92 | end subroutine nufft2d2f90 93 | 94 | subroutine nufft2d3f90(nj,xj,yj,cj, iflag,eps, nk,sk,tk,fk,ier) ! in :_nufft:src/nufft/nufft2df90.f 95 | integer, optional,check(len(xj)>=nj && len(xj)==len(yj)),depend(xj,yj) :: nj=len(xj) 96 | real*8 dimension(nj) :: xj 97 | real*8 dimension(nj) :: yj 98 | complex*16 dimension(nj),depend(nj) :: cj 99 | integer :: iflag 100 | real*8 :: eps 101 | integer, optional,check(len(sk)>=nk && len(sk)==len(tk)),depend(sk,tk) :: nk=len(sk) 102 | real*8 dimension(nk) :: sk 103 | real*8 dimension(nk) :: tk 104 | complex*16 dimension(nk),intent(out),depend(nk) :: fk 105 | integer,intent(out) :: ier 106 | end subroutine nufft2d3f90 107 | 108 | subroutine dirft2d1(nj,xj,yj,cj, iflag, ms,mt,fk) ! in :_nufft:src/nufft/dirft2d.f 109 | integer, optional,check(len(xj)>=nj && len(xj)==len(yj)),depend(xj, yj) :: nj=len(xj) 110 | real*8 dimension(nj) :: xj 111 | real*8 dimension(nj) :: yj 112 | complex*16 dimension(nj),depend(nj) :: cj 113 | integer :: iflag 114 | integer :: ms 115 | integer :: mt 116 | complex*16 dimension(ms, mt),intent(out),depend(ms, mt) :: fk 117 | end subroutine dirft2d1 118 | 119 | subroutine dirft2d2(nj,xj,yj,cj, iflag, ms,mt,fk) ! in :_nufft:src/nufft/dirft2d.f 120 | integer, optional,check(len(xj)>=nj && len(xj)==len(yj)),depend(xj, yj) :: nj=len(xj) 121 | real*8 dimension(nj) :: xj 122 | real*8 dimension(nj) :: yj 123 | complex*16 dimension(nj),intent(out),depend(nj) :: cj 124 | integer :: iflag 125 | integer, optional,check(size(fk, 1)>=ms),depend(fk) :: ms=size(fk, 1) 126 | integer, optional,check(size(fk, 2)>=mt),depend(fk) :: mt=size(fk, 2) 127 | complex*16 dimension(ms, mt) :: fk 128 | end subroutine dirft2d2 129 | 130 | subroutine dirft2d3(nj,xj,yj,cj, iflag, nk,sk,tk,fk) ! in :_nufft:src/nufft/dirft2d.f 131 | integer, optional,check(len(xj)>=nj && len(xj)==len(yj)),depend(xj,yj) :: nj=len(xj) 132 | real*8 dimension(nj) :: xj 133 | real*8 dimension(nj) :: yj 134 | complex*16 dimension(nj),depend(nj) :: cj 135 | integer :: iflag 136 | integer, optional,check(len(sk)>=nk && len(sk)==len(tk)),depend(sk,tk) :: nk=len(sk) 137 | real*8 dimension(nk) :: sk 138 | real*8 dimension(nk) :: tk 139 | complex*16 dimension(nk),intent(out),depend(nk) :: fk 140 | end subroutine dirft2d3 141 | 142 | subroutine nufft3d1f90(nj,xj,yj,zj,cj, iflag,eps, ms,mt,mu,fk,ier) ! in :_nufft:src/nufft/nufft3df90.f 143 | integer, optional,check(len(xj)>=nj && len(xj)==len(yj) && len(yj)==len(zj)),depend(xj,yj,zj) :: nj=len(xj) 144 | real*8 dimension(nj) :: xj 145 | real*8 dimension(nj) :: yj 146 | real*8 dimension(nj) :: zj 147 | complex*16 dimension(nj),depend(nj) :: cj 148 | integer :: iflag 149 | real*8 :: eps 150 | integer :: ms 151 | integer :: mt 152 | integer :: mu 153 | complex*16 dimension(ms, mt, mu),intent(out),depend(ms, mt, mu) :: fk 154 | integer,intent(out) :: ier 155 | end subroutine nufft3d1f90 156 | 157 | subroutine nufft3d2f90(nj,xj,yj,zj,cj, iflag,eps, ms,mt,mu,fk,ier) ! in :_nufft:src/nufft/nufft3df90.f 158 | integer, optional,check(len(xj)>=nj && len(xj)==len(yj) && len(yj)==len(zj)),depend(xj, yj, zj) :: nj=len(xj) 159 | real*8 dimension(nj) :: xj 160 | real*8 dimension(nj) :: yj 161 | real*8 dimension(nj) :: zj 162 | complex*16 dimension(nj),intent(out),depend(nj) :: cj 163 | integer :: iflag 164 | real*8 :: eps 165 | integer, optional,check(size(fk, 1)>=ms),depend(fk) :: ms=size(fk, 1) 166 | integer, optional,check(size(fk, 2)>=mt),depend(fk) :: mt=size(fk, 2) 167 | integer, optional,check(size(fk, 3)>=mu),depend(fk) :: mt=size(fk, 3) 168 | complex*16 dimension(ms, mt, mu) :: fk 169 | integer,intent(out) :: ier 170 | end subroutine nufft3d2f90 171 | 172 | subroutine nufft3d3f90(nj,xj,yj,zj,cj, iflag,eps, nk,sk,tk,uk,fk,ier) ! in :_nufft:src/nufft/nufft3df90.f 173 | integer, optional,check(len(xj)>=nj && len(xj)==len(yj) && len(yj)==len(zj)),depend(xj,yj,zj) :: nj=len(xj) 174 | real*8 dimension(nj) :: xj 175 | real*8 dimension(nj) :: yj 176 | real*8 dimension(nj) :: zj 177 | complex*16 dimension(nj),depend(nj) :: cj 178 | integer :: iflag 179 | real*8 :: eps 180 | integer, optional,check(len(sk)>=nk && len(sk)==len(tk) && len(sk)==len(uk)),depend(sk,tk,uk) :: nk=len(sk) 181 | real*8 dimension(nk) :: sk 182 | real*8 dimension(nk) :: tk 183 | real*8 dimension(nk) :: uk 184 | complex*16 dimension(nk),intent(out),depend(nk) :: fk 185 | integer,intent(out) :: ier 186 | end subroutine nufft3d3f90 187 | 188 | subroutine dirft3d1(nj,xj,yj,zj,cj, iflag, ms,mt,mu,fk) ! in :_nufft:src/nufft/dirft3d.f 189 | integer, optional,check(len(xj)>=nj && len(xj)==len(yj) && len(yj)==len(zj)),depend(xj, yj, zj) :: nj=len(xj) 190 | real*8 dimension(nj) :: xj 191 | real*8 dimension(nj) :: yj 192 | real*8 dimension(nj) :: zj 193 | complex*16 dimension(nj),depend(nj) :: cj 194 | integer :: iflag 195 | integer :: ms 196 | integer :: mt 197 | integer :: mu 198 | complex*16 dimension(ms, mt, mu),intent(out),depend(ms, mt, mu) :: fk 199 | end subroutine dirft3d1 200 | 201 | subroutine dirft3d2(nj,xj,yj,zj,cj, iflag, ms,mt,mu,fk) ! in :_nufft:src/nufft/dirft3d.f 202 | integer, optional,check(len(xj)>=nj && len(xj)==len(yj) && len(yj)==len(zj)),depend(xj, yj, zj) :: nj=len(xj) 203 | real*8 dimension(nj) :: xj 204 | real*8 dimension(nj) :: yj 205 | real*8 dimension(nj) :: zj 206 | complex*16 dimension(nj),intent(out),depend(nj) :: cj 207 | integer :: iflag 208 | integer, optional,check(size(fk, 1)>=ms),depend(fk) :: ms=size(fk, 1) 209 | integer, optional,check(size(fk, 2)>=mt),depend(fk) :: mt=size(fk, 2) 210 | integer, optional,check(size(fk, 3)>=mu),depend(fk) :: mt=size(fk, 3) 211 | complex*16 dimension(ms, mt, mu) :: fk 212 | end subroutine dirft3d2 213 | 214 | subroutine dirft3d3(nj,xj,yj,zj,cj, iflag, nk,sk,tk,uk,fk) ! in :_nufft:src/nufft/dirft3d.f 215 | integer, optional,check(len(xj)>=nj && len(xj)==len(yj) && len(yj)==len(zj)),depend(xj,yj,zj) :: nj=len(xj) 216 | real*8 dimension(nj) :: xj 217 | real*8 dimension(nj) :: yj 218 | real*8 dimension(nj) :: zj 219 | complex*16 dimension(nj),depend(nj) :: cj 220 | integer :: iflag 221 | integer, optional,check(len(sk)>=nk && len(sk)==len(tk) && len(sk)==len(uk)),depend(sk,tk,uk) :: nk=len(sk) 222 | real*8 dimension(nk) :: sk 223 | real*8 dimension(nk) :: tk 224 | real*8 dimension(nk) :: uk 225 | complex*16 dimension(nk),intent(out),depend(nk) :: fk 226 | end subroutine dirft3d3 227 | 228 | end interface 229 | end python module _nufft 230 | xo 231 | -------------------------------------------------------------------------------- /requirements-test.txt: -------------------------------------------------------------------------------- 1 | nose 2 | unittest2 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | sphinx 3 | sphinx_rtd_theme 4 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import sys 5 | from numpy.distutils.core import setup, Extension 6 | 7 | # Hackishly inject a constant into builtins to enable importing of the 8 | # package even if numpy isn't installed. Only do this if we're not 9 | # running the tests! 10 | if sys.version_info[0] < 3: 11 | import __builtin__ as builtins 12 | else: 13 | import builtins 14 | builtins.__NUFFT_SETUP__ = True 15 | import nufft 16 | version = nufft.__version__ 17 | 18 | # Publish the library to PyPI. 19 | if "publish" in sys.argv[-1]: 20 | os.system("python setup.py sdist upload") 21 | sys.exit() 22 | 23 | # Push a new tag to GitHub. 24 | if "tag" in sys.argv: 25 | os.system("git tag -a {0} -m 'version {0}'".format(version)) 26 | os.system("git push --tags") 27 | sys.exit() 28 | 29 | # Set up the compiled extension. 30 | extensions = [] 31 | if not os.environ.get('READTHEDOCS', None) == 'True': 32 | sources = list(map(os.path.join("src", "nufft", "{0}").format, 33 | ["dfftpack.f", 34 | "dirft1d.f", 35 | "dirft2d.f", 36 | "dirft3d.f", 37 | "next235.f", 38 | "nufft1df90.f", 39 | "nufft2df90.f", 40 | "nufft3df90.f"])) 41 | sources += [os.path.join("nufft", "nufft.pyf")] 42 | extensions = [Extension("nufft._nufft", sources=sources)] 43 | 44 | setup( 45 | name="nufft", 46 | version=version, 47 | author="Daniel Foreman-Mackey", 48 | author_email="danfm@nyu.edu", 49 | url="https://github.com/dfm/python-nufft", 50 | license="MIT", 51 | packages=["nufft"], 52 | install_requires=[ 53 | 'numpy', 54 | 'sphinx_rtd_theme' 55 | ], 56 | ext_modules=extensions, 57 | description="non-uniform FFTs", 58 | long_description=open("README.rst").read(), 59 | package_data={"": ["README.rst", "LICENSE"]}, 60 | test_suite='tests', 61 | tests_require=[ 62 | 'nose', 63 | 'unittest2' 64 | ], 65 | include_package_data=True, 66 | classifiers=[ 67 | # "Development Status :: 5 - Production/Stable", 68 | "Intended Audience :: Developers", 69 | "Intended Audience :: Science/Research", 70 | "License :: OSI Approved :: MIT License", 71 | "Operating System :: OS Independent", 72 | "Programming Language :: Python", 73 | ], 74 | ) 75 | -------------------------------------------------------------------------------- /src/nufft/README: -------------------------------------------------------------------------------- 1 | This directory contains Fortran code for the 1D, 2D and 3D NUFFTs. 2 | 3 | dirft*d.f contains direct evaluation schemes for verification/testing, 4 | where * = 1,2,3 5 | 6 | nufft*df90.f contains NUFFT routines of types 1,2,3 with dynamic F90 7 | workspace allocation. 8 | 9 | nufft*df77.f contains NUFFT routines of types 1,2,3 with static F77 10 | workspace allocation in the calling (driver) routine. 11 | 12 | next235.f contains a utility routine that finds a highly composite 13 | integer greater than a given number. 14 | 15 | dfftpack.f contains a double precision FFT package from Netlib. 16 | 17 | nufft*d_demof77.f contains a sample driver routine for the F77 18 | versions of the codes. 19 | 20 | nufft*d_demof90.f contains the analogous driver for the F90 21 | versions of the codes. 22 | 23 | ------------------------------------------------------------------ 24 | Simply compile 25 | 26 | nufft*d_demof90.f nufft*df90.f dirft*d.f dfftpack.f next235.f 27 | 28 | or 29 | 30 | nufft*d_demof77.f nufft*df77.f dirft*d.f dfft.f next235.f 31 | 32 | 33 | Release notes: 34 | c 35 | c NUFFT 1.2 : Jan 20, 2009. 36 | c First external release. 37 | c 38 | c NUFFT 1.3 : Nov 28, 2011. 39 | c Adjust parameters and constants for double/quad precision. 40 | c Add Matlab/Octave wrappers and mex files. 41 | c 42 | c NUFFT 1.3.3 : Nov 8, 2014. 43 | c Mergerd into a single release for all dimensions 44 | c with minor fixes, documentation modification. 45 | c 46 | -------------------------------------------------------------------------------- /src/nufft/dirft1d.f: -------------------------------------------------------------------------------- 1 | cc Copyright (C) 2004-2009: Leslie Greengard and June-Yub Lee 2 | cc Contact: greengard@cims.nyu.edu 3 | cc 4 | cc This software is being released under a FreeBSD license 5 | cc (see license.txt in this directory). 6 | c*********************************************************************** 7 | subroutine dirft1d1(nj,xj,cj, iflag, ms,fk) 8 | implicit none 9 | integer nj, iflag, ms 10 | real*8 xj(nj) 11 | complex*16 cj(nj), fk(-ms/2:(ms-1)/2) 12 | c ---------------------------------------------------------------------- 13 | c direct computation of nonuniform FFT 14 | c 15 | c 1 nj 16 | c fk(k1) = -- SUM cj(j) exp(+/-i k1 xj(j)) 17 | c nj j=1 18 | c 19 | c for -ms/2 <= k1 <= (ms-1)/2 20 | c 21 | c If (iflag .ge.0) the + sign is used in the exponential. 22 | c If (iflag .lt.0) the - sign is used in the exponential. 23 | c 24 | c*********************************************************************** 25 | integer j, k1 26 | complex*16 zf, cm1 27 | c 28 | do k1 = -ms/2, (ms-1)/2 29 | fk(k1) = dcmplx(0d0,0d0) 30 | enddo 31 | c 32 | do j = 1, nj 33 | if (iflag .ge. 0) then 34 | zf = dcmplx(dcos(xj(j)),+dsin(xj(j))) 35 | else 36 | zf = dcmplx(dcos(xj(j)),-dsin(xj(j))) 37 | endif 38 | c 39 | cm1 = cj(j) / dble(nj) 40 | do k1 = 0, (ms-1)/2 41 | fk(k1) = fk(k1) + cm1 42 | cm1 = cm1 * zf 43 | enddo 44 | c 45 | zf = dconjg(zf) 46 | cm1 = cj(j) / dble(nj) 47 | do k1 = -1, -ms/2, -1 48 | cm1 = cm1 * zf 49 | fk(k1) = fk(k1) + cm1 50 | enddo 51 | enddo 52 | end 53 | c 54 | c 55 | c 56 | c 57 | c 58 | c*********************************************************************** 59 | subroutine dirft1d2(nj,xj,cj, iflag, ms,fk) 60 | implicit none 61 | integer nj, iflag, ms 62 | real*8 xj(nj) 63 | complex*16 cj(nj), fk(-ms/2:(ms-1)/2) 64 | c ---------------------------------------------------------------------- 65 | c direct computation of nonuniform FFT 66 | c 67 | c cj(j) = SUM fk(k1) exp(+/-i k1 xj(j)) 68 | c k1 69 | c for j = 1,...,nj 70 | c 71 | c where -ms/2 <= k1 <= (ms-1)/2 72 | c 73 | c 74 | c If (iflag .ge.0) the + sign is used in the exponential. 75 | c If (iflag .lt.0) the - sign is used in the exponential. 76 | c*********************************************************************** 77 | integer j, k1 78 | complex*16 zf, cm1 79 | c 80 | do j = 1, nj 81 | if (iflag .ge. 0) then 82 | zf = dcmplx(dcos(xj(j)),+dsin(xj(j))) 83 | else 84 | zf = dcmplx(dcos(xj(j)),-dsin(xj(j))) 85 | endif 86 | c 87 | cj(j) = fk(0) 88 | cm1 = zf 89 | do k1 = 1, (ms-1)/2 90 | cj(j) = cj(j) + cm1*fk(k1)+dconjg(cm1)*fk(-k1) 91 | cm1 = cm1 * zf 92 | enddo 93 | if (ms/2*2.eq.ms) cj(j) = cj(j) + dconjg(cm1)*fk(-ms/2) 94 | enddo 95 | end 96 | c 97 | c 98 | c 99 | c 100 | c 101 | c 102 | c*********************************************************************** 103 | subroutine dirft1d3(nj,xj,cj, iflag, nk,sk,fk) 104 | implicit none 105 | integer nj, iflag, nk 106 | real*8 xj(nj), sk(nk) 107 | complex*16 cj(nj), fk(nk) 108 | c ---------------------------------------------------------------------- 109 | c direct computation of nonuniform FFT 110 | c 111 | c nj 112 | c fk(k) = SUM cj(j) exp(+/-i s(k) xj(j)) 113 | c j=1 114 | c 115 | c for k = 1, ..., nk 116 | c 117 | c If (iflag .ge.0) the + sign is used in the exponential. 118 | c If (iflag .lt.0) the - sign is used in the exponential. 119 | c 120 | c*********************************************************************** 121 | integer j, k 122 | real*8 ssk 123 | c 124 | do k = 1, nk 125 | if (iflag .ge. 0) then 126 | ssk = sk(k) 127 | else 128 | ssk = -sk(k) 129 | endif 130 | c 131 | fk(k) = dcmplx(0d0, 0d0) 132 | do j = 1, nj 133 | fk(k) = fk(k) + cj(j)*dcmplx(cos(ssk*xj(j)),sin(ssk*xj(j))) 134 | enddo 135 | enddo 136 | end 137 | -------------------------------------------------------------------------------- /src/nufft/dirft2d.f: -------------------------------------------------------------------------------- 1 | cc Copyright (C) 2004-2009: Leslie Greengard and June-Yub Lee 2 | cc Contact: greengard@cims.nyu.edu 3 | cc 4 | cc This software is being released under a FreeBSD license 5 | cc (see license.txt in this directory). 6 | cc 7 | subroutine dirft2d1(nj,xj,yj,cj, iflag, ms,mt,fk) 8 | implicit none 9 | integer nj, iflag, ms, mt 10 | real*8 xj(nj), yj(nj) 11 | complex*16 cj(nj), fk(-ms/2:(ms-1)/2,-mt/2:(mt-1)/2) 12 | c ------------------------------------------------------------------ 13 | c direct computation of nonuniform FFT 14 | c 15 | c 1 nj 16 | c fk(k1,k2) = -- SUM cj(j) exp(+/-i k1 xj(j)) exp(+/-i k2 yj(j)) 17 | c nj j=1 18 | c 19 | c for -ms/2 <= k1 <= (ms-1)/2, -mt/2 <= k2 <= (mt-1)/2 20 | c 21 | c If (iflag .ge.0) the + sign is used in the exponential. 22 | c If (iflag .lt.0) the - sign is used in the exponential. 23 | c 24 | c*********************************************************************** 25 | integer j, k1, k2 26 | complex*16 zf, cm1, z1n(-ms/2:(ms-1)/2) 27 | c 28 | do k2 = -mt/2, (mt-1)/2 29 | do k1 = -ms/2, (ms-1)/2 30 | fk(k1,k2) = dcmplx(0d0,0d0) 31 | enddo 32 | enddo 33 | c 34 | do j = 1, nj 35 | c 36 | c ---------------------------------------------------------- 37 | c Precompute exponential for exp(+/-i k1 xj) 38 | c ---------------------------------------------------------- 39 | c 40 | if (iflag .ge. 0) then 41 | zf = dcmplx(dcos(xj(j)),+dsin(xj(j))) 42 | else 43 | zf = dcmplx(dcos(xj(j)),-dsin(xj(j))) 44 | endif 45 | z1n(0) = (1d0,0d0) 46 | do k1 = 1, (ms-1)/2 47 | z1n(k1) = zf*z1n(k1-1) 48 | z1n(-k1)= dconjg(z1n(k1)) 49 | enddo 50 | if (ms/2*2.eq.ms) z1n(-ms/2) = dconjg(zf*z1n(ms/2-1)) 51 | c 52 | c ---------------------------------------------------------- 53 | c Loop over k2 for yj 54 | c ---------------------------------------------------------- 55 | if (iflag .ge. 0) then 56 | zf = dcmplx(dcos(yj(j)),+dsin(yj(j))) 57 | else 58 | zf = dcmplx(dcos(yj(j)),-dsin(yj(j))) 59 | endif 60 | c 61 | cm1 = cj(j) / dble(nj) 62 | do k2 = 0, (mt-1)/2 63 | do k1 = -ms/2, (ms-1)/2 64 | fk(k1,k2) = fk(k1,k2) + cm1*z1n(k1) 65 | enddo 66 | cm1 = cm1*zf 67 | enddo 68 | c 69 | zf = dconjg(zf) 70 | cm1 = cj(j) / dble(nj) 71 | do k2 = -1, -mt/2, -1 72 | cm1 = cm1*zf 73 | do k1 = -ms/2, (ms-1)/2 74 | fk(k1,k2) = fk(k1,k2) + cm1*z1n(k1) 75 | enddo 76 | enddo 77 | enddo 78 | end 79 | c 80 | c 81 | c 82 | c 83 | c 84 | c************************************************************************ 85 | subroutine dirft2d2(nj,xj,yj,cj, iflag, ms,mt,fk) 86 | implicit none 87 | integer nj, iflag, ms, mt 88 | real*8 xj(nj), yj(nj) 89 | complex*16 cj(nj), fk(-ms/2:(ms-1)/2,-mt/2:(mt-1)/2) 90 | c ---------------------------------------------------------------------- 91 | c direct computation of nonuniform FFT 92 | c 93 | c 94 | c cj(j) = SUM SUM fk(k1,k2) exp(+/-i k1 xj(j)) exp(+/-i k2 yj(j)) 95 | c k1 k2 96 | c 97 | c for j = 1,...,nj 98 | c 99 | c where -ms/2 <= k1 <= (ms-1)/2, -mt/2 <= k2 <= (mt-1)/2 100 | c 101 | c 102 | c If (iflag .ge.0) the + sign is used in the exponential. 103 | c If (iflag .lt.0) the - sign is used in the exponential. 104 | ************************************************************************ 105 | integer j, k1, k2 106 | complex*16 zf, cm1, cm2, z1n(-ms/2:(ms-1)/2) 107 | c 108 | do j = 1, nj 109 | c 110 | c ---------------------------------------------------------- 111 | c Precompute exponential for exp(+/-i k1 xj) 112 | c ---------------------------------------------------------- 113 | if (iflag .ge. 0) then 114 | zf = dcmplx(dcos(xj(j)),+dsin(xj(j))) 115 | else 116 | zf = dcmplx(dcos(xj(j)),-dsin(xj(j))) 117 | endif 118 | z1n(0) = (1d0,0d0) 119 | do k1 = 1, (ms-1)/2 120 | z1n(k1) = zf*z1n(k1-1) 121 | z1n(-k1)= dconjg(z1n(k1)) 122 | enddo 123 | if (ms/2*2.eq.ms) z1n(-ms/2) = dconjg(zf*z1n(ms/2-1)) 124 | if (iflag .ge. 0) then 125 | zf = dcmplx(dcos(yj(j)),+dsin(yj(j))) 126 | else 127 | zf = dcmplx(dcos(yj(j)),-dsin(yj(j))) 128 | endif 129 | c 130 | cm1 = (0d0, 0d0) 131 | do k1 = -ms/2, (ms-1)/2 132 | cm1 = cm1 + z1n(k1) * fk(k1,0) 133 | enddo 134 | cj(j) = cm1 135 | c 136 | c ---------------------------------------------------------- 137 | c Loop over k2 for yj 138 | c ---------------------------------------------------------- 139 | c 140 | cm2 = zf 141 | do k2 = 1, (mt-1)/2 142 | cm1 = (0d0, 0d0) 143 | do k1 = -ms/2, (ms-1)/2 144 | cm1 = cm1 + z1n(k1) * fk(k1,k2) 145 | enddo 146 | cj(j) = cj(j) + cm2 * cm1 147 | 148 | cm1 = (0d0, 0d0) 149 | do k1 = -ms/2, (ms-1)/2 150 | cm1 = cm1 + z1n(k1) * fk(k1,-k2) 151 | enddo 152 | cj(j) = cj(j) + dconjg(cm2) * cm1 153 | cm2 = cm2*zf 154 | enddo 155 | c 156 | if (mt/2*2.eq.mt) then 157 | cm1 = (0d0, 0d0) 158 | do k1 = -ms/2, (ms-1)/2 159 | cm1 = cm1 + z1n(k1) * fk(k1,-mt/2) 160 | enddo 161 | cj(j) = cj(j) + dconjg(cm2) * cm1 162 | endif 163 | 164 | enddo 165 | end 166 | 167 | ************************************************************************ 168 | subroutine dirft2d3(nj,xj,yj,cj, iflag, nk,sk,tk,fk) 169 | implicit none 170 | integer nj, iflag, nk 171 | real*8 xj(nj), yj(nj), sk(nk), tk(nk) 172 | complex*16 cj(nj), fk(nk) 173 | c ---------------------------------------------------------------------- 174 | c direct computation of nonuniform FFT 175 | c 176 | c nj 177 | c fk(k) = SUM cj(j) exp(+/-i s(k) xj(j)) exp(+/-i t(k) yj(j)) 178 | c j=1 179 | c 180 | c for k = 1, ..., nk 181 | c 182 | c If (iflag .ge.0) the + sign is used in the exponential. 183 | c If (iflag .lt.0) the - sign is used in the exponential. 184 | c 185 | ************************************************************************ 186 | integer k, j 187 | real*8 ssk, stk 188 | c 189 | do k = 1, nk 190 | if (iflag .ge. 0) then 191 | ssk = sk(k) 192 | stk = tk(k) 193 | else 194 | ssk = -sk(k) 195 | stk = -tk(k) 196 | endif 197 | c 198 | fk(k) = dcmplx(0d0,0d0) 199 | do j = 1, nj 200 | fk(k) = fk(k) + cj(j) * dcmplx 201 | & ( dcos(ssk*xj(j)+stk*yj(j)), dsin(ssk*xj(j)+stk*yj(j)) ) 202 | enddo 203 | enddo 204 | end 205 | -------------------------------------------------------------------------------- /src/nufft/dirft3d.f: -------------------------------------------------------------------------------- 1 | cc Copyright (C) 2004-2009: Leslie Greengard and June-Yub Lee 2 | cc Contact: greengard@cims.nyu.edu 3 | cc 4 | cc This software is being released under a FreeBSD license 5 | cc (see license.txt in this directory). 6 | cc 7 | ************************************************************************ 8 | subroutine dirft3d1(nj,xj,yj,zj,cj,iflag,ms,mt,mu,fk) 9 | implicit none 10 | integer nj, iflag, ms, mt, mu 11 | real*8 xj(nj), yj(nj), zj(nj) 12 | complex*16 cj(nj),fk(-ms/2:(ms-1)/2,-mt/2:(mt-1)/2,-mu/2:(mu-1)/2) 13 | c ---------------------------------------------------------------------- 14 | c direct computation of nonuniform FFT 15 | c 16 | c 1 nj 17 | c fk(k1,k2,k3) = -- SUM cj(j) exp(+/-i k1 xj(j)) * 18 | c nj j=1 exp(+/-i k2 yj(j)) * 19 | c exp(+/-i k3 zj(j)) 20 | c 21 | c for -ms/2 <= k1 <= (ms-1)/2, 22 | c -mt/2 <= k2 <= (mt-1)/2 23 | c -mu/2 <= k3 <= (mu-1)/2 24 | c 25 | c If (iflag .ge.0) the + sign is used in the exponential. 26 | c If (iflag .lt.0) the - sign is used in the exponential. 27 | c 28 | ************************************************************************ 29 | integer j, k1, k2, k3 30 | complex*16 zf, cm1, cm2, z1n(-ms/2:(ms-1)/2), z2n(-mt/2:(mt-1)/2) 31 | c 32 | do k3 = -mu/2, (mu-1)/2 33 | do k2 = -mt/2, (mt-1)/2 34 | do k1 = -ms/2, (ms-1)/2 35 | fk(k1,k2,k3) = dcmplx(0d0,0d0) 36 | enddo 37 | enddo 38 | enddo 39 | c 40 | do j = 1, nj 41 | c 42 | c ---------------------------------------------------------- 43 | c Precompute exponential for exp(+/-i k1 xj) 44 | c ---------------------------------------------------------- 45 | c 46 | if (iflag .ge. 0) then 47 | zf = dcmplx(dcos(xj(j)),+dsin(xj(j))) 48 | else 49 | zf = dcmplx(dcos(xj(j)),-dsin(xj(j))) 50 | endif 51 | z1n(0) = (1d0,0d0) 52 | do k1 = 1, (ms-1)/2 53 | z1n(k1) = zf*z1n(k1-1) 54 | z1n(-k1)= dconjg(z1n(k1)) 55 | enddo 56 | if (ms/2*2.eq.ms) z1n(-ms/2) = dconjg(zf*z1n(ms/2-1)) 57 | c 58 | c ---------------------------------------------------------- 59 | c Precompute exponential for exp(+/-i k2 yj) 60 | c ---------------------------------------------------------- 61 | if (iflag .ge. 0) then 62 | zf = dcmplx(dcos(yj(j)),+dsin(yj(j))) 63 | else 64 | zf = dcmplx(dcos(yj(j)),-dsin(yj(j))) 65 | endif 66 | z2n(0) = (1d0,0d0) 67 | do k1 = 1, (mt-1)/2 68 | z2n(k1) = zf*z2n(k1-1) 69 | z2n(-k1)= dconjg(z2n(k1)) 70 | enddo 71 | if (mt/2*2.eq.mt) z2n(-mt/2) = dconjg(zf*z2n(mt/2-1)) 72 | c 73 | c ---------------------------------------------------------- 74 | c Loop over k3 for zj 75 | c ---------------------------------------------------------- 76 | c 77 | if (iflag .ge. 0) then 78 | zf = dcmplx(dcos(zj(j)),+dsin(zj(j))) 79 | else 80 | zf = dcmplx(dcos(zj(j)),-dsin(zj(j))) 81 | endif 82 | c 83 | cm2 = cj(j) / dble(nj) 84 | do k3 = 0, (mu-1)/2 85 | do k2 = -mt/2, (mt-1)/2 86 | cm1 = cm2 * z2n(k2) 87 | do k1 = -ms/2, (ms-1)/2 88 | fk(k1,k2,k3) = fk(k1,k2,k3) + cm1*z1n(k1) 89 | enddo 90 | enddo 91 | cm2 = zf*cm2 92 | enddo 93 | c 94 | zf = dconjg(zf) 95 | cm2 = cj(j) / dble(nj) 96 | do k3 = -1, -mu/2, -1 97 | cm2 = zf*cm2 98 | do k2 = -mt/2, (mt-1)/2 99 | cm1 = cm2 * z2n(k2) 100 | do k1 = -ms/2, (ms-1)/2 101 | fk(k1,k2,k3) = fk(k1,k2,k3) + cm1*z1n(k1) 102 | enddo 103 | enddo 104 | enddo 105 | 106 | enddo 107 | end 108 | c 109 | c 110 | c 111 | c 112 | c 113 | ************************************************************************ 114 | subroutine dirft3d2(nj,xj,yj,zj,cj, iflag, ms,mt,mu,fk) 115 | implicit none 116 | integer nj, iflag, ms, mt, mu 117 | real*8 xj(nj), yj(nj), zj(nj) 118 | complex*16 cj(nj),fk(-ms/2:(ms-1)/2,-mt/2:(mt-1)/2,-mu/2:(mu-1)/2) 119 | c ---------------------------------------------------------------------- 120 | c direct computation of nonuniform FFT 121 | c 122 | c 123 | c cj(j) = SUM SUM SUM fk(k1,k2,k3) exp(+/-i k1 xj(j)) * 124 | c k1 k2 k3 exp(+/-i k2 yj(j)) 125 | c exp(+/-i k3 zj(j)) 126 | c 127 | c for j = 1,...,nj 128 | c 129 | c where -ms/2 <= k1 <= (ms-1)/2 130 | c -mt/2 <= k2 <= (mt-1)/2 131 | c -mu/2 <= k3 <= (mu-1)/2 132 | c 133 | c 134 | c If (iflag .ge.0) the + sign is used in the exponential. 135 | c If (iflag .lt.0) the - sign is used in the exponential. 136 | c 137 | ************************************************************************ 138 | integer j, k1, k2, k3 139 | complex*16 zf, cm1,cm2,cm3,z1n(-ms/2:(ms-1)/2),z2n(-mt/2:(mt-1)/2) 140 | c 141 | do j = 1, nj 142 | c 143 | c ---------------------------------------------------------- 144 | c Precompute exponential for exp(+/-i k1 xj) 145 | c ---------------------------------------------------------- 146 | if (iflag .ge. 0) then 147 | zf = dcmplx(dcos(xj(j)),+dsin(xj(j))) 148 | else 149 | zf = dcmplx(dcos(xj(j)),-dsin(xj(j))) 150 | endif 151 | z1n(0) = (1d0,0d0) 152 | do k1 = 1, (ms-1)/2 153 | z1n(k1) = zf*z1n(k1-1) 154 | z1n(-k1)= dconjg(z1n(k1)) 155 | enddo 156 | if (ms/2*2.eq.ms) z1n(-ms/2) = dconjg(zf*z1n(ms/2-1)) 157 | c 158 | c ---------------------------------------------------------- 159 | c Precompute exponential for exp(+/-i k2 yj) 160 | c ---------------------------------------------------------- 161 | c 162 | if (iflag .ge. 0) then 163 | zf = dcmplx(dcos(yj(j)),+dsin(yj(j))) 164 | else 165 | zf = dcmplx(dcos(yj(j)),-dsin(yj(j))) 166 | endif 167 | z2n(0) = (1d0,0d0) 168 | do k2 = 1, (mt-1)/2 169 | z2n(k2) = zf*z2n(k2-1) 170 | z2n(-k2)= dconjg(z2n(k2)) 171 | enddo 172 | if (mt/2*2.eq.mt) z2n(-mt/2) = dconjg(zf*z2n(mt/2-1)) 173 | c 174 | c ---------------------------------------------------------- 175 | c Loop over k3 for zj 176 | c ---------------------------------------------------------- 177 | if (iflag .ge. 0) then 178 | zf = dcmplx(dcos(zj(j)),+dsin(zj(j))) 179 | else 180 | zf = dcmplx(dcos(zj(j)),-dsin(zj(j))) 181 | endif 182 | c 183 | cm2 = (0d0, 0d0) 184 | do k2 = -mt/2, (mt-1)/2 185 | cm1 = (0d0, 0d0) 186 | do k1 = -ms/2, (ms-1)/2 187 | cm1 = cm1 + z1n(k1) * fk(k1,k2,0) 188 | enddo 189 | cm2 = cm2 + z2n(k2) * cm1 190 | enddo 191 | cj(j) = cm2 192 | c 193 | cm3 = zf 194 | do k3 = 1, (mu-1)/2 195 | cm2 = (0d0, 0d0) 196 | do k2 = -mt/2, (mt-1)/2 197 | cm1 = (0d0, 0d0) 198 | do k1 = -ms/2, (ms-1)/2 199 | cm1 = cm1 + z1n(k1) * fk(k1,k2,k3) 200 | enddo 201 | cm2 = cm2 + z2n(k2) * cm1 202 | enddo 203 | cj(j) = cj(j) + cm3 * cm2 204 | 205 | cm2 = (0d0, 0d0) 206 | do k2 = -mt/2, (mt-1)/2 207 | cm1 = (0d0, 0d0) 208 | do k1 = -ms/2, (ms-1)/2 209 | cm1 = cm1 + z1n(k1) * fk(k1,k2,-k3) 210 | enddo 211 | cm2 = cm2 + z2n(k2) * cm1 212 | enddo 213 | cj(j) = cj(j) + dconjg(cm3) * cm2 214 | cm3 = cm3*zf 215 | enddo 216 | c 217 | if (mu/2*2.eq.mu) then 218 | cm2 = (0d0, 0d0) 219 | do k2 = -mt/2, (mt-1)/2 220 | cm1 = (0d0, 0d0) 221 | do k1 = -ms/2, (ms-1)/2 222 | cm1 = cm1 + z1n(k1) * fk(k1,k2,-mu/2) 223 | enddo 224 | cm2 = cm2 + z2n(k2) * cm1 225 | enddo 226 | cj(j) = cj(j) + dconjg(cm3) * cm2 227 | endif 228 | enddo 229 | end 230 | c 231 | c 232 | c 233 | c 234 | c 235 | ************************************************************************ 236 | subroutine dirft3d3(nj,xj,yj,zj,cj, iflag, nk,sk,tk,uk,fk) 237 | implicit none 238 | integer nj, iflag, nk 239 | real*8 xj(nj), yj(nj), zj(nj), sk(nk), tk(nk), uk(nk) 240 | complex*16 cj(nj), fk(nk) 241 | c ---------------------------------------------------------------------- 242 | c direct computation of nonuniform FFT 243 | c 244 | c nj 245 | c fk(k) = SUM cj(j) exp(+/-i s(k) xj(j)) * 246 | c j=1 exp(+/-i t(k) yj(j)) * 247 | c exp(+/-i u(k) zj(j)) 248 | c 249 | c for k = 1, ..., nk 250 | c 251 | c If (iflag .ge.0) the + sign is used in the exponential. 252 | c If (iflag .lt.0) the - sign is used in the exponential. 253 | c 254 | ************************************************************************ 255 | integer k, j 256 | real*8 ssk, stk, suk 257 | c 258 | do k = 1, nk 259 | if (iflag .ge. 0) then 260 | ssk = sk(k) 261 | stk = tk(k) 262 | suk = uk(k) 263 | else 264 | ssk = -sk(k) 265 | stk = -tk(k) 266 | suk = -uk(k) 267 | endif 268 | c 269 | fk(k) = dcmplx(0d0,0d0) 270 | do j = 1, nj 271 | fk(k) = fk(k) + cj(j) * dcmplx 272 | & ( dcos(ssk*xj(j)+stk*yj(j)+suk*zj(j)), 273 | & dsin(ssk*xj(j)+stk*yj(j)+suk*zj(j)) ) 274 | enddo 275 | enddo 276 | end 277 | 278 | -------------------------------------------------------------------------------- /src/nufft/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-2014, Leslie Greengard, June-Yub Lee and Zydrunas Gimbutas 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those 25 | of the authors and should not be interpreted as representing official policies, 26 | either expressed or implied, of the FreeBSD Project. 27 | -------------------------------------------------------------------------------- /src/nufft/next235.f: -------------------------------------------------------------------------------- 1 | ************************************************************************ 2 | function next235(base) 3 | implicit none 4 | integer next235, numdiv 5 | real*8 base 6 | c ---------------------------------------------------------------------- 7 | c integer function next235 returns a multiple of 2, 3, and 5 8 | c 9 | c next235 = 2^p 3^q 5^r >= base where p>=1, q>=0, r>=0 10 | ************************************************************************ 11 | next235 = 2 * int(base/2d0+.9999d0) 12 | if (next235.le.0) next235 = 2 13 | 14 | 100 numdiv = next235 15 | do while (numdiv/2*2 .eq. numdiv) 16 | numdiv = numdiv /2 17 | enddo 18 | do while (numdiv/3*3 .eq. numdiv) 19 | numdiv = numdiv /3 20 | enddo 21 | do while (numdiv/5*5 .eq. numdiv) 22 | numdiv = numdiv /5 23 | enddo 24 | if (numdiv .eq. 1) return 25 | next235 = next235 + 2 26 | goto 100 27 | end 28 | 29 | -------------------------------------------------------------------------------- /src/nufft/nufft1d_demof77.f: -------------------------------------------------------------------------------- 1 | cc Copyright (C) 2004-2009: Leslie Greengard and June-Yub Lee 2 | cc Contact: greengard@cims.nyu.edu 3 | cc 4 | cc This software is being released under a FreeBSD license 5 | cc (see license.txt in this directory). 6 | c 7 | program testfft 8 | implicit none 9 | c 10 | c --- local variables 11 | c 12 | integer i,ier,iflag,j,k1,lused,lw,mx,ms,nj 13 | parameter (mx=10 000) 14 | parameter (lw=10 000) 15 | real*8 xj(mx), sk(mx) 16 | real*8 err,eps,pi 17 | real*8 fw(0:lw-1) 18 | parameter (pi=3.141592653589793238462643383279502884197d0) 19 | complex*16 cj(mx),cj0(mx),cj1(mx) 20 | complex*16 fk0(mx),fk1(mx) 21 | c 22 | c -------------------------------------------------- 23 | c create some test data 24 | c -------------------------------------------------- 25 | ms = 90 26 | nj = 128 27 | do k1 = -nj/2, (nj-1)/2 28 | j = k1+nj/2+1 29 | xj(j) = pi * dcos(-pi*j/nj) 30 | cj(j) = dcmplx( dsin(pi*j/nj), dcos(pi*j/nj)) 31 | enddo 32 | write(6,1000) ( xj(j),j=1,nj) 33 | 1000 format(6(1x,e12.5)) 34 | c 35 | c -------------------------------------------------- 36 | c start tests 37 | c -------------------------------------------------- 38 | c 39 | iflag = 1 40 | print*,' Start 1D testing: ', ' nj =',nj, ' ms =',ms 41 | do i = 1,4 42 | if (i.eq.1) eps=1d-4 43 | if (i.eq.2) eps=1d-8 44 | if (i.eq.3) eps=1d-12 45 | if (i.eq.4) eps=1d-16 46 | c extended/quad precision tests 47 | if (i.eq.5) eps=1d-20 48 | if (i.eq.6) eps=1d-24 49 | if (i.eq.7) eps=1d-28 50 | if (i.eq.8) eps=1d-32 51 | print*,' ' 52 | print*,' Requested precision eps =',eps 53 | print*,' ' 54 | c 55 | c ----------------------- 56 | c call 1D Type1 method 57 | c ----------------------- 58 | c 59 | call dirft1d1(nj,xj,cj,iflag, ms,fk0) 60 | call nufft1d1(nj,xj,cj,iflag,eps,ms,fk1,fw,lw,lused,ier) 61 | call errcomp(fk0,fk1,ms,err) 62 | print *,' ier = ',ier 63 | print *,' type 1 error = ',err 64 | print *,' lused is = ',lused 65 | c 66 | c ----------------------- 67 | c call 1D Type2 method 68 | c ----------------------- 69 | c 70 | call dirft1d2(nj,xj,cj0,iflag, ms,fk0,ier) 71 | call nufft1d2(nj,xj,cj1,iflag,eps,ms,fk0,fw,lw,lused,ier) 72 | call errcomp(cj0,cj1,nj,err) 73 | print *,' ier = ',ier 74 | print *,' type 2 error = ',err 75 | print *,' lused is = ',lused 76 | c 77 | c ----------------------- 78 | c call 1D Type3 method 79 | c ----------------------- 80 | do k1 = 1, ms 81 | sk(k1) = 48*dcos(k1*pi/ms) 82 | enddo 83 | call dirft1d3(nj,xj,cj,iflag, ms,sk,fk0) 84 | call nufft1d3(nj,xj,cj,iflag,eps,ms,sk,fk1,fw,lw,lused,ier) 85 | call errcomp(cj0,cj1,nj,err) 86 | print *,' ier = ',ier 87 | print *,' type 3 error = ',err 88 | print *,' lused is = ',lused 89 | enddo 90 | stop 91 | end 92 | c 93 | c 94 | c 95 | c 96 | c 97 | subroutine errcomp(fk0,fk1,n,err) 98 | implicit none 99 | integer k,n 100 | complex*16 fk0(n), fk1(n) 101 | real *8 salg,ealg,err 102 | c 103 | ealg = 0d0 104 | salg = 0d0 105 | do k = 1, n 106 | ealg = ealg + cdabs(fk1(k)-fk0(k))**2 107 | salg = salg + cdabs(fk0(k))**2 108 | enddo 109 | err =sqrt(ealg/salg) 110 | return 111 | end 112 | -------------------------------------------------------------------------------- /src/nufft/nufft1d_demof90.f: -------------------------------------------------------------------------------- 1 | cc Copyright (C) 2004-2009: Leslie Greengard and June-Yub Lee 2 | cc Contact: greengard@cims.nyu.edu 3 | cc 4 | cc This software is being released under a FreeBSD license 5 | cc (see license.txt in this directory). 6 | c 7 | program testfft 8 | implicit none 9 | c 10 | c --- local variables 11 | c 12 | integer i,ier,iflag,j,k1,mx,ms,nj 13 | parameter (mx=10 000) 14 | real*8 xj(mx), sk(mx) 15 | real*8 err,eps,pi 16 | parameter (pi=3.141592653589793238462643383279502884197d0) 17 | complex*16 cj(mx),cj0(mx),cj1(mx) 18 | complex*16 fk0(mx),fk1(mx) 19 | c 20 | c -------------------------------------------------- 21 | c create some test data 22 | c -------------------------------------------------- 23 | ms = 90 24 | nj = 128 25 | do k1 = -nj/2, (nj-1)/2 26 | j = k1+nj/2+1 27 | xj(j) = pi * dcos(-pi*j/nj) 28 | cj(j) = dcmplx( dsin(pi*j/nj), dcos(pi*j/nj)) 29 | enddo 30 | c 31 | c -------------------------------------------------- 32 | c start tests 33 | c -------------------------------------------------- 34 | c 35 | iflag = 1 36 | print*,' Start 1D testing: ', ' nj =',nj, ' ms =',ms 37 | do i = 1,4 38 | if (i.eq.1) eps=1d-4 39 | if (i.eq.2) eps=1d-8 40 | if (i.eq.3) eps=1d-12 41 | if (i.eq.4) eps=1d-16 42 | c extended/quad precision tests 43 | if (i.eq.5) eps=1d-20 44 | if (i.eq.6) eps=1d-24 45 | if (i.eq.7) eps=1d-28 46 | if (i.eq.8) eps=1d-32 47 | print*,' ' 48 | print*,' Requested precision eps =',eps 49 | print*,' ' 50 | c 51 | c ----------------------- 52 | c call 1D Type1 method 53 | c ----------------------- 54 | c 55 | call dirft1d1(nj,xj,cj,iflag, ms,fk0) 56 | call nufft1d1f90(nj,xj,cj,iflag,eps, ms,fk1,ier) 57 | call errcomp(fk0,fk1,ms,err) 58 | print *,' ier = ',ier 59 | print *,' type 1 error = ',err 60 | c 61 | c ----------------------- 62 | c call 1D Type2 method 63 | c ----------------------- 64 | c 65 | call dirft1d2(nj,xj,cj0,iflag, ms,fk0,ier) 66 | call nufft1d2f90(nj,xj,cj1,iflag, eps, ms,fk0,ier) 67 | call errcomp(cj0,cj1,nj,err) 68 | print *,' ier = ',ier 69 | print *,' type 2 error = ',err 70 | c 71 | c ----------------------- 72 | c call 1D Type3 method 73 | c ----------------------- 74 | do k1 = 1, ms 75 | sk(k1) = 48*dcos(k1*pi/ms) 76 | enddo 77 | call dirft1d3(nj,xj,cj,iflag, ms,sk,fk0) 78 | call nufft1d3f90(nj,xj,cj,iflag,eps, ms,sk,fk1,ier) 79 | call errcomp(cj0,cj1,nj,err) 80 | print *,' ier = ',ier 81 | print *,' type 3 error = ',err 82 | enddo 83 | stop 84 | end 85 | c 86 | c 87 | c 88 | c 89 | c 90 | subroutine errcomp(fk0,fk1,n,err) 91 | implicit none 92 | integer k,n 93 | complex*16 fk0(n), fk1(n) 94 | real *8 salg,ealg,err 95 | c 96 | ealg = 0d0 97 | salg = 0d0 98 | do k = 1, n 99 | ealg = ealg + cdabs(fk1(k)-fk0(k))**2 100 | salg = salg + cdabs(fk0(k))**2 101 | enddo 102 | err =sqrt(ealg/salg) 103 | return 104 | end 105 | -------------------------------------------------------------------------------- /src/nufft/nufft1df77.f: -------------------------------------------------------------------------------- 1 | cc Copyright (C) 2004-2009: Leslie Greengard and June-Yub Lee 2 | cc Contact: greengard@cims.nyu.edu 3 | cc 4 | cc This software is being released under a FreeBSD license 5 | cc (see license.txt in this directory). 6 | c 7 | c NUFFT 1.3 release notes: 8 | c 9 | c These codes are asymptotically fast (O(N log N)), but not optimized. 10 | c 11 | c 1) We initialize the FFT on every call. 12 | c 13 | c 2) We do not precompute the exponentials involved in "fast Gaussian 14 | c gridding". 15 | c 16 | c 3) We do not block structure the code so that irregularly placed points 17 | c are interpolated (gridded) in a cache-aware fashion. 18 | c 19 | c 4) We use dfftpack.f from Netlib for FFT (http://www.netlib.org) 20 | c rather than the state of the art FFTW package (www.fftw.org). 21 | c 22 | c Different applications have different needs, and we have chosen 23 | c to provide the simplest code as a reasonable efficient template. 24 | c 25 | c********************************************************************** 26 | subroutine nufft1d1(nj,xj,cj,iflag,eps,ms,fk,fw,lw,lused,ier) 27 | implicit none 28 | integer ier,iflag,istart,iw1,iwsav 29 | integer j,jb1,jb1u,jb1d,k1,lused,lw,ms,next235,nf1,nj,nspread 30 | real*8 cross,cross1,diff1,eps,hx,pi,rat,r2lamb,t1,tau 31 | real*8 xc(-147:147),xj(nj) 32 | real*8 fw(0:lw-1) 33 | parameter (pi=3.141592653589793238462643383279502884197d0) 34 | complex*16 cj(nj),fk(-ms/2:(ms-1)/2),zz,ccj 35 | c ---------------------------------------------------------------------- 36 | c if (iflag .ge. 0) then 37 | c 38 | c 1 nj 39 | c fk(k1) = -- SUM cj(j) exp(+i k1 xj(j)) for -ms/2 <= k1 <= (ms-1)/2 40 | c nj j=1 41 | c 42 | c else 43 | c 44 | c 1 nj 45 | c fk(k1) = -- SUM cj(j) exp(-i k1 xj(j)) for -ms/2 <= k1 <= (ms-1)/2 46 | c nj j=1 47 | c 48 | c References: 49 | c 50 | c [DR] Fast Fourier transforms for nonequispaced data, 51 | c A. Dutt and V. Rokhlin, SIAM J. Sci. Comput. 14, 52 | c 1368-1383, 1993. 53 | c 54 | c [GL] Accelerating the Nonuniform Fast Fourier Transform, 55 | c L. Greengard and J.-Y. Lee, SIAM Review 46, 443-454 (2004). 56 | c 57 | c ---------------------------------------------------------------------- 58 | c INPUT: 59 | c 60 | c nj number of sources (integer) 61 | c xj location of sources (real *8) 62 | c 63 | c on interval [-pi,pi]. 64 | c 65 | c cj strengths of sources (complex *16) 66 | c iflag determines sign of FFT (see above) 67 | c eps precision request (between 1.0d-33 and 1.0d-1) 68 | c recomended value is 1d-15 for double precision calculations 69 | c ms number of Fourier modes computed (-ms/2 to (ms-1)/2 ) 70 | c 71 | c OUTPUT: 72 | c 73 | c fk Fourier transform values (complex *16) 74 | c ier error return code 75 | c 76 | c ier = 0 => normal execution. 77 | c ier = 1 => precision eps requested is out of range. 78 | c ier = 2 => insufficient workspace 79 | c 80 | c The type 1 NUFFT proceeds in three steps (see [GL]). 81 | c 82 | c 1) spread data to oversampled regular mesh using convolution with 83 | c a Gaussian 84 | c 2) compute FFT on uniform mesh 85 | c 3) deconvolve each Fourier mode independently 86 | c (mutiplying by Fourier transform of Gaussian). 87 | c 88 | c ---------------------------------------------------------------------- 89 | c 90 | c The oversampled regular mesh is defined by 91 | c 92 | c nf1 = rat*ms points, where rat is the oversampling ratio. 93 | c 94 | c For simplicity, we set 95 | c 96 | c rat = 2 for eps > 1.0d-11 97 | c rat = 3 for eps <= 1.0d-11. 98 | c 99 | c The Gaussian used for convolution is: 100 | c 101 | c g(x) = exp(-x^2 / 4tau) 102 | c 103 | c It can be shown [DR] that the precision eps is achieved when 104 | c 105 | c nspread = int(-log(eps)/(pi*(rat-1d0)/(rat-.5d0)) + .5d0) 106 | c and tau is chosen as 107 | c 108 | c tau = pi*lambda/(ms**2) 109 | c lambda = nspread/(rat(rat-0.5)). 110 | c 111 | c Note that the Fourier transform of g(x) is 112 | c 113 | c G(s) = exp(-s^2 tau) = exp(-pi*lambda s^2/ms^2) 114 | c 115 | c 116 | c ---------------------------------------------------------------------- 117 | c Fast Gaussian gridding is based on the following observation. 118 | c 119 | c Let hx = 2*pi/nf1. In gridding data onto a regular mesh with 120 | c spacing nf1, we shift the source point xj by pi so 121 | c that it lies in [0,2*pi] to simplify the calculations. 122 | c Since we are viewing the function 123 | c as periodic, this has no effect on the result. 124 | c 125 | c For source (xj+pi), let kb*hx denote the closest grid point and 126 | c let kx*hx be a regular grid point within the spreading 127 | c distance. We can write 128 | c 129 | c (xj+pi) - kx*hx = kb*hx + diff*hx - kx*hx = diff*hx - (kx-kb)*hx 130 | c 131 | c where diff = (xj+pi)/hx - kb. 132 | c 133 | c Let t1 = hx*hx/(4 tau) = pi/(nf1*nf1)/lambda*ms*ms 134 | c = pi/lambda/(rat*rat) 135 | c 136 | c exp(-( (xj+pi) -kx*hx)**2 / 4 tau) 137 | c = exp(-pi/lamb/rat^2 *(diff - (kx-kb))**2) 138 | c = exp(-t1 *(diff - (kx-kb))**2) 139 | c = exp(-t1*diff**2) * exp(2*t1*diff)**k * exp(-t1*k**2) 140 | c where k = kx-kb. 141 | c 142 | c************************************************************************ 143 | c 144 | c Precision dependent parameters 145 | c 146 | c rat is oversampling parameter 147 | c nspread is number of neighbors to which Gaussian gridding is 148 | c carried out. 149 | c ------------------------------- 150 | ier = 0 151 | if ((eps.lt.1d-33).or.(eps.gt.1d-1)) then 152 | ier = 1 153 | return 154 | endif 155 | if (eps.le.1d-11) then 156 | rat = 3.0d0 157 | else 158 | rat = 2.0d0 159 | endif 160 | nspread = int(-log(eps)/(pi*(rat-1d0)/(rat-.5d0)) + .5d0) 161 | nf1 = rat*ms 162 | if (2*nspread.gt.nf1) then 163 | nf1 = next235(2d0*nspread) 164 | endif 165 | c 166 | c lambda (described above) = nspread/(rat*(rat-0.5d0)) 167 | c It is more convenient to define r2lamb = rat*rat*lambda 168 | c 169 | r2lamb = rat*rat * nspread / (rat*(rat-.5d0)) 170 | hx = 2*pi/nf1 171 | c 172 | c ----------------------------------- 173 | c Compute workspace size 174 | c ----------------------------------- 175 | iw1 = 2*nf1 176 | iwsav = iw1+nspread+1 177 | lused = iwsav+4*nf1+15 178 | if (lw .lt.lused) then 179 | ier = 2 180 | return 181 | endif 182 | c 183 | c --------------------------------------------------------------- 184 | c Precompute spreading constants and initialize fw 185 | c to hold one term needed for fast Gaussian gridding 186 | c --------------------------------------------------------------- 187 | t1 = pi/r2lamb 188 | do k1 = 1, nspread 189 | fw(iw1+k1) = exp(-t1*k1**2) 190 | enddo 191 | call dcffti(nf1,fw(iwsav)) 192 | c 193 | c --------------------------------------------------------------- 194 | c Initialize fine grid data to zero. 195 | c --------------------------------------------------------------- 196 | do k1 = 0, 2*nf1-1 197 | fw(k1) = dcmplx(0d0,0d0) 198 | enddo 199 | c 200 | c --------------------------------------------------------------- 201 | c Loop over sources (1,...,nj) 202 | c 203 | c 1. find closest mesh point (with periodic wrapping if necessary) 204 | c 2. spread source data onto nearest nspread grid points 205 | c using fast Gaussian gridding. 206 | c 207 | c The following is a little hard to read because it takes 208 | c advantage of fast gridding and optimized to minimize the 209 | c the number of multiplies in the inner loops. 210 | c 211 | c --------------------------------------------------------------- 212 | c 213 | do j = 1, nj 214 | ccj = cj(j)/dble(nj) 215 | 216 | jb1 = int((xj(j)+pi)/hx) 217 | diff1 = (xj(j)+pi)/hx - jb1 218 | jb1 = mod(jb1, nf1) 219 | if (jb1.lt.0) jb1=jb1+nf1 220 | c 221 | xc(0) = exp(-t1*diff1**2) 222 | cross = xc(0) 223 | cross1 = exp(2d0*t1 * diff1) 224 | do k1 = 1, nspread 225 | cross = cross * cross1 226 | xc(k1) = fw(iw1+k1)*cross 227 | enddo 228 | cross = xc(0) 229 | cross1 = 1d0/cross1 230 | do k1 = 1, nspread-1 231 | cross = cross * cross1 232 | xc(-k1) = fw(iw1+k1)*cross 233 | enddo 234 | c 235 | jb1d = min(nspread-1, jb1) 236 | jb1u = min(nspread, nf1-jb1-1) 237 | do k1 = -nspread+1, -jb1d-1 238 | istart = 2*(jb1+k1+nf1) 239 | zz=xc(k1)*ccj 240 | fw(istart)=fw(istart)+dreal(zz) 241 | fw(istart+1)=fw(istart+1)+dimag(zz) 242 | enddo 243 | do k1 = -jb1d, jb1u 244 | istart = 2*(jb1+k1) 245 | zz=xc(k1)*ccj 246 | fw(istart)=fw(istart)+dreal(zz) 247 | fw(istart+1)=fw(istart+1)+dimag(zz) 248 | enddo 249 | do k1 = jb1u+1, nspread 250 | istart = 2*(jb1+k1-nf1) 251 | zz=xc(k1)*ccj 252 | fw(istart)=fw(istart)+dreal(zz) 253 | fw(istart+1)=fw(istart+1)+dimag(zz) 254 | enddo 255 | enddo 256 | c 257 | c --------------------------------------------------------------- 258 | c Compute 1D FFT and carry out deconvolution. 259 | c 260 | c There is a factor of (-1)**k1 needed to account for the 261 | c FFT phase shift. 262 | c --------------------------------------------------------------- 263 | c 264 | if (iflag .ge. 0) then 265 | call dcfftb(nf1,fw(0),fw(iwsav)) 266 | else 267 | call dcfftf(nf1,fw(0),fw(iwsav)) 268 | endif 269 | c 270 | tau = pi * r2lamb / dble(nf1)**2 271 | cross1 = 1d0/sqrt(r2lamb) 272 | zz = dcmplx(fw(0),fw(1)) 273 | fk(0) = cross1*zz 274 | do k1 = 1, (ms-1)/2 275 | cross1 = -cross1 276 | cross = cross1*exp(tau*dble(k1)**2) 277 | zz = dcmplx(fw(2*k1),fw(2*k1+1)) 278 | fk(k1) = cross*zz 279 | zz = dcmplx(fw(2*(nf1-k1)),fw(2*(nf1-k1)+1)) 280 | fk(-k1) = cross*zz 281 | enddo 282 | if (ms/2*2.eq.ms) then 283 | cross = -cross1*exp(tau*dble(ms/2)**2) 284 | zz = dcmplx(fw(2*nf1-ms),fw(2*nf1-ms+1)) 285 | fk(-ms/2) = cross*zz 286 | endif 287 | return 288 | end 289 | c 290 | c 291 | c 292 | c 293 | c 294 | ************************************************************************ 295 | subroutine nufft1d2(nj,xj,cj, iflag,eps, ms,fk,fw,lw,lused,ier) 296 | implicit none 297 | integer ier,iflag,iw1,iwsav,j,jb1,jb1u,jb1d,k1,lused,lw 298 | integer ms,next235,nf1,nj,nspread,nw 299 | real*8 cross,cross1,diff1,eps,hx,pi,rat,r2lamb,t1 300 | real*8 xj(nj),xc(-147:147) 301 | real*8 fw(0:lw-1) 302 | parameter (pi=3.141592653589793238462643383279502884197d0) 303 | complex*16 cj(nj), fk(-ms/2:(ms-1)/2) 304 | complex*16 zz 305 | c ---------------------------------------------------------------------- 306 | c if (iflag .ge. 0) then 307 | c 308 | c (ms-1)/2 309 | c cj(j) = SUM fk(k1) exp(+i k1 xj(j)) for j = 1,...,nj 310 | c k1= -ms/2 311 | c 312 | c else 313 | c 314 | c (ms-1)/2 315 | c cj(j) = SUM fk(k1) exp(-i k1 xj(j)) for j = 1,...,nj 316 | c k1= -ms/2 317 | c 318 | c ---------------------------------------------------------------------- 319 | c INPUT: 320 | c 321 | c nj number of output values (integer) 322 | c xj location of output values (real *8 array) 323 | c iflag determines sign of FFT (see above) 324 | c eps precision request (between 1.0d-33 and 1.0d-1) 325 | c recomended value is 1d-15 for double precision calculations 326 | c ms number of Fourier modes given [ -ms/2: (ms-1)/2 ] 327 | c fk Fourier coefficient values (complex *16 array) 328 | c 329 | c OUTPUT: 330 | c 331 | c cj output values (complex *16 array) 332 | c ier error return code 333 | c 334 | c ier = 0 => normal execution. 335 | c ier = 1 => precision eps requested is out of range. 336 | c 337 | c 338 | c The type 2 algorithm proceeds in three steps (see [GL]). 339 | c 340 | c 1) deconvolve (amplify) each Fourier mode first 341 | c 2) compute inverse FFT on uniform fine grid 342 | c 3) spread data to regular mesh using Gaussian 343 | c 344 | c 345 | c See subroutine nufft1d1f90(nj,xj,cj,iflag,eps,ms,fk,ier) 346 | c for more comments on fast gridding and parameter selection. 347 | c 348 | ************************************************************************ 349 | c 350 | c Precision dependent parameters 351 | c 352 | c rat is oversampling parameter 353 | c nspread is number of neighbors to which Gaussian gridding is 354 | c carried out. 355 | c ------------------------------- 356 | ier = 0 357 | if ((eps.lt.1d-33).or.(eps.gt.1d-1)) then 358 | ier = 1 359 | return 360 | endif 361 | if (eps.le.1d-11) then 362 | rat = 3.0d0 363 | else 364 | rat = 2.0d0 365 | endif 366 | nspread = int(-log(eps)/(pi*(rat-1d0)/(rat-.5d0)) + .5d0) 367 | nf1 = rat*ms 368 | if (2*nspread.gt.nf1) then 369 | nf1 = next235(2d0*nspread) 370 | endif 371 | c 372 | c lambda (described above) = nspread/(rat*(rat-0.5d0)) 373 | c It is more convenient to define r2lamb = rat*rat*lambda 374 | c 375 | c ------------------------------- 376 | ier = 0 377 | if ((eps.lt.1d-33).or.(eps.gt.1d-1)) then 378 | ier = 1 379 | return 380 | endif 381 | if (eps.le.1d-11) then 382 | rat = 3.0d0 383 | else 384 | rat = 2.0d0 385 | endif 386 | c 387 | nspread = int(-log(eps)/(pi*(rat-1d0)/(rat-.5d0)) + .5d0) 388 | nf1 = rat*ms 389 | if (2*nspread.gt.nf1) then 390 | nf1 = next235(2d0*nspread) 391 | endif 392 | c 393 | r2lamb = rat*rat * nspread / (rat*(rat-.5d0)) 394 | hx = 2*pi/nf1 395 | c 396 | c ----------------------------------- 397 | c Compute workspace size 398 | c ----------------------------------- 399 | iw1 = 2*nf1 400 | iwsav = iw1 + nspread+1 401 | lused = iwsav + 4*nf1 + 15 402 | if (lw .lt.lused) then 403 | ier = 2 404 | return 405 | endif 406 | c 407 | c --------------------------------------------------------------- 408 | c Precompute spreading constants and initialize fw 409 | c to hold one term needed for fast Gaussian gridding 410 | c --------------------------------------------------------------- 411 | t1 = pi/r2lamb 412 | do k1 = 1, nspread 413 | fw(iw1+k1) = exp(-t1*k1**2) 414 | enddo 415 | call dcffti(nf1,fw(iwsav)) 416 | c 417 | c --------------------------------------------------------------- 418 | c Deconvolve and compute inverse 1D FFT 419 | c (A factor of (-1)**k is needed to shift phase.) 420 | c --------------------------------------------------------------- 421 | c 422 | t1 = pi * r2lamb / dble(nf1)**2 423 | cross1 = 1d0/sqrt(r2lamb) 424 | zz = cross1*fk(0) 425 | fw(0) = dreal(zz) 426 | fw(1) = dimag(zz) 427 | do k1 = 1, (ms-1)/2 428 | cross1 = -cross1 429 | cross = cross1*exp(t1*dble(k1)**2) 430 | zz = cross*fk(k1) 431 | fw(2*k1) = dreal(zz) 432 | fw(2*k1+1) = dimag(zz) 433 | zz = cross*fk(-k1) 434 | fw(2*(nf1-k1)) = dreal(zz) 435 | fw(2*(nf1-k1)+1) = dimag(zz) 436 | enddo 437 | cross = -cross1*exp(t1*dble(ms/2)**2) 438 | if (ms/2*2.eq.ms) then 439 | zz = cross*fk(-ms/2) 440 | fw(2*nf1-ms) = dreal(zz) 441 | fw(2*nf1-ms+1) = dimag(zz) 442 | endif 443 | do k1 = (ms+1)/2, nf1-ms/2-1 444 | fw(2*k1) = dcmplx(0d0, 0d0) 445 | fw(2*k1+1) = dcmplx(0d0, 0d0) 446 | enddo 447 | c 448 | if (iflag .ge. 0) then 449 | call dcfftb(nf1,fw(0),fw(iwsav)) 450 | else 451 | call dcfftf(nf1,fw(0),fw(iwsav)) 452 | endif 453 | c 454 | c --------------------------------------------------------------- 455 | c Loop over target points (1,...,nj) 456 | c 457 | c 1. find closest mesh point (with periodic wrapping if needed) 458 | c 2. get contributions from regular fine grid to target 459 | c locations using Gaussian convolution. 460 | c --------------------------------------------------------------- 461 | t1 = pi/r2lamb 462 | do j = 1, nj 463 | cj(j) = dcmplx(0d0,0d0) 464 | jb1 = int((xj(j)+pi)/hx) 465 | diff1 = (xj(j)+pi)/hx - jb1 466 | jb1 = mod(jb1, nf1) 467 | if (jb1.lt.0) jb1=jb1+nf1 468 | xc(0) = exp(-t1*diff1**2) 469 | cross = xc(0) 470 | cross1 = exp(2d0*t1 * diff1) 471 | do k1 = 1, nspread 472 | cross = cross * cross1 473 | xc(k1) = fw(iw1+k1)*cross 474 | enddo 475 | cross = xc(0) 476 | cross1 = 1d0/cross1 477 | do k1 = 1, nspread-1 478 | cross = cross * cross1 479 | xc(-k1) = fw(iw1+k1)*cross 480 | enddo 481 | c 482 | jb1d = min(nspread-1, jb1) 483 | jb1u = min(nspread, nf1-jb1-1) 484 | do k1 = -nspread+1, -jb1d-1 485 | zz = dcmplx(fw(2*(jb1+k1+nf1)),fw(2*(jb1+k1+nf1)+1)) 486 | cj(j) = cj(j) + xc(k1)*zz 487 | enddo 488 | do k1 = -jb1d, jb1u 489 | zz = dcmplx(fw(2*(jb1+k1)),fw(2*(jb1+k1)+1)) 490 | cj(j) = cj(j) + xc(k1)*zz 491 | enddo 492 | do k1 = jb1u+1, nspread 493 | zz = dcmplx(fw(2*(jb1+k1-nf1)),fw(2*(jb1+k1-nf1)+1)) 494 | cj(j) = cj(j) + xc(k1)*zz 495 | enddo 496 | enddo 497 | return 498 | end 499 | c 500 | c 501 | c 502 | c 503 | c 504 | c 505 | ************************************************************************ 506 | subroutine nufft1d3(nj,xj,cj,iflag,eps,nk,sk,fk,fw,lw,lused,ier) 507 | implicit none 508 | integer ier,iflag,istart,iw1,iwsave,j,jb1,k1,kb1,kmax 509 | integer lused,lw,next235,nf1,nj,nk,nspread 510 | real*8 ang,cross,cross1,diff1,eps,hx,hs,rat,pi,r2lamb1 511 | real*8 sm,sb,t1,t2,xm,xb 512 | real*8 xc(-147:147), xj(nj), sk(nk) 513 | real*8 fw(0:lw-1) 514 | parameter (pi=3.141592653589793238462643383279502884197d0) 515 | complex*16 cj(nj), fk(nk), zz, cs 516 | c 517 | c ---------------------------------------------------------------------- 518 | c if (iflag .ge. 0) then 519 | c 520 | c nj 521 | c fk(sk(k)) = SUM cj(j) exp(+i sk(k) xj(j)) for k = 1,..., nk 522 | c j=1 523 | c 524 | c else 525 | c 526 | c nj 527 | c fk(sk(k)) = SUM cj(j) exp(-i sk(k) xj(j)) for k = 1,..., nk 528 | c j=1 529 | c ---------------------------------------------------------------------- 530 | c INPUT: 531 | c 532 | c nj number of sources (integer) 533 | c xj location of sources (double array) 534 | c cj strengths of sources (double complex array) 535 | c iflag determines sign of FFT (see above) 536 | c eps precision request (between 1.0d-33 and 1.0d-1) 537 | c recomended value is 1d-15 for double precision calculations 538 | c nk number of (noninteger) Fourier modes computed 539 | c sk k-values (locations) of desired Fourier modes 540 | c 541 | c OUTPUT: 542 | c 543 | c fk Fourier transform values (double complex array) 544 | c ier error return code 545 | c 546 | c ier = 0 => normal execution. 547 | c ier = 1 => precision eps requested is out of range. 548 | c 549 | c 550 | c References: 551 | c 552 | c [DR] Fast Fourier transforms for nonequispaced data, 553 | c A. Dutt and V. Rokhlin, SIAM J. Sci. Comput. 14, 554 | c 1368-1383, 1993. 555 | c 556 | c [LG] The type 3 nonuniform FFT and its applications 557 | c J.-Y. Lee and L. Greengard, J. Comput. Phys. 206, 1-5 (2005). 558 | c 559 | c The algorithm is essentially a concatenation of the 560 | c type 1 and 2 transforms. 561 | c 562 | c 1) Gaussian gridding of strengths cj(j) centered at xj 563 | c to create f_\tau(n \Delta_x) (in notation of [LG]) 564 | c 2) Deconvolve each regular grid mode 565 | c to create f^{-\sigma}_\tau(n \Delta_x) (in notation of [LG]) 566 | c 3) compute FFT on uniform mesh 567 | c to create F^{-\sigma}_\tau(m \Delta_s) (in notation of [LG]) 568 | c 4) Gaussian gridding to irregular frequency points 569 | c to create F_\tau(s_k) (in notation of [LG]) 570 | c 5) Deconvolution of result 571 | c to create F(s_k) (in notation of [LG]) 572 | c 573 | c*********************************************************************** 574 | ier = 0 575 | if ((eps.lt.1d-33).or.(eps.gt.1d-1)) then 576 | ier = 1 577 | return 578 | endif 579 | c 580 | c --- Check the ranges of {xj}/{sk} and the workspace size 581 | c 582 | t1 = xj(1) 583 | t2 = xj(1) 584 | do j = 2, nj 585 | if (xj(j).gt.t2) then 586 | t2=xj(j) 587 | else if (xj(j).lt.t1) then 588 | t1=xj(j) 589 | endif 590 | enddo 591 | xb = (t1+t2) / 2d0 592 | xm = max(t2-xb,-t1+xb) ! max(abs(t2-xb),abs(t1-xb)) 593 | c 594 | t1 = sk(1) 595 | t2 = sk(1) 596 | do k1 = 2, nk 597 | if (sk(k1).gt.t2) then 598 | t2=sk(k1) 599 | else if (sk(k1).lt.t1) then 600 | t1=sk(k1) 601 | endif 602 | enddo 603 | sb = (t1+t2) / 2d0 604 | sm = max(t2-sb,-t1+sb) 605 | c 606 | c ------------------------------- 607 | c Precision dependent parameters 608 | c 609 | c rat is oversampling parameter 610 | c nspread is number of neighbors to which Gaussian gridding is 611 | c carried out. 612 | c ------------------------------- 613 | if (eps.le.1d-11) then 614 | rat = sqrt(3.0d0) 615 | else 616 | rat = sqrt(2.0d0) 617 | endif 618 | c 619 | nspread = int(-log(eps)/(pi*(rat-1d0)/(rat-.5d0)) + .5d0) 620 | t1 = 2d0/pi * xm*sm 621 | nf1 = next235(rat*max(rat*t1+2*nspread,2*nspread/(rat-1))) 622 | rat = (sqrt(nf1*t1+nspread**2)-nspread)/t1 623 | c 624 | r2lamb1 = rat*rat * nspread / (rat*(rat-.5d0)) 625 | hx = pi/(rat*sm) 626 | hs = 2d0*pi/dble(nf1)/hx ! hx hs = 2.pi/nf1 627 | c 628 | c ------------------------------- 629 | c Compute workspace size 630 | c ------------------------------- 631 | c 632 | kmax = int(nf1*(r2lamb1-nspread)/r2lamb1+.1d0) 633 | iw1 = 2*nf1 634 | iwsave = iw1 + nspread+1 635 | lused = iwsave + 16+4*nf1 636 | if (lw .lt.lused) then 637 | ier = 2 638 | return 639 | endif 640 | c 641 | c --------------------------------------------------------------- 642 | c Precompute spreading constants and initialize fw 643 | c to hold one term needed for fast Gaussian gridding 644 | c --------------------------------------------------------------- 645 | c 646 | t1 = pi/r2lamb1 647 | do k1 = 1, nspread 648 | fw(iw1+k1) = exp(-t1*k1**2) 649 | enddo 650 | c 651 | call dcffti(nf1,fw(iwsave)) 652 | c 653 | c --------------------------------------------------------------- 654 | c Initialize fine grid data to zero. 655 | c --------------------------------------------------------------- 656 | do k1 = 0, 2*nf1-1 657 | fw(k1) = dcmplx(0d0,0d0) 658 | enddo 659 | c 660 | c --------------------------------------------------------------- 661 | c Step 1/5 - gridding as in type 1 transform. 662 | c --------------------------------------------------------------- 663 | c 664 | t1 = pi/r2lamb1 665 | if (iflag .lt. 0) sb = -sb 666 | do j = 1, nj 667 | jb1 = int(dble(nf1/2) + (xj(j)-xb)/hx) 668 | diff1 = dble(nf1/2) + (xj(j)-xb)/hx - jb1 669 | ang = sb*xj(j) 670 | cs = dcmplx(cos(ang),sin(ang)) * cj(j) 671 | 672 | xc(0) = exp(-t1*diff1**2) 673 | cross = xc(0) 674 | cross1 = exp(2d0*t1 * diff1) 675 | do k1 = 1, nspread 676 | cross = cross * cross1 677 | xc(k1) = fw(iw1+k1)*cross 678 | enddo 679 | cross = xc(0) 680 | cross1 = 1d0/cross1 681 | do k1 = 1, nspread-1 682 | cross = cross * cross1 683 | xc(-k1) = fw(iw1+k1)*cross 684 | enddo 685 | 686 | do k1 = -nspread+1, nspread 687 | istart = 2*(jb1+k1) 688 | zz = xc(k1)*cs 689 | fw(istart) = fw(istart) + dreal(zz) 690 | fw(istart+1) = fw(istart+1) + dimag(zz) 691 | enddo 692 | enddo 693 | if (iflag .lt. 0) sb = -sb 694 | c 695 | c --------------------------------------------------------------- 696 | c Step 2: Deconvolve (amplify) as in Type 2 transform 697 | c Step 3: Compute FFT with shift 698 | c (-1)^k F_(k+M/2) = Sum (-1)^j F_(j+M/2) e(2pi ijk/M) 699 | c --------------------------------------------------------------- 700 | c 701 | t1 = pi * r2lamb1 / dble(nf1)**2 702 | cross1 = (1d0-2d0*mod(nf1/2,2))/r2lamb1 703 | zz = dcmplx(fw(nf1),fw(nf1+1)) 704 | zz = cross1*zz 705 | fw(nf1) = dreal(zz) 706 | fw(nf1+1) = dimag(zz) 707 | do k1 = 1, kmax 708 | cross1 = -cross1 709 | cross = cross1*exp(t1*dble(k1)**2) 710 | zz = dcmplx(fw(nf1-2*k1),fw(nf1-2*k1+1)) 711 | zz = cross*zz 712 | fw(nf1-2*k1) = dreal(zz) 713 | fw(nf1-2*k1+1) = dimag(zz) 714 | zz = dcmplx(fw(nf1+2*k1),fw(nf1+2*k1+1)) 715 | zz = cross*zz 716 | fw(nf1+2*k1) = dreal(zz) 717 | fw(nf1+2*k1+1) = dimag(zz) 718 | enddo 719 | c 720 | if (iflag .ge. 0) then 721 | call dcfftb(nf1,fw(0),fw(iwsave)) 722 | else 723 | call dcfftf(nf1,fw(0),fw(iwsave)) 724 | endif 725 | do k1 = 1, kmax+nspread, 2 726 | fw(nf1+2*k1) = -fw(nf1+2*k1) 727 | fw(nf1+2*k1+1) = -fw(nf1+2*k1+1) 728 | fw(nf1-2*k1) = -fw(nf1-2*k1) 729 | fw(nf1-2*k1+1) = -fw(nf1-2*k1+1) 730 | enddo 731 | c 732 | c --------------------------------------------------------------- 733 | c Step 4 Gaussian gridding to irregular points 734 | c Step 5 Final deconvolution 735 | c --------------------------------------------------------------- 736 | t1 = pi/r2lamb1 737 | do j = 1, nk 738 | kb1 = int(dble(nf1/2) + (sk(j)-sb)/hs) 739 | diff1 = dble(nf1/2) + (sk(j)-sb)/hs - kb1 740 | 741 | ! exp(-t1*(diff1-k1)**2) = xc(k1) 742 | xc(0) = exp(-t1*diff1**2) 743 | cross = xc(0) 744 | cross1 = exp(2d0*t1 * diff1) 745 | do k1 = 1, nspread 746 | cross = cross * cross1 747 | xc(k1) = fw(iw1+k1)*cross 748 | enddo 749 | cross = xc(0) 750 | cross1 = 1d0/cross1 751 | do k1 = 1, nspread-1 752 | cross = cross * cross1 753 | xc(-k1) = fw(iw1+k1)*cross 754 | enddo 755 | c 756 | fk(j) = dcmplx(0d0,0d0) 757 | do k1 = -nspread+1, nspread 758 | zz = dcmplx(fw(2*(kb1+k1)),fw(2*(kb1+k1)+1)) 759 | fk(j) = fk(j) + xc(k1)*zz 760 | enddo 761 | enddo 762 | c 763 | if (iflag .lt. 0) xb = -xb 764 | t1 = r2lamb1/(4d0*pi) * hx**2 765 | do j = 1, nk 766 | fk(j) = (exp(t1*(sk(j)-sb)**2))*fk(j) 767 | ang = (sk(j)-sb)*xb 768 | fk(j) = dcmplx(cos(ang),sin(ang)) * fk(j) 769 | enddo 770 | return 771 | end 772 | -------------------------------------------------------------------------------- /src/nufft/nufft1df90.f: -------------------------------------------------------------------------------- 1 | cc Copyright (C) 2004-2009: Leslie Greengard and June-Yub Lee 2 | cc Contact: greengard@cims.nyu.edu 3 | cc 4 | cc This software is being released under a FreeBSD license 5 | cc (see license.txt in this directory). 6 | cc 7 | c 8 | c NUFFT 1.3 release notes: 9 | c 10 | c These codes are asymptotically fast (O(N log N)), but not optimized. 11 | c 12 | c 1) We initialize the FFT on every call. 13 | c 14 | c 2) We do not precompute the exponentials involved in "fast Gaussian 15 | c gridding". 16 | c 17 | c 3) We do not block structure the code so that irregularly placed points 18 | c are interpolated (gridded) in a cache-aware fashion. 19 | c 20 | c 4) We use the Netlib FFT library (www.netlib.org) 21 | c rather than the state of the art FFTW package (www.fftw.org). 22 | c 23 | c Different applications have different needs, and we have chosen 24 | c to provide the simplest code as a reasonable efficient template. 25 | c 26 | c********************************************************************** 27 | subroutine nufft1d1f90(nj,xj,cj,iflag,eps,ms,fk,ier) 28 | implicit none 29 | integer ier,iflag,istart,iw1,iwtot,iwsav 30 | integer j,jb1,jb1u,jb1d,k1,ms,next235,nf1,nj,nspread 31 | real*8 cross,cross1,diff1,eps,hx,pi,rat,r2lamb,t1,tau 32 | real*8 xc(-147:147),xj(nj) 33 | parameter (pi=3.141592653589793238462643383279502884197d0) 34 | complex*16 cj(nj),fk(-ms/2:(ms-1)/2),zz,ccj 35 | c ---------------------------------------------------------------------- 36 | real*8, allocatable :: fw(:) 37 | c ---------------------------------------------------------------------- 38 | c if (iflag .ge. 0) then 39 | c 40 | c 1 nj 41 | c fk(k1) = -- SUM cj(j) exp(+i k1 xj(j)) for -ms/2 <= k1 <= (ms-1)/2 42 | c nj j=1 43 | c 44 | c else 45 | c 46 | c 1 nj 47 | c fk(k1) = -- SUM cj(j) exp(-i k1 xj(j)) for -ms/2 <= k1 <= (ms-1)/2 48 | c nj j=1 49 | c 50 | c References: 51 | c 52 | c [DR] Fast Fourier transforms for nonequispaced data, 53 | c A. Dutt and V. Rokhlin, SIAM J. Sci. Comput. 14, 54 | c 1368-1383, 1993. 55 | c 56 | c [GL] Accelerating the Nonuniform Fast Fourier Transform, 57 | c L. Greengard and J.-Y. Lee, SIAM Review 46, 443-454 (2004). 58 | c 59 | c ---------------------------------------------------------------------- 60 | c INPUT: 61 | c 62 | c nj number of sources (integer) 63 | c xj location of sources (real *8) 64 | c 65 | c on interval [-pi,pi]. 66 | c 67 | c cj strengths of sources (complex *16) 68 | c iflag determines sign of FFT (see above) 69 | c eps precision request (between 1.0d-33 and 1.0d-1) 70 | c recomended value is 1d-15 for double precision calculations 71 | c ms number of Fourier modes computed (-ms/2 to (ms-1)/2 ) 72 | c 73 | c OUTPUT: 74 | c 75 | c fk Fourier transform values (complex *16) 76 | c ier error return code 77 | c 78 | c ier = 0 => normal execution. 79 | c ier = 1 => precision eps requested is out of range. 80 | c 81 | c The type 1 NUFFT proceeds in three steps (see [GL]). 82 | c 83 | c 1) spread data to oversampled regular mesh using convolution with 84 | c a Gaussian 85 | c 2) compute FFT on uniform mesh 86 | c 3) deconvolve each Fourier mode independently 87 | c (mutiplying by Fourier transform of Gaussian). 88 | c 89 | c ---------------------------------------------------------------------- 90 | c 91 | c The oversampled regular mesh is defined by 92 | c 93 | c nf1 = rat*ms points, where rat is the oversampling ratio. 94 | c 95 | c For simplicity, we set 96 | c 97 | c rat = 2 for eps > 1.0d-11 98 | c rat = 3 for eps <= 1.0d-11. 99 | c 100 | c The Gaussian used for convolution is: 101 | c 102 | c g(x) = exp(-x^2 / 4tau) 103 | c 104 | c It can be shown [DR] that the precision eps is achieved when 105 | c 106 | c nspread = int(-log(eps)/(pi*(rat-1d0)/(rat-.5d0)) + .5d0) 107 | c and tau is chosen as 108 | c 109 | c tau = pi*lambda/(ms**2) 110 | c lambda = nspread/(rat(rat-0.5)). 111 | c 112 | c Note that the Fourier transform of g(x) is 113 | c 114 | c G(s) = exp(-s^2 tau) = exp(-pi*lambda s^2/ms^2) 115 | c 116 | c 117 | c ---------------------------------------------------------------------- 118 | c Fast Gaussian gridding is based on the following observation. 119 | c 120 | c Let hx = 2*pi/nf1. In gridding data onto a regular mesh with 121 | c spacing nf1, we shift the source point xj by pi so 122 | c that it lies in [0,2*pi] to simplify the calculations. 123 | c Since we are viewing the function 124 | c as periodic, this has no effect on the result. 125 | c 126 | c For source (xj+pi), let kb*hx denote the closest grid point and 127 | c let kx*hx be a regular grid point within the spreading 128 | c distance. We can write 129 | c 130 | c (xj+pi) - kx*hx = kb*hx + diff*hx - kx*hx = diff*hx - (kx-kb)*hx 131 | c 132 | c where diff = (xj+pi)/hx - kb. 133 | c 134 | c Let t1 = hx*hx/(4 tau) = pi/(nf1*nf1)/lambda*ms*ms 135 | c = pi/lambda/(rat*rat) 136 | c 137 | c exp(-( (xj+pi) -kx*hx)**2 / 4 tau) 138 | c = exp(-pi/lamb/rat^2 *(diff - (kx-kb))**2) 139 | c = exp(-t1 *(diff - (kx-kb))**2) 140 | c = exp(-t1*diff**2) * exp(2*t1*diff)**k * exp(-t1*k**2) 141 | c where k = kx-kb. 142 | c 143 | c************************************************************************ 144 | c 145 | c Precision dependent parameters 146 | c 147 | c rat is oversampling parameter 148 | c nspread is number of neighbors to which Gaussian gridding is 149 | c carried out. 150 | c ------------------------------- 151 | ier = 0 152 | if ((eps.lt.1d-33).or.(eps.gt.1d-1)) then 153 | ier = 1 154 | return 155 | endif 156 | if (eps.le.1d-11) then 157 | rat = 3.0d0 158 | else 159 | rat = 2.0d0 160 | endif 161 | nspread = int(-log(eps)/(pi*(rat-1d0)/(rat-.5d0)) + .5d0) 162 | nf1 = rat*ms 163 | if (2*nspread.gt.nf1) then 164 | nf1 = next235(2d0*nspread) 165 | endif 166 | c 167 | c lambda (described above) = nspread/(rat*(rat-0.5d0)) 168 | c It is more convenient to define r2lamb = rat*rat*lambda 169 | c 170 | r2lamb = rat*rat * nspread / (rat*(rat-.5d0)) 171 | hx = 2*pi/nf1 172 | c 173 | c ----------------------------------- 174 | c Compute workspace size and allocate 175 | c ----------------------------------- 176 | iw1 = 2*nf1 177 | iwsav = iw1+nspread+1 178 | iwtot = iwsav+4*nf1+15 179 | allocate ( fw(0:iwtot) ) 180 | c 181 | c --------------------------------------------------------------- 182 | c Precompute spreading constants and initialize fw 183 | c to hold one term needed for fast Gaussian gridding 184 | c --------------------------------------------------------------- 185 | t1 = pi/r2lamb 186 | do k1 = 1, nspread 187 | fw(iw1+k1) = exp(-t1*k1**2) 188 | enddo 189 | call dcffti(nf1,fw(iwsav)) 190 | c 191 | c --------------------------------------------------------------- 192 | c Initialize fine grid data to zero. 193 | c --------------------------------------------------------------- 194 | do k1 = 0, 2*nf1-1 195 | fw(k1) = dcmplx(0d0,0d0) 196 | enddo 197 | c 198 | c --------------------------------------------------------------- 199 | c Loop over sources (1,...,nj) 200 | c 201 | c 1. find closest mesh point (with periodic wrapping if necessary) 202 | c 2. spread source data onto nearest nspread grid points 203 | c using fast Gaussian gridding. 204 | c 205 | c The following is a little hard to read because it takes 206 | c advantage of fast gridding and optimized to minimize the 207 | c the number of multiplies in the inner loops. 208 | c 209 | c --------------------------------------------------------------- 210 | c 211 | do j = 1, nj 212 | ccj = cj(j)/dble(nj) 213 | 214 | jb1 = int((xj(j)+pi)/hx) 215 | diff1 = (xj(j)+pi)/hx - jb1 216 | jb1 = mod(jb1, nf1) 217 | if (jb1.lt.0) jb1=jb1+nf1 218 | c 219 | xc(0) = exp(-t1*diff1**2) 220 | cross = xc(0) 221 | cross1 = exp(2d0*t1 * diff1) 222 | do k1 = 1, nspread 223 | cross = cross * cross1 224 | xc(k1) = fw(iw1+k1)*cross 225 | enddo 226 | cross = xc(0) 227 | cross1 = 1d0/cross1 228 | do k1 = 1, nspread-1 229 | cross = cross * cross1 230 | xc(-k1) = fw(iw1+k1)*cross 231 | enddo 232 | c 233 | jb1d = min(nspread-1, jb1) 234 | jb1u = min(nspread, nf1-jb1-1) 235 | do k1 = -nspread+1, -jb1d-1 236 | istart = 2*(jb1+k1+nf1) 237 | zz=xc(k1)*ccj 238 | fw(istart)=fw(istart)+dreal(zz) 239 | fw(istart+1)=fw(istart+1)+dimag(zz) 240 | enddo 241 | do k1 = -jb1d, jb1u 242 | istart = 2*(jb1+k1) 243 | zz=xc(k1)*ccj 244 | fw(istart)=fw(istart)+dreal(zz) 245 | fw(istart+1)=fw(istart+1)+dimag(zz) 246 | enddo 247 | do k1 = jb1u+1, nspread 248 | istart = 2*(jb1+k1-nf1) 249 | zz=xc(k1)*ccj 250 | fw(istart)=fw(istart)+dreal(zz) 251 | fw(istart+1)=fw(istart+1)+dimag(zz) 252 | enddo 253 | enddo 254 | c 255 | c --------------------------------------------------------------- 256 | c Compute 1D FFT and carry out deconvolution. 257 | c 258 | c There is a factor of (-1)**k1 needed to account for the 259 | c FFT phase shift. 260 | c --------------------------------------------------------------- 261 | c 262 | if (iflag .ge. 0) then 263 | call dcfftb(nf1,fw(0),fw(iwsav)) 264 | else 265 | call dcfftf(nf1,fw(0),fw(iwsav)) 266 | endif 267 | c 268 | tau = pi * r2lamb / dble(nf1)**2 269 | cross1 = 1d0/sqrt(r2lamb) 270 | zz = dcmplx(fw(0),fw(1)) 271 | fk(0) = cross1*zz 272 | do k1 = 1, (ms-1)/2 273 | cross1 = -cross1 274 | cross = cross1*exp(tau*dble(k1)**2) 275 | zz = dcmplx(fw(2*k1),fw(2*k1+1)) 276 | fk(k1) = cross*zz 277 | zz = dcmplx(fw(2*(nf1-k1)),fw(2*(nf1-k1)+1)) 278 | fk(-k1) = cross*zz 279 | enddo 280 | if (ms/2*2.eq.ms) then 281 | cross = -cross1*exp(tau*dble(ms/2)**2) 282 | zz = dcmplx(fw(2*nf1-ms),fw(2*nf1-ms+1)) 283 | fk(-ms/2) = cross*zz 284 | endif 285 | deallocate(fw) 286 | return 287 | end 288 | c 289 | c 290 | c 291 | c 292 | c 293 | ************************************************************************ 294 | subroutine nufft1d2f90(nj,xj,cj, iflag,eps, ms,fk,ier) 295 | implicit none 296 | integer ier,iflag,iw1,iwsav,iwtot,j,jb1,jb1u,jb1d,k1 297 | integer ms,next235,nf1,nj,nspread,nw 298 | real*8 cross,cross1,diff1,eps,hx,pi,rat,r2lamb,t1 299 | real*8 xj(nj),xc(-147:147) 300 | parameter (pi=3.141592653589793238462643383279502884197d0) 301 | complex*16 cj(nj), fk(-ms/2:(ms-1)/2) 302 | complex*16 zz 303 | c ---------------------------------------------------------------------- 304 | real*8, allocatable :: fw(:) 305 | c ---------------------------------------------------------------------- 306 | c if (iflag .ge. 0) then 307 | c 308 | c (ms-1)/2 309 | c cj(j) = SUM fk(k1) exp(+i k1 xj(j)) for j = 1,...,nj 310 | c k1= -ms/2 311 | c 312 | c else 313 | c 314 | c (ms-1)/2 315 | c cj(j) = SUM fk(k1) exp(-i k1 xj(j)) for j = 1,...,nj 316 | c k1= -ms/2 317 | c 318 | c ---------------------------------------------------------------------- 319 | c INPUT: 320 | c 321 | c nj number of output values (integer) 322 | c xj location of output values (real *8 array) 323 | c iflag determines sign of FFT (see above) 324 | c eps precision request (between 1.0d-33 and 1.0d-1) 325 | c recomended value is 1d-15 for double precision calculations 326 | c ms number of Fourier modes given [ -ms/2: (ms-1)/2 ] 327 | c fk Fourier coefficient values (complex *16 array) 328 | c 329 | c OUTPUT: 330 | c 331 | c cj output values (complex *16 array) 332 | c ier error return code 333 | c 334 | c ier = 0 => normal execution. 335 | c ier = 1 => precision eps requested is out of range. 336 | c 337 | c 338 | c The type 2 algorithm proceeds in three steps (see [GL]). 339 | c 340 | c 1) deconvolve (amplify) each Fourier mode first 341 | c 2) compute inverse FFT on uniform fine grid 342 | c 3) spread data to regular mesh using Gaussian 343 | c 344 | c 345 | c See subroutine nufft1d1f90(nj,xj,cj,iflag,eps,ms,fk,ier) 346 | c for more comments on fast gridding and parameter selection. 347 | c 348 | ************************************************************************ 349 | c 350 | c Precision dependent parameters 351 | c 352 | c rat is oversampling parameter 353 | c nspread is number of neighbors to which Gaussian gridding is 354 | c carried out. 355 | c ------------------------------- 356 | c 357 | c lambda (described above) = nspread/(rat*(rat-0.5d0)) 358 | c It is more convenient to define r2lamb = rat*rat*lambda 359 | c 360 | c ------------------------------- 361 | ier = 0 362 | if ((eps.lt.1d-33).or.(eps.gt.1d-1)) then 363 | ier = 1 364 | return 365 | endif 366 | if (eps.le.1d-11) then 367 | rat = 3.0d0 368 | else 369 | rat = 2.0d0 370 | endif 371 | c 372 | nspread = int(-log(eps)/(pi*(rat-1d0)/(rat-.5d0)) + .5d0) 373 | nf1 = rat*ms 374 | if (2*nspread.gt.nf1) then 375 | nf1 = next235(2d0*nspread) 376 | endif 377 | c 378 | r2lamb = rat*rat * nspread / (rat*(rat-.5d0)) 379 | hx = 2*pi/nf1 380 | c 381 | c ----------------------------------- 382 | c Compute workspace size and allocate 383 | c ----------------------------------- 384 | iw1 = 2*nf1 385 | iwsav = iw1 + nspread+1 386 | iwtot = iwsav + 4*nf1 + 15 387 | allocate ( fw(0:iwtot)) 388 | c 389 | c --------------------------------------------------------------- 390 | c Precompute spreading constants and initialize fw 391 | c to hold one term needed for fast Gaussian gridding 392 | c --------------------------------------------------------------- 393 | t1 = pi/r2lamb 394 | do k1 = 1, nspread 395 | fw(iw1+k1) = exp(-t1*k1**2) 396 | enddo 397 | call dcffti(nf1,fw(iwsav)) 398 | c 399 | c --------------------------------------------------------------- 400 | c Deconvolve and compute inverse 1D FFT 401 | c (A factor of (-1)**k is needed to shift phase.) 402 | c --------------------------------------------------------------- 403 | c 404 | t1 = pi * r2lamb / dble(nf1)**2 405 | cross1 = 1d0/sqrt(r2lamb) 406 | zz = cross1*fk(0) 407 | fw(0) = dreal(zz) 408 | fw(1) = dimag(zz) 409 | do k1 = 1, (ms-1)/2 410 | cross1 = -cross1 411 | cross = cross1*exp(t1*dble(k1)**2) 412 | zz = cross*fk(k1) 413 | fw(2*k1) = dreal(zz) 414 | fw(2*k1+1) = dimag(zz) 415 | zz = cross*fk(-k1) 416 | fw(2*(nf1-k1)) = dreal(zz) 417 | fw(2*(nf1-k1)+1) = dimag(zz) 418 | enddo 419 | cross = -cross1*exp(t1*dble(ms/2)**2) 420 | if (ms/2*2.eq.ms) then 421 | zz = cross*fk(-ms/2) 422 | fw(2*nf1-ms) = dreal(zz) 423 | fw(2*nf1-ms+1) = dimag(zz) 424 | endif 425 | do k1 = (ms+1)/2, nf1-ms/2-1 426 | fw(2*k1) = dcmplx(0d0, 0d0) 427 | fw(2*k1+1) = dcmplx(0d0, 0d0) 428 | enddo 429 | c 430 | if (iflag .ge. 0) then 431 | call dcfftb(nf1,fw(0),fw(iwsav)) 432 | else 433 | call dcfftf(nf1,fw(0),fw(iwsav)) 434 | endif 435 | c 436 | c --------------------------------------------------------------- 437 | c Loop over target points (1,...,nj) 438 | c 439 | c 1. find closest mesh point (with periodic wrapping if needed) 440 | c 2. get contributions from regular fine grid to target 441 | c locations using Gaussian convolution. 442 | c --------------------------------------------------------------- 443 | t1 = pi/r2lamb 444 | do j = 1, nj 445 | cj(j) = dcmplx(0d0,0d0) 446 | jb1 = int((xj(j)+pi)/hx) 447 | diff1 = (xj(j)+pi)/hx - jb1 448 | jb1 = mod(jb1, nf1) 449 | if (jb1.lt.0) jb1=jb1+nf1 450 | xc(0) = exp(-t1*diff1**2) 451 | cross = xc(0) 452 | cross1 = exp(2d0*t1 * diff1) 453 | do k1 = 1, nspread 454 | cross = cross * cross1 455 | xc(k1) = fw(iw1+k1)*cross 456 | enddo 457 | cross = xc(0) 458 | cross1 = 1d0/cross1 459 | do k1 = 1, nspread-1 460 | cross = cross * cross1 461 | xc(-k1) = fw(iw1+k1)*cross 462 | enddo 463 | c 464 | jb1d = min(nspread-1, jb1) 465 | jb1u = min(nspread, nf1-jb1-1) 466 | do k1 = -nspread+1, -jb1d-1 467 | zz = dcmplx(fw(2*(jb1+k1+nf1)),fw(2*(jb1+k1+nf1)+1)) 468 | cj(j) = cj(j) + xc(k1)*zz 469 | enddo 470 | do k1 = -jb1d, jb1u 471 | zz = dcmplx(fw(2*(jb1+k1)),fw(2*(jb1+k1)+1)) 472 | cj(j) = cj(j) + xc(k1)*zz 473 | enddo 474 | do k1 = jb1u+1, nspread 475 | zz = dcmplx(fw(2*(jb1+k1-nf1)),fw(2*(jb1+k1-nf1)+1)) 476 | cj(j) = cj(j) + xc(k1)*zz 477 | enddo 478 | enddo 479 | deallocate(fw) 480 | return 481 | end 482 | c 483 | c 484 | c 485 | c 486 | c 487 | c 488 | ************************************************************************ 489 | subroutine nufft1d3f90(nj,xj,cj, iflag,eps, nk,sk,fk,ier) 490 | implicit none 491 | integer ier,iw1,iwsave,iwtot,j,jb1,k1,kb1,kmax,nj,iflag,nk 492 | integer next235,nf1,nspread 493 | real*8 ang,cross,cross1,diff1,eps,hx,hs,rat,pi,r2lamb1 494 | real*8 sm,sb,t1,t2,xm,xb 495 | real*8 xc(-147:147), xj(nj), sk(nk) 496 | parameter (pi=3.141592653589793238462643383279502884197d0) 497 | complex*16 cj(nj), fk(nk), zz, cs 498 | c 499 | c ---------------------------------------------------------------------- 500 | integer nw, istart 501 | real*8, allocatable :: fw(:) 502 | c ---------------------------------------------------------------------- 503 | c if (iflag .ge. 0) then 504 | c 505 | c nj 506 | c fk(sk(k)) = SUM cj(j) exp(+i sk(k) xj(j)) for k = 1,..., nk 507 | c j=1 508 | c 509 | c else 510 | c 511 | c nj 512 | c fk(sk(k)) = SUM cj(j) exp(-i sk(k) xj(j)) for k = 1,..., nk 513 | c j=1 514 | c ---------------------------------------------------------------------- 515 | c INPUT: 516 | c 517 | c nj number of sources (integer) 518 | c xj location of sources (double array) 519 | c cj strengths of sources (double complex array) 520 | c iflag determines sign of FFT (see above) 521 | c eps precision request (between 1.0d-33 and 1.0d-1) 522 | c recomended value is 1d-15 for double precision calculations 523 | c nk number of (noninteger) Fourier modes computed 524 | c sk k-values (locations) of desired Fourier modes 525 | c 526 | c OUTPUT: 527 | c 528 | c fk Fourier transform values (double complex array) 529 | c ier error return code 530 | c 531 | c ier = 0 => normal execution. 532 | c ier = 1 => precision eps requested is out of range. 533 | c 534 | c 535 | c References: 536 | c 537 | c [DR] Fast Fourier transforms for nonequispaced data, 538 | c A. Dutt and V. Rokhlin, SIAM J. Sci. Comput. 14, 539 | c 1368-1383, 1993. 540 | c 541 | c [LG] The type 3 nonuniform FFT and its applications 542 | c J.-Y. Lee and L. Greengard, J. Comput. Phys. 206, 1-5 (2005). 543 | c 544 | c The algorithm is essentially a concatenation of the 545 | c type 1 and 2 transforms. 546 | c 547 | c 1) Gaussian gridding of strengths cj(j) centered at xj 548 | c to create f_\tau(n \Delta_x) (in notation of [LG]) 549 | c 2) Deconvolve each regular grid mode 550 | c to create f^{-\sigma}_\tau(n \Delta_x) (in notation of [LG]) 551 | c 3) compute FFT on uniform mesh 552 | c to create F^{-\sigma}_\tau(m \Delta_s) (in notation of [LG]) 553 | c 4) Gaussian gridding to irregular frequency points 554 | c to create F_\tau(s_k) (in notation of [LG]) 555 | c 5) Deconvolution of result 556 | c to create F(s_k) (in notation of [LG]) 557 | c 558 | c*********************************************************************** 559 | ier = 0 560 | if ((eps.lt.1d-33).or.(eps.gt.1d-1)) then 561 | ier = 1 562 | return 563 | endif 564 | c 565 | c --- Check the ranges of {xj}/{sk} and the workspace size 566 | c 567 | t1 = xj(1) 568 | t2 = xj(1) 569 | do j = 2, nj 570 | if (xj(j).gt.t2) then 571 | t2=xj(j) 572 | else if (xj(j).lt.t1) then 573 | t1=xj(j) 574 | endif 575 | enddo 576 | xb = (t1+t2) / 2d0 577 | xm = max(t2-xb,-t1+xb) ! max(abs(t2-xb),abs(t1-xb)) 578 | c 579 | t1 = sk(1) 580 | t2 = sk(1) 581 | do k1 = 2, nk 582 | if (sk(k1).gt.t2) then 583 | t2=sk(k1) 584 | else if (sk(k1).lt.t1) then 585 | t1=sk(k1) 586 | endif 587 | enddo 588 | sb = (t1+t2) / 2d0 589 | sm = max(t2-sb,-t1+sb) 590 | c 591 | c ------------------------------- 592 | c Precision dependent parameters 593 | c 594 | c rat is oversampling parameter 595 | c nspread is number of neighbors to which Gaussian gridding is 596 | c carried out. 597 | c ------------------------------- 598 | if (eps.le.1d-11) then 599 | rat = sqrt(3.0d0) 600 | else 601 | rat = sqrt(2.0d0) 602 | endif 603 | c 604 | nspread = int(-log(eps)/(pi*(rat-1d0)/(rat-.5d0)) + .5d0) 605 | t1 = 2d0/pi * xm*sm 606 | nf1 = next235(rat*max(rat*t1+2*nspread,2*nspread/(rat-1))) 607 | rat = (sqrt(nf1*t1+nspread**2)-nspread)/t1 608 | c 609 | r2lamb1 = rat*rat * nspread / (rat*(rat-.5d0)) 610 | hx = pi/(rat*sm) 611 | hs = 2d0*pi/dble(nf1)/hx ! hx hs = 2.pi/nf1 612 | c 613 | c ------------------------------- 614 | c Compute workspace size and allocate 615 | c ------------------------------- 616 | c 617 | kmax = int(nf1*(r2lamb1-nspread)/r2lamb1+.1d0) 618 | iw1 = 2*nf1 619 | iwsave = iw1 + nspread+1 620 | iwtot = iwsave + 16+4*nf1 621 | allocate ( fw(0:iwtot-1) ) 622 | c 623 | c --------------------------------------------------------------- 624 | c Precompute spreading constants and initialize fw 625 | c to hold one term needed for fast Gaussian gridding 626 | c --------------------------------------------------------------- 627 | c 628 | t1 = pi/r2lamb1 629 | do k1 = 1, nspread 630 | fw(iw1+k1) = exp(-t1*k1**2) 631 | enddo 632 | c 633 | call dcffti(nf1,fw(iwsave)) 634 | c 635 | c --------------------------------------------------------------- 636 | c Initialize fine grid data to zero. 637 | c --------------------------------------------------------------- 638 | do k1 = 0, 2*nf1-1 639 | fw(k1) = dcmplx(0d0,0d0) 640 | enddo 641 | c 642 | c --------------------------------------------------------------- 643 | c Step 1/5 - gridding as in type 1 transform. 644 | c --------------------------------------------------------------- 645 | c 646 | t1 = pi/r2lamb1 647 | if (iflag .lt. 0) sb = -sb 648 | do j = 1, nj 649 | jb1 = int(dble(nf1/2) + (xj(j)-xb)/hx) 650 | diff1 = dble(nf1/2) + (xj(j)-xb)/hx - jb1 651 | ang = sb*xj(j) 652 | cs = dcmplx(cos(ang),sin(ang)) * cj(j) 653 | 654 | xc(0) = exp(-t1*diff1**2) 655 | cross = xc(0) 656 | cross1 = exp(2d0*t1 * diff1) 657 | do k1 = 1, nspread 658 | cross = cross * cross1 659 | xc(k1) = fw(iw1+k1)*cross 660 | enddo 661 | cross = xc(0) 662 | cross1 = 1d0/cross1 663 | do k1 = 1, nspread-1 664 | cross = cross * cross1 665 | xc(-k1) = fw(iw1+k1)*cross 666 | enddo 667 | 668 | do k1 = -nspread+1, nspread 669 | istart = 2*(jb1+k1) 670 | zz = xc(k1)*cs 671 | fw(istart) = fw(istart) + dreal(zz) 672 | fw(istart+1) = fw(istart+1) + dimag(zz) 673 | enddo 674 | enddo 675 | if (iflag .lt. 0) sb = -sb 676 | c 677 | c --------------------------------------------------------------- 678 | c Step 2: Deconvolve (amplify) as in Type 2 transform 679 | c Step 3: Compute FFT with shift 680 | c (-1)^k F_(k+M/2) = Sum (-1)^j F_(j+M/2) e(2pi ijk/M) 681 | c --------------------------------------------------------------- 682 | c 683 | t1 = pi * r2lamb1 / dble(nf1)**2 684 | cross1 = (1d0-2d0*mod(nf1/2,2))/r2lamb1 685 | zz = dcmplx(fw(nf1),fw(nf1+1)) 686 | zz = cross1*zz 687 | fw(nf1) = dreal(zz) 688 | fw(nf1+1) = dimag(zz) 689 | do k1 = 1, kmax 690 | cross1 = -cross1 691 | cross = cross1*exp(t1*dble(k1)**2) 692 | zz = dcmplx(fw(nf1-2*k1),fw(nf1-2*k1+1)) 693 | zz = cross*zz 694 | fw(nf1-2*k1) = dreal(zz) 695 | fw(nf1-2*k1+1) = dimag(zz) 696 | zz = dcmplx(fw(nf1+2*k1),fw(nf1+2*k1+1)) 697 | zz = cross*zz 698 | fw(nf1+2*k1) = dreal(zz) 699 | fw(nf1+2*k1+1) = dimag(zz) 700 | enddo 701 | c 702 | if (iflag .ge. 0) then 703 | call dcfftb(nf1,fw(0),fw(iwsave)) 704 | else 705 | call dcfftf(nf1,fw(0),fw(iwsave)) 706 | endif 707 | do k1 = 1, kmax+nspread, 2 708 | fw(nf1+2*k1) = -fw(nf1+2*k1) 709 | fw(nf1+2*k1+1) = -fw(nf1+2*k1+1) 710 | fw(nf1-2*k1) = -fw(nf1-2*k1) 711 | fw(nf1-2*k1+1) = -fw(nf1-2*k1+1) 712 | enddo 713 | c 714 | c --------------------------------------------------------------- 715 | c Step 4 Gaussian gridding to irregular points 716 | c Step 5 Final deconvolution 717 | c --------------------------------------------------------------- 718 | t1 = pi/r2lamb1 719 | do j = 1, nk 720 | kb1 = int(dble(nf1/2) + (sk(j)-sb)/hs) 721 | diff1 = dble(nf1/2) + (sk(j)-sb)/hs - kb1 722 | 723 | ! exp(-t1*(diff1-k1)**2) = xc(k1) 724 | xc(0) = exp(-t1*diff1**2) 725 | cross = xc(0) 726 | cross1 = exp(2d0*t1 * diff1) 727 | do k1 = 1, nspread 728 | cross = cross * cross1 729 | xc(k1) = fw(iw1+k1)*cross 730 | enddo 731 | cross = xc(0) 732 | cross1 = 1d0/cross1 733 | do k1 = 1, nspread-1 734 | cross = cross * cross1 735 | xc(-k1) = fw(iw1+k1)*cross 736 | enddo 737 | c 738 | fk(j) = dcmplx(0d0,0d0) 739 | do k1 = -nspread+1, nspread 740 | zz = dcmplx(fw(2*(kb1+k1)),fw(2*(kb1+k1)+1)) 741 | fk(j) = fk(j) + xc(k1)*zz 742 | enddo 743 | enddo 744 | c 745 | if (iflag .lt. 0) xb = -xb 746 | t1 = r2lamb1/(4d0*pi) * hx**2 747 | do j = 1, nk 748 | fk(j) = (exp(t1*(sk(j)-sb)**2))*fk(j) 749 | ang = (sk(j)-sb)*xb 750 | fk(j) = dcmplx(cos(ang),sin(ang)) * fk(j) 751 | enddo 752 | deallocate(fw) 753 | return 754 | end 755 | -------------------------------------------------------------------------------- /src/nufft/nufft2d_demof77.f: -------------------------------------------------------------------------------- 1 | cc Copyright (C) 2004-2009: Leslie Greengard and June-Yub Lee 2 | cc Contact: greengard@cims.nyu.edu 3 | cc 4 | cc This software is being released under a FreeBSD license 5 | cc (see license.txt in this directory). 6 | cc 7 | program testfft 8 | implicit none 9 | c 10 | integer i,ier,iflag,j,k1,k2,lused,lw,mx,ms,mt,n1,n2,nj,nk 11 | parameter (mx=256*256) 12 | parameter (lw=1000 000) 13 | real*8 xj(mx),yj(mx) 14 | real *8 sk(mx),tk(mx) 15 | real*8 err,pi,eps,salg,ealg 16 | real*8 fw(0:lw-1) 17 | parameter (pi=3.141592653589793238462643383279502884197d0) 18 | complex*16 cj(mx),cj0(mx),cj1(mx) 19 | complex*16 fk0(mx),fk1(mx) 20 | c 21 | c -------------------------------------------------- 22 | c create some test data 23 | c -------------------------------------------------- 24 | c 25 | n1 = 36 26 | n2 = 40 27 | ms = 32 28 | mt = 30 29 | nj = n1*n2 30 | do k1 = -n1/2, (n1-1)/2 31 | do k2 = -n2/2, (n2-1)/2 32 | j = (k2+n2/2+1) + (k1+n1/2)*n2 33 | xj(j) = pi*dcos(-pi*k1/n1) 34 | yj(j) = pi*dcos(-pi*k2/n2) 35 | cj(j) = dcmplx(dsin(pi*j/n1),dcos(pi*j/n2)) 36 | enddo 37 | enddo 38 | c 39 | c ----------------------- 40 | c start tests 41 | c ----------------------- 42 | c 43 | iflag = 1 44 | print*,'Starting 2D testing: ', ' nj =',nj, ' ms,mt =',ms,mt 45 | do i = 1,4 46 | if (i.eq.1) eps=1d-4 47 | if (i.eq.2) eps=1d-8 48 | if (i.eq.3) eps=1d-12 49 | if (i.eq.4) eps=1d-16 50 | c extended/quad precision tests 51 | if (i.eq.5) eps=1d-20 52 | if (i.eq.6) eps=1d-24 53 | if (i.eq.7) eps=1d-28 54 | if (i.eq.8) eps=1d-32 55 | print*,' ' 56 | print*,' Requested precision eps =',eps 57 | print*,' ' 58 | c 59 | c ----------------------- 60 | c call 2D Type 1 method 61 | c ----------------------- 62 | c 63 | call dirft2d1(nj,xj,yj,cj,iflag,ms,mt,fk0) 64 | call nufft2d1(nj,xj,yj,cj,iflag,eps,ms,mt,fk1,fw,lw,lused,ier) 65 | call errcomp(fk0,fk1,ms*mt,err) 66 | print *, ' iflag = ',iflag 67 | print *, ' ier = ',ier 68 | print *, ' meomory used = ',lused 69 | call errcomp(fk0,fk1,ms*mt,err) 70 | print *, ' type 1 err = ',err 71 | c 72 | c ----------------------- 73 | c call 2D Type 2 method 74 | c ----------------------- 75 | call dirft2d2(nj,xj,yj,cj0,iflag,ms,mt,fk0) 76 | call nufft2d2(nj,xj,yj,cj1,iflag,eps,ms,mt,fk1, 77 | 1 fw,lw,lused,ier) 78 | print *, ' ier = ',ier 79 | print *, ' meomory used = ',lused 80 | call errcomp(cj0,cj1,nj,err) 81 | print *, ' type 1 err = ',err 82 | c 83 | c ----------------------- 84 | c call 2D Type3 method 85 | c ----------------------- 86 | nk = ms*mt 87 | do k1 = 1, nk 88 | sk(k1) = 64*(dcos(k1*pi/nk)) 89 | tk(k1) = 48*(dsin(-pi/2+k1*pi/nk)) 90 | enddo 91 | 92 | call dirft2d3(nj,xj,yj,cj,iflag, nk,sk,tk,fk0) 93 | call nufft2d3(nj,xj,yj,cj,iflag,eps,nk,sk,tk,fk1, 94 | 1 fw,lw,lused,ier) 95 | c 96 | print *, ' ier = ',ier 97 | print *, ' meomory used = ',lused 98 | call errcomp(fk0,fk1,nk,err) 99 | print *, ' type 1 err = ',err 100 | enddo 101 | stop 102 | end 103 | c 104 | c 105 | c 106 | c 107 | c 108 | subroutine errcomp(fk0,fk1,n,err) 109 | implicit none 110 | integer k,n 111 | complex*16 fk0(n), fk1(n) 112 | real *8 salg,ealg,err 113 | c 114 | ealg = 0d0 115 | salg = 0d0 116 | do k = 1, n 117 | ealg = ealg + cdabs(fk1(k)-fk0(k))**2 118 | salg = salg + cdabs(fk0(k))**2 119 | enddo 120 | err =sqrt(ealg/salg) 121 | return 122 | end 123 | -------------------------------------------------------------------------------- /src/nufft/nufft2d_demof90.f: -------------------------------------------------------------------------------- 1 | cc Copyright (C) 2004-2009: Leslie Greengard and June-Yub Lee 2 | cc Contact: greengard@cims.nyu.edu 3 | cc 4 | cc This software is being released under a FreeBSD license 5 | cc (see license.txt in this directory). 6 | cc 7 | program testfft 8 | implicit none 9 | c 10 | integer i,ier,iflag,j,k1,k2,mx,ms,mt,n1,n2,nj,nk 11 | parameter (mx=256*256) 12 | real*8 xj(mx),yj(mx) 13 | real *8 sk(mx),tk(mx) 14 | real*8 err,pi,eps,salg,ealg 15 | parameter (pi=3.141592653589793238462643383279502884197d0) 16 | complex*16 cj(mx),cj0(mx),cj1(mx) 17 | complex*16 fk0(mx),fk1(mx) 18 | c 19 | c -------------------------------------------------- 20 | c create some test data 21 | c -------------------------------------------------- 22 | c 23 | n1 = 36 24 | n2 = 40 25 | ms = 32 26 | mt = 30 27 | nj = n1*n2 28 | do k1 = -n1/2, (n1-1)/2 29 | do k2 = -n2/2, (n2-1)/2 30 | j = (k2+n2/2+1) + (k1+n1/2)*n2 31 | xj(j) = pi*dcos(-pi*k1/n1) 32 | yj(j) = pi*dcos(-pi*k2/n2) 33 | cj(j) = dcmplx(dsin(pi*j/n1),dcos(pi*j/n2)) 34 | enddo 35 | enddo 36 | c 37 | c ----------------------- 38 | c start tests 39 | c ----------------------- 40 | c 41 | iflag = 1 42 | print*,'Starting 2D testing: ', ' nj =',nj, ' ms,mt =',ms,mt 43 | do i = 1,4 44 | if (i.eq.1) eps=1d-4 45 | if (i.eq.2) eps=1d-8 46 | if (i.eq.3) eps=1d-12 47 | if (i.eq.4) eps=1d-16 48 | c extented/quad precision tests 49 | if (i.eq.5) eps=1d-20 50 | if (i.eq.6) eps=1d-24 51 | if (i.eq.7) eps=1d-28 52 | if (i.eq.8) eps=1d-32 53 | print*,' ' 54 | print*,' Requested precision eps =',eps 55 | print*,' ' 56 | c 57 | c ----------------------- 58 | c call 2D Type 1 method 59 | c ----------------------- 60 | c 61 | call dirft2d1(nj,xj,yj,cj,iflag,ms,mt,fk0) 62 | call nufft2d1f90(nj,xj,yj,cj,iflag,eps,ms,mt,fk1,ier) 63 | call errcomp(fk0,fk1,ms*mt,err) 64 | print *, ' ier = ',ier 65 | call errcomp(fk0,fk1,ms*mt,err) 66 | print *, ' type 1 err = ',err 67 | c 68 | c ----------------------- 69 | c call 2D Type 2 method 70 | c ----------------------- 71 | call dirft2d2(nj,xj,yj,cj0,iflag,ms,mt,fk0) 72 | call nufft2d2f90(nj,xj,yj,cj1,iflag,eps,ms,mt,fk1,ier) 73 | print *, ' ier = ',ier 74 | call errcomp(cj0,cj1,nj,err) 75 | print *, ' type 1 err = ',err 76 | c 77 | c ----------------------- 78 | c call 2D Type3 method 79 | c ----------------------- 80 | nk = ms*mt 81 | do k1 = 1, nk 82 | sk(k1) = 48*(dcos(k1*pi/nk)) 83 | tk(k1) = 32*(dsin(-pi/2+k1*pi/nk)) 84 | enddo 85 | 86 | call dirft2d3(nj,xj,yj,cj,iflag,nk,sk,tk,fk0) 87 | call nufft2d3f90(nj,xj,yj,cj,iflag,eps,nk,sk,tk,fk1,ier) 88 | c 89 | print *, ' ier = ',ier 90 | call errcomp(fk0,fk1,nk,err) 91 | print *, ' type 1 err = ',err 92 | enddo 93 | stop 94 | end 95 | c 96 | c 97 | c 98 | c 99 | c 100 | subroutine errcomp(fk0,fk1,n,err) 101 | implicit none 102 | integer k,n 103 | complex*16 fk0(n), fk1(n) 104 | real *8 salg,ealg,err 105 | c 106 | ealg = 0d0 107 | salg = 0d0 108 | do k = 1, n 109 | ealg = ealg + cdabs(fk1(k)-fk0(k))**2 110 | salg = salg + cdabs(fk0(k))**2 111 | enddo 112 | err =sqrt(ealg/salg) 113 | return 114 | end 115 | -------------------------------------------------------------------------------- /src/nufft/nufft3d_demof77.f: -------------------------------------------------------------------------------- 1 | cc Copyright (C) 2004-2009: Leslie Greengard and June-Yub Lee 2 | cc Contact: greengard@cims.nyu.edu 3 | cc 4 | cc This software is being released under a FreeBSD license 5 | cc (see license.txt in this directory). 6 | cc 7 | program testfft 8 | implicit none 9 | c 10 | integer i,ier,iflag,j,k1,k2,k3,mx,ms,mt,mu,n1,n2,n3,nj,nk 11 | integer lw,lused 12 | parameter (mx=1000 000) 13 | parameter (lw=20 000 000) 14 | real*8 fw(0:lw-1) 15 | real*8 xj(mx),yj(mx),zj(mx) 16 | real *8 sk(mx),tk(mx),uk(mx) 17 | real*8 err,pi,eps,salg,ealg 18 | real*8 t0,t1,second 19 | parameter (pi=3.141592653589793238462643383279502884197d0) 20 | complex*16 cj(mx),cj0(mx),cj1(mx) 21 | complex*16 fk0(mx),fk1(mx) 22 | c 23 | c -------------------------------------------------- 24 | c create some test data 25 | c -------------------------------------------------- 26 | c 27 | ms = 24 28 | mt = 16 29 | mu = 18 30 | n1 = 16 31 | n2 = 18 32 | n3 = 24 33 | nj = n1*n2*n3 34 | do k3 = -n3/2, (n3-1)/2 35 | do k2 = -n2/2, (n2-1)/2 36 | do k1 = -n1/2, (n1-1)/2 37 | j = 1 + (k1+n1/2+1) + (k2+n2/2)*n1 + (k3+n3/2)*n1*n2 38 | xj(j) = pi*dcos(-pi*k1/n1) 39 | yj(j) = pi*dcos(-pi*k2/n2) 40 | zj(j) = pi*dcos(-pi*k3/n3) 41 | cj(j) = dcmplx(dsin(pi*j/n1),dcos(pi*j/n2)) 42 | enddo 43 | enddo 44 | enddo 45 | c 46 | c ----------------------- 47 | c start tests 48 | c ----------------------- 49 | c 50 | iflag = 1 51 | print*,'Starting 3D testing: ', 'nj =',nj, 'ms,mt,mu =',ms,mt,mu 52 | do i = 1,4 53 | if (i.eq.1) eps=1d-4 54 | if (i.eq.2) eps=1d-8 55 | if (i.eq.3) eps=1d-12 56 | if (i.eq.4) eps=1d-16 57 | c extended/quad precision tests 58 | if (i.eq.5) eps=1d-20 59 | if (i.eq.6) eps=1d-24 60 | if (i.eq.7) eps=1d-28 61 | if (i.eq.8) eps=1d-32 62 | print*,' ' 63 | print*,' Requested precision eps =',eps 64 | print*,' ' 65 | c 66 | c ----------------------- 67 | c call 3D Type 1 method 68 | c ----------------------- 69 | c 70 | call dirft3d1(nj,xj,yj,zj,cj,iflag,ms,mt,mu,fk0) 71 | call nufft3d1(nj,xj,yj,zj,cj,iflag,eps,ms,mt,mu,fk1, 72 | 1 fw,lw,lused,ier) 73 | print *, ' ier = ',ier 74 | print *, ' lused = ',lused 75 | call errcomp(fk0,fk1,ms*mt,err) 76 | print *, ' type 1 err = ',err 77 | c 78 | c ----------------------- 79 | c call 3D Type 2 method 80 | c ----------------------- 81 | call dirft3d2(nj,xj,yj,zj,cj0,iflag,ms,mt,mu,fk0) 82 | call nufft3d2(nj,xj,yj,zj,cj1,iflag,eps,ms,mt,mu,fk1, 83 | 1 fw,lw,lused,ier) 84 | print *, ' ier = ',ier 85 | print *, ' lused = ',lused 86 | call errcomp(cj0,cj1,nj,err) 87 | print *, ' type 2 err = ',err 88 | c 89 | c ----------------------- 90 | c call 3D Type3 method 91 | c ----------------------- 92 | nk = ms*mt*mu 93 | do k1 = 1, nk 94 | sk(k1) = 12*(dcos(k1*pi/nk)) 95 | tk(k1) = 8*(dsin(-pi/2+k1*pi/nk)) 96 | uk(k1) = 10*(dcos(k1*pi/nk)) 97 | enddo 98 | c 99 | call dirft3d3(nj,xj,yj,zj,cj,iflag,nk,sk,tk,uk,fk0) 100 | call nufft3d3(nj,xj,yj,zj,cj,iflag,eps,nk,sk,tk,uk,fk1, 101 | 1 fw,lw,lused,ier) 102 | print *, ' ier = ',ier 103 | print *, ' lused = ',lused 104 | call errcomp(fk0,fk1,nk,err) 105 | print *, ' type 3 err = ',err 106 | enddo 107 | stop 108 | end 109 | c 110 | c 111 | c 112 | c 113 | c 114 | subroutine errcomp(fk0,fk1,n,err) 115 | implicit none 116 | integer k,n 117 | complex*16 fk0(n), fk1(n) 118 | real *8 salg,ealg,err 119 | c 120 | ealg = 0d0 121 | salg = 0d0 122 | do k = 1, n 123 | ealg = ealg + cdabs(fk1(k)-fk0(k))**2 124 | salg = salg + cdabs(fk0(k))**2 125 | enddo 126 | err =sqrt(ealg/salg) 127 | return 128 | end 129 | -------------------------------------------------------------------------------- /src/nufft/nufft3d_demof90.f: -------------------------------------------------------------------------------- 1 | cc Copyright (C) 2004-2009: Leslie Greengard and June-Yub Lee 2 | cc Contact: greengard@cims.nyu.edu 3 | cc 4 | cc This software is being released under a FreeBSD license 5 | cc (see license.txt in this directory). 6 | cc 7 | program testfft 8 | implicit none 9 | c 10 | integer i,ier,iflag,j,k1,k2,k3,mx,ms,mt,mu,n1,n2,n3,nj,nk 11 | parameter (mx=1000 000) 12 | real*8 xj(mx),yj(mx),zj(mx) 13 | real *8 sk(mx),tk(mx),uk(mx) 14 | real*8 err,pi,eps,salg,ealg 15 | real*8 t0,t1,second 16 | parameter (pi=3.141592653589793238462643383279502884197d0) 17 | complex*16 cj(mx),cj0(mx),cj1(mx) 18 | complex*16 fk0(mx),fk1(mx) 19 | c 20 | c -------------------------------------------------- 21 | c create some test data 22 | c -------------------------------------------------- 23 | c 24 | ms = 24/2 25 | mt = 16/2 26 | mu = 18/2 27 | n1 = 16/2 28 | n2 = 18/2 29 | n3 = 24/2 30 | nj = n1*n2*n3 31 | do k3 = -n3/2, (n3-1)/2 32 | do k2 = -n2/2, (n2-1)/2 33 | do k1 = -n1/2, (n1-1)/2 34 | j = 1 + (k1+n1/2+1) + (k2+n2/2)*n1 + (k3+n3/2)*n1*n2 35 | xj(j) = pi*dcos(-pi*k1/n1) 36 | yj(j) = pi*dcos(-pi*k2/n2) 37 | zj(j) = pi*dcos(-pi*k3/n3) 38 | cj(j) = dcmplx(dsin(pi*j/n1),dcos(pi*j/n2)) 39 | enddo 40 | enddo 41 | enddo 42 | c 43 | c ----------------------- 44 | c start tests 45 | c ----------------------- 46 | c 47 | iflag = 1 48 | print*,'Starting 3D testing: ', 'nj =',nj, 'ms,mt,mu =',ms,mt,mu 49 | do i = 1,4 50 | if (i.eq.1) eps=1d-4 51 | if (i.eq.2) eps=1d-8 52 | if (i.eq.3) eps=1d-12 53 | if (i.eq.4) eps=1d-16 54 | c extended/quad precision tests 55 | if (i.eq.5) eps=1d-20 56 | if (i.eq.6) eps=1d-24 57 | if (i.eq.7) eps=1d-28 58 | if (i.eq.8) eps=1d-32 59 | print*,' ' 60 | print*,' Requested precision eps =',eps 61 | print*,' ' 62 | c 63 | c ----------------------- 64 | c call 3D Type 1 method 65 | c ----------------------- 66 | c 67 | call dirft3d1(nj,xj,yj,zj,cj,iflag,ms,mt,mu,fk0) 68 | call nufft3d1f90(nj,xj,yj,zj,cj,iflag,eps,ms,mt,mu,fk1,ier) 69 | print *, ' ier = ',ier 70 | call errcomp(fk0,fk1,ms*mt,err) 71 | print *, ' type 1 err = ',err 72 | c 73 | c ----------------------- 74 | c call 3D Type 2 method 75 | c ----------------------- 76 | call dirft3d2(nj,xj,yj,zj,cj0,iflag,ms,mt,mu,fk0) 77 | call nufft3d2f90(nj,xj,yj,zj,cj1,iflag,eps,ms,mt,mu,fk1,ier) 78 | print *, ' ier = ',ier 79 | call errcomp(cj0,cj1,nj,err) 80 | print *, ' type 2 err = ',err 81 | c 82 | c ----------------------- 83 | c call 3D Type3 method 84 | c ----------------------- 85 | nk = ms*mt*mu 86 | do k1 = 1, nk 87 | sk(k1) = 12*(dcos(k1*pi/nk)) 88 | tk(k1) = 8*(dsin(-pi/2+k1*pi/nk)) 89 | uk(k1) = 10*(dcos(k1*pi/nk)) 90 | enddo 91 | 92 | call dirft3d3(nj,xj,yj,zj,cj,iflag,nk,sk,tk,uk,fk0) 93 | call nufft3d3f90(nj,xj,yj,zj,cj,iflag,eps,nk,sk,tk,uk,fk1,ier) 94 | print *, ' ier = ',ier 95 | call errcomp(fk0,fk1,nk,err) 96 | print *, ' type 3 err = ',err 97 | enddo 98 | stop 99 | end 100 | c 101 | c 102 | c 103 | c 104 | c 105 | subroutine errcomp(fk0,fk1,n,err) 106 | implicit none 107 | integer k,n 108 | complex*16 fk0(n), fk1(n) 109 | real *8 salg,ealg,err 110 | c 111 | ealg = 0d0 112 | salg = 0d0 113 | do k = 1, n 114 | ealg = ealg + cdabs(fk1(k)-fk0(k))**2 115 | salg = salg + cdabs(fk0(k))**2 116 | enddo 117 | err =sqrt(ealg/salg) 118 | return 119 | end 120 | -------------------------------------------------------------------------------- /tests/__init.py__: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dfm/python-nufft/207f2064aa2895806233e72d810cad8a0adb4325/tests/__init.py__ -------------------------------------------------------------------------------- /tests/test_nufft1d.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from __future__ import division, print_function 4 | import unittest 5 | import numpy as np 6 | from nufft import nufft1d1freqs, nufft1d1, nufft1d2, nufft1d3 7 | 8 | 9 | def _get_data(): 10 | ms = 90 11 | nj = 128 12 | k1 = np.arange(-0.5 * nj, 0.5 * nj) 13 | j = k1 + 0.5 * nj + 1 14 | x = np.pi * np.cos(-np.pi * j / nj) 15 | c = np.empty_like(x, dtype=np.complex128) 16 | c.real = np.sin(np.pi * j / nj) 17 | c.imag = np.cos(np.pi * j / nj) 18 | f = 48 * np.cos((np.arange(ms) + 1) * np.pi / ms) 19 | return x, c, f 20 | 21 | 22 | def _get_data_roundtrip(): 23 | ms = 512 24 | nj = 200 25 | x = np.sort(np.random.choice(np.linspace(-np.pi, 26 | np.pi, 27 | ms, 28 | endpoint=False), 29 | nj, 30 | replace=False)) 31 | c = np.random.randn(nj) 32 | f = np.empty(ms) 33 | return x, c, f 34 | 35 | 36 | def _error(exact, approx): 37 | return np.sqrt(np.sum(np.abs(exact - approx) ** 2) / np.sum(np.abs(exact)**2)) 38 | 39 | 40 | class NUFFT1DTestCase(unittest.TestCase): 41 | """Tests for 1D `nufft.py`.""" 42 | 43 | def setUp(self): 44 | self.x, self.c, self.f = _get_data() 45 | 46 | def _type_1_even(self, eps=1e-10): 47 | p2 = nufft1d1(self.x, self.c, len(self.f), direct=True) 48 | p1 = nufft1d1(self.x, self.c, len(self.f), eps=eps) 49 | self.assertTrue(_error(p1, p2) < eps, 50 | "Type 1: Discrepancy between direct and fft function") 51 | self.assertEqual(len(nufft1d1freqs(len(self.f))), len(p1), 52 | "Wrong length of frequency array") 53 | 54 | def _type_1_odd(self, eps=1e-10): 55 | p2 = nufft1d1(self.x, self.c, len(self.f) + 1, direct=True) 56 | p1 = nufft1d1(self.x, self.c, len(self.f) + 1, eps=eps) 57 | self.assertTrue(_error(p1, p2) < eps, 58 | "Type 1: Discrepancy between direct and fft function") 59 | self.assertEqual(len(nufft1d1freqs(len(self.f) + 1)), len(p1), 60 | "Wrong length of frequency array") 61 | 62 | def _type_2(self, eps=1e-10): 63 | c2 = nufft1d2(self.x, self.f, direct=True) 64 | c1 = nufft1d2(self.x, self.f, eps=eps) 65 | self.assertTrue(_error(c1, c2) < eps, 66 | "Type 2: Discrepancy between direct and fft function") 67 | 68 | def _type_3(self, eps=1e-10): 69 | p2 = nufft1d3(self.x, self.c, self.f, direct=True) 70 | p1 = nufft1d3(self.x, self.c, self.f, eps=eps) 71 | self.assertTrue(_error(p1, p2) < eps, 72 | "Type 3: Discrepancy between direct and fft function") 73 | 74 | def _type_1_2_roundtrip(self, eps=1e-10): 75 | x, c1, f = _get_data_roundtrip() 76 | p = nufft1d1(x, c1, len(f), iflag=-1, eps=eps) 77 | c2 = len(x) / len(f) * nufft1d2(x, p, iflag=1, direct=True) 78 | self.assertTrue(_error(c1, c2) < eps, 79 | "Type 1 and 2: roundtrip error.") 80 | 81 | def _type_1_and_3(self, eps=1e-10): 82 | 83 | f = nufft1d1freqs(len(self.f)) 84 | p2 = nufft1d3(self.x, self.c, f, eps=eps) 85 | p1 = nufft1d1(self.x, self.c, len(f), eps=eps) 86 | self.assertTrue(_error(p1, p2) < eps, 87 | "Type 1 and 3 and not close (even)") 88 | 89 | f = nufft1d1freqs(len(f) + 1) 90 | p2 = nufft1d3(self.x, self.c, f, eps=eps) 91 | p1 = nufft1d1(self.x, self.c, len(f), eps=eps) 92 | self.assertTrue(_error(p1, p2) < eps, 93 | "Type 1 and 3 and not close (odd)") 94 | 95 | df = 0.5 * (f[1] - f[0]) 96 | p1 = nufft1d1(self.x, self.c, len(f), eps=eps, df=df) 97 | f = nufft1d1freqs(len(f), df=df) 98 | p2 = nufft1d3(self.x, self.c, f, eps=eps) 99 | self.assertTrue(_error(p1, p2) < eps, 100 | "Type 1 and 3 and not close (even)") 101 | 102 | def test_type_1_even(self): 103 | """Is the 1D type 1 with even data correct?""" 104 | for eps in [1e-2, 1e-5, 1e-10, 1e-12]: 105 | self._type_1_even(eps) 106 | 107 | def test_type_1_odd(self): 108 | """Is the 1D type 1 with odd data correct?""" 109 | for eps in [1e-2, 1e-5, 1e-10, 1e-12]: 110 | self._type_1_odd(eps) 111 | 112 | def test_type_2(self): 113 | """Is the 1D type 2 correct?""" 114 | for eps in [1e-6, 1e-10, 1e-12]: 115 | self._type_2(eps) 116 | 117 | def test_type_3(self): 118 | """Is the 1D type 3 correct?""" 119 | for eps in [1e-2, 1e-5, 1e-10, 1e-12]: 120 | self._type_3(eps) 121 | 122 | def test_type_1_2_roundtrip(self): 123 | """Is the 1D roundtrip using type 1 and 2 correct?""" 124 | for eps in [1e-2, 1e-5, 1e-10, 1e-12]: 125 | self._type_1_2_roundtrip(eps) 126 | 127 | def test_1_and_3(self): 128 | """Are the 1D type 1 and 3 similar?""" 129 | for eps in [1e-2, 1e-5, 1e-10, 1e-12]: 130 | self._type_1_and_3(eps) 131 | 132 | 133 | if __name__ == '__main__': 134 | unittest.main() 135 | -------------------------------------------------------------------------------- /tests/test_nufft1d_dft.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from __future__ import division, print_function 4 | import unittest 5 | import numpy as np 6 | from nufft import nufft1d1, nufft1d2, nufft1d3 7 | 8 | 9 | def _error(exact, approx): 10 | return np.sqrt(np.sum(np.abs(exact - approx) ** 2) / np.sum(np.abs(exact)**2)) 11 | 12 | 13 | class NUFFT1DTestCase(unittest.TestCase): 14 | """Tests for 1D `nufft.py`. 15 | 16 | The purpose of this script is to test the NUFFT library through 17 | the python-nufft interface. This seeks to validate the NUFFT 18 | implementation for the special case where it corresponds to a DFT. 19 | The script transforms 1-dimensional arrays between the space/time 20 | and the Fourier domain and compares the output to that of the 21 | corresponding FFT implementation from NumPy. 22 | 23 | """ 24 | 25 | def setUp(self): 26 | 27 | # Parameters 28 | self.N = 32 29 | self.eps = 1e-13 30 | 31 | # Coordinates 32 | self.x = 2 * np.pi * np.arange(self.N) / self.N 33 | 34 | self.c = self.x 35 | 36 | # Frequency points 37 | self.st = np.arange(self.N) 38 | 39 | # Numpy baseline FFT 40 | self.f_numpy = np.fft.fft(self.c) 41 | self.c_numpy = np.fft.ifft(self.f_numpy) 42 | self.fr_numpy = np.fft.rfft(self.c) 43 | self.cr_numpy = np.fft.irfft(self.fr_numpy) 44 | 45 | def test_type1_dft(self): 46 | """Is the NUFFT type 1 DFT correct?""" 47 | f_dir1 = np.roll(nufft1d1(self.x, 48 | self.c, 49 | self.N, 50 | iflag=-1, 51 | direct=True), 52 | -int(self.N / 2), 53 | 0) * self.N 54 | f_nufft1 = np.roll(nufft1d1(self.x, 55 | self.c, 56 | self.N, 57 | iflag=-1, 58 | direct=False), 59 | -int(self.N / 2), 60 | 0) * self.N 61 | 62 | self.assertTrue(_error(self.f_numpy, f_dir1) < self.eps, 63 | "NUFFT direct DFT (1) vs. NumPy FFT: error too large") 64 | self.assertTrue(_error(self.f_numpy, f_nufft1) < self.eps, 65 | "NUFFT direct DFT (1) vs. NumPy FFT: error too large") 66 | 67 | def test_type1_idft(self): 68 | """Is the NUFFT type 1 IDFT correct?""" 69 | c_dir = np.roll(nufft1d1(self.x, 70 | self.f_numpy, 71 | self.N, 72 | iflag=1, 73 | direct=True), 74 | -int(self.N / 2), 75 | 0) 76 | c_nufft = np.roll(nufft1d1(self.x, 77 | self.f_numpy, 78 | self.N, 79 | iflag=1, 80 | direct=False), 81 | -int(self.N / 2), 82 | 0) 83 | 84 | self.assertTrue(_error(self.c_numpy, c_dir) < self.eps, 85 | "NUFFT direct IDFT (1) vs. NumPy IFFT: error too large") 86 | self.assertTrue(_error(self.c_numpy, c_nufft) < self.eps, 87 | "NUFFT direct IDFT (1) vs. NumPy IFFT: error too large") 88 | 89 | def test_type1_rdft(self): 90 | """Is the NUFFT type 1 RDFT correct?""" 91 | f_dir1 = np.roll(nufft1d1(self.x, 92 | self.c, 93 | self.N, 94 | iflag=-1, 95 | direct=True), 96 | -int(self.N / 2), 97 | 0)[:int(self.N / 2) + 1] * self.N 98 | f_nufft1 = np.roll(nufft1d1(self.x, 99 | self.c, 100 | self.N, 101 | iflag=-1, 102 | direct=False), 103 | -int(self.N / 2), 104 | 0)[:int(self.N / 2) + 1] * self.N 105 | 106 | self.assertTrue(_error(self.fr_numpy, f_dir1) < self.eps, 107 | "NUFFT direct RDFT (1) vs. NumPy IRFFT: error too large") 108 | self.assertTrue(_error(self.fr_numpy, f_nufft1) < self.eps, 109 | "NUFFT RFFT (1) vs. NumPy IRFFT: error too large") 110 | 111 | def test_type1_irdft(self): 112 | """Is the NUFFT type 1 IRDFT correct?""" 113 | 114 | # Trick to make it think it is seeing a full FFT 115 | f = np.concatenate((self.fr_numpy, 116 | np.conj(self.fr_numpy[-2:0:-1]))) 117 | 118 | c_dir = np.roll(nufft1d1(self.x, 119 | f, 120 | self.N, 121 | iflag=1, 122 | direct=True), 123 | -int(self.N / 2), 124 | 0) 125 | c_nufft = np.roll(nufft1d1(self.x, 126 | f, 127 | self.N, 128 | iflag=1, 129 | direct=False), 130 | -int(self.N / 2), 131 | 0) 132 | 133 | self.assertTrue(_error(self.cr_numpy, c_dir) < self.eps, 134 | "NUFFT direct IRDFT (1) vs. NumPy IRFFT: error too large") 135 | self.assertTrue(_error(self.cr_numpy, c_nufft) < self.eps, 136 | "NUFFT direct IRDFT (1) vs. NumPy IRFFT: error too large") 137 | 138 | def test_type2_dft(self): 139 | """Is the NUFFT type 2 DFT correct?""" 140 | f_dir2 = nufft1d2(self.x, 141 | np.roll(self.c, 142 | -int(self.N / 2), 143 | 0), 144 | iflag=-1, 145 | direct=True) 146 | f_nufft2 = nufft1d2(self.x, 147 | np.roll(self.c, 148 | -int(self.N / 2), 149 | 0), 150 | iflag=-1, 151 | direct=False) 152 | 153 | self.assertTrue(_error(self.f_numpy, f_dir2) < self.eps, 154 | "NUFFT direct DFT (2) vs. NumPy FFT: error too large") 155 | self.assertTrue(_error(self.f_numpy, f_nufft2) < self.eps, 156 | "NUFFT FFT (2) vs. NumPy FFT: error too large") 157 | 158 | def test_type2_idft(self): 159 | """Is the NUFFT type 2 IDFT correct?""" 160 | c_dir2 = nufft1d2(self.x, 161 | np.roll(self.f_numpy, 162 | -int(self.N / 2), 163 | 0), 164 | iflag=1, 165 | direct=True) / self.N 166 | c_nufft2 = nufft1d2(self.x, 167 | np.roll(self.f_numpy, 168 | -int(self.N / 2), 169 | 0), 170 | iflag=1, 171 | direct=False) / self.N 172 | 173 | self.assertTrue(_error(self.c_numpy, c_dir2) < self.eps, 174 | "NUFFT direct IDFT (2) vs. NumPy IFFT: error too large") 175 | self.assertTrue(_error(self.c_numpy, c_nufft2) < self.eps, 176 | "NUFFT IFFT (2) vs. NumPy IFFT: error too large") 177 | 178 | def test_type3_dft(self): 179 | """Is the NUFFT type 3 DFT correct?""" 180 | f_dir3 = nufft1d3(self.x, 181 | self.c, 182 | self.st, 183 | iflag=-1, 184 | direct=True) * self.N 185 | f_nufft3 = nufft1d3(self.x, 186 | self.c, 187 | self.st, 188 | iflag=-1, 189 | direct=False) * self.N 190 | 191 | self.assertTrue(_error(self.f_numpy, f_dir3) < self.eps, 192 | "NUFFT direct DFT (3) vs. NumPy FFT: error too large") 193 | self.assertTrue(_error(self.f_numpy, f_nufft3) < self.eps, 194 | "NUFFT FFT (3) vs. NumPy FFT: error too large") 195 | 196 | def test_type3_idft(self): 197 | """Is the NUFFT type 3 IDFT correct?""" 198 | c_dir3 = nufft1d3(self.x, 199 | self.f_numpy, 200 | self.st, 201 | iflag=1, 202 | direct=True) 203 | c_nufft3 = nufft1d3(self.x, 204 | self.f_numpy, 205 | self.st, 206 | iflag=1, 207 | direct=False) 208 | 209 | self.assertTrue(_error(self.c_numpy, c_dir3) < self.eps, 210 | "NUFFT direct IDFT (2) vs. NumPy IFFT: error too large") 211 | self.assertTrue(_error(self.c_numpy, c_nufft3) < self.eps, 212 | "NUFFT IFFT (2) error vs. NumPy IFFT: error too large") 213 | 214 | 215 | if __name__ == '__main__': 216 | unittest.main() 217 | -------------------------------------------------------------------------------- /tests/test_nufft2d.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from __future__ import division, print_function 4 | import unittest 5 | import numpy as np 6 | from nufft import nufft2d1, nufft2d2, nufft2d3 7 | 8 | 9 | def _error(exact, approx): 10 | return np.sqrt(np.sum(np.abs(exact - approx) ** 2) / 11 | np.sum(np.abs(exact)**2)) 12 | 13 | 14 | class NUFFT2DTestCase(unittest.TestCase): 15 | """Tests for 2D `nufft.py`. 16 | 17 | The purpose of this script is to test the NUFFT library through 18 | the python-nufft interface. In addition to the usual interface 19 | checks, this seeks to validate the NUFFT implementation for the 20 | special case where it corresponds to a DFT. The script transforms 21 | 2-dimensional arrays between the space/time and the Fourier domain 22 | and compares the output to that of the corresponding FFT 23 | implementation from NumPy. 24 | 25 | """ 26 | 27 | def setUp(self): 28 | 29 | # Parameters 30 | self.N = 32 * np.ones(2, dtype=int) 31 | self.eps = 1e-13 32 | 33 | # Coordinates 34 | x = [2 * np.pi * np.arange(self.N[0]) / self.N[0], 35 | 2 * np.pi * np.arange(self.N[1]) / self.N[1]] 36 | self.X = np.meshgrid(x[0], x[1], indexing='ij') 37 | 38 | self.c = self.X[0] + 2 * self.X[1] 39 | 40 | # Frequency points 41 | self.st_grid = np.meshgrid(np.arange(self.N[0]), 42 | np.arange(self.N[1]), 43 | indexing='ij') 44 | 45 | # Numpy baseline FFT 46 | self.kx = (np.fft.fftfreq(self.N[0]) * self.N[0]).astype(int) 47 | self.ky = (np.fft.fftfreq(self.N[1]) * self.N[1]).astype(int) 48 | self.f_numpy = np.fft.fft2(self.c) 49 | self.c_numpy = np.fft.ifft2(self.f_numpy) 50 | self.fr_numpy = np.fft.rfft2(self.c) 51 | self.cr_numpy = np.fft.irfft2(self.fr_numpy) 52 | 53 | def _type_1_even(self, eps=1e-10): 54 | 55 | p2 = nufft2d1(self.X[0].reshape(-1), 56 | self.X[1].reshape(-1), 57 | self.c.reshape(-1), 58 | self.N[0], 59 | self.N[1], 60 | direct=True) 61 | p1 = nufft2d1(self.X[0].reshape(-1), 62 | self.X[1].reshape(-1), 63 | self.c.reshape(-1), 64 | self.N[0], 65 | self.N[1], 66 | direct=False) 67 | self.assertTrue(_error(p1, p2) < eps, 68 | "Type 1: Discrepancy between direct and fft function") 69 | 70 | def _type_1_odd(self, eps=1e-10): 71 | 72 | p2 = nufft2d1(self.X[0].reshape(-1), 73 | self.X[1].reshape(-1), 74 | self.c.reshape(-1), 75 | self.N[0] + 1, 76 | self.N[1] + 1, 77 | direct=True) 78 | p1 = nufft2d1(self.X[0].reshape(-1), 79 | self.X[1].reshape(-1), 80 | self.c.reshape(-1), 81 | self.N[0] + 1, 82 | self.N[1] + 1, 83 | eps=eps) 84 | self.assertTrue(_error(p1, p2) < eps, 85 | "Type 1: Discrepancy between direct and fft function") 86 | 87 | def _type_2(self, eps=1e-10): 88 | c2 = nufft2d2(self.X[0].reshape(-1), 89 | self.X[1].reshape(-1), 90 | np.roll(np.roll(self.c, 91 | -int(self.N[0] / 2), 92 | 0), 93 | -int(self.N[1] / 2), 94 | 1), 95 | direct=True) 96 | c1 = nufft2d2(self.X[0].reshape(-1), 97 | self.X[1].reshape(-1), 98 | np.roll(np.roll(self.c, 99 | -int(self.N[0] / 2), 100 | 0), 101 | -int(self.N[1] / 2), 102 | 1), 103 | eps=eps) 104 | self.assertTrue(_error(c1, c2) < eps, 105 | "Type 2: Discrepancy between direct and fft function") 106 | 107 | def _type_3(self, eps=1e-10): 108 | p2 = nufft2d3(self.X[0].reshape(-1), 109 | self.X[1].reshape(-1), 110 | self.c.reshape(-1), 111 | self.st_grid[0].reshape(-1), 112 | self.st_grid[1].reshape(-1), 113 | direct=True) 114 | p1 = nufft2d3(self.X[0].reshape(-1), 115 | self.X[1].reshape(-1), 116 | self.c.reshape(-1), 117 | self.st_grid[0].reshape(-1), 118 | self.st_grid[1].reshape(-1), 119 | eps=eps) 120 | self.assertTrue(_error(p1, p2) < eps, 121 | "Type 3: Discrepancy between direct and fft function") 122 | 123 | def _type_1_2_roundtrip(self, eps=1e-10): 124 | p = nufft2d1(self.X[0].reshape(-1), 125 | self.X[1].reshape(-1), 126 | self.c.reshape(-1), 127 | self.N[0], 128 | self.N[1], 129 | iflag=-1, 130 | eps=eps) 131 | c2 = nufft2d2(self.X[0].reshape(-1), 132 | self.X[1].reshape(-1), 133 | p, 134 | iflag=1, 135 | direct=True) 136 | self.assertTrue(_error(self.c.reshape(-1), c2) < eps, 137 | "Type 1 and 2: roundtrip error.") 138 | 139 | def _type_1_and_3(self, eps=1e-10): 140 | 141 | p2 = nufft2d3(self.X[0].reshape(-1), 142 | self.X[1].reshape(-1), 143 | self.c.reshape(-1), 144 | self.st_grid[0].reshape(-1), 145 | self.st_grid[1].reshape(-1), 146 | eps=eps) 147 | p1 = np.roll(np.roll(nufft2d1(self.X[0].reshape(-1), 148 | self.X[1].reshape(-1), 149 | self.c.reshape(-1), 150 | self.N[0], 151 | self.N[1], 152 | eps=eps), 153 | -int(self.N[0] / 2), 154 | 0), 155 | -int(self.N[1] / 2), 156 | 1) 157 | self.assertTrue(_error(p1.reshape(-1), p2) < eps, 158 | "Type 1 and 3 and not close") 159 | 160 | def test_type_1_even(self): 161 | """Is the 2D type 1 with even data correct?""" 162 | for eps in [1e-2, 1e-5, 1e-10, 1e-12]: 163 | self._type_1_even(eps) 164 | 165 | def test_type_1_odd(self): 166 | """Is the 2D type 1 with odd data correct?""" 167 | for eps in [1e-2, 1e-5, 1e-10, 1e-12]: 168 | self._type_1_odd(eps) 169 | 170 | def test_type_2(self): 171 | """Is the 2D type 2 correct?""" 172 | for eps in [1e-6, 1e-10, 1e-12]: 173 | self._type_2(eps) 174 | 175 | def test_type_3(self): 176 | """Is the 2D type 3 correct?""" 177 | for eps in [1e-2, 1e-5, 1e-10, 1e-12]: 178 | self._type_3(eps) 179 | 180 | def test_type_1_2_roundtrip(self): 181 | """Is the 2D roundtrip using type 1 and 2 correct?""" 182 | for eps in [1e-2, 1e-5, 1e-10, 1e-12]: 183 | self._type_1_2_roundtrip(eps) 184 | 185 | def test_1_and_3(self): 186 | """Are the 2D type 1 and 3 similar?""" 187 | for eps in [1e-2, 1e-5, 1e-10, 1e-12]: 188 | self._type_1_and_3(eps) 189 | 190 | def test_type1_dft(self): 191 | """Is the NUFFT type 1 DFT correct?""" 192 | f_dir1 = np.roll(np.roll(nufft2d1(self.X[0].reshape(-1), 193 | self.X[1].reshape(-1), 194 | self.c.reshape(-1), 195 | self.N[0], 196 | self.N[1], 197 | iflag=-1, 198 | direct=True), 199 | -int(self.N[0] / 2), 200 | 0), 201 | -int(self.N[1] / 2), 202 | 1) * self.N.prod() 203 | f_nufft1 = np.roll(np.roll(nufft2d1(self.X[0].reshape(-1), 204 | self.X[1].reshape(-1), 205 | self.c.reshape(-1), 206 | self.N[0], 207 | self.N[1], 208 | iflag=-1, 209 | direct=False), 210 | -int(self.N[0] / 2), 211 | 0), 212 | -int(self.N[1] / 2), 213 | 1) * self.N.prod() 214 | 215 | self.assertTrue(_error(self.f_numpy.reshape(-1), 216 | f_dir1.reshape(-1)) < self.eps, 217 | "NUFFT direct DFT (1) vs. NumPy FFT: error too large") 218 | self.assertTrue(_error(self.f_numpy.reshape(-1), 219 | f_nufft1.reshape(-1)) < self.eps, 220 | "NUFFT FFT (1) vs. NumPy FFT: error too large") 221 | 222 | def test_type1_idft(self): 223 | """Is the NUFFT type 1 IDFT correct?""" 224 | c_dir = np.roll(np.roll(nufft2d1(self.X[0].reshape(-1), 225 | self.X[1].reshape(-1), 226 | self.f_numpy.reshape(-1), 227 | self.N[0], 228 | self.N[1], 229 | iflag=1, 230 | direct=True), 231 | -int(self.N[0] / 2), 232 | 0), 233 | -int(self.N[1] / 2), 234 | 1) 235 | c_nufft = np.roll(np.roll(nufft2d1(self.X[0].reshape(-1), 236 | self.X[1].reshape(-1), 237 | self.f_numpy.reshape(-1), 238 | self.N[0], 239 | self.N[1], 240 | iflag=1, 241 | direct=False), 242 | -int(self.N[0] / 2), 243 | 0), 244 | -int(self.N[1] / 2), 245 | 1) 246 | 247 | self.assertTrue(_error(self.c_numpy.reshape(-1), 248 | c_dir.reshape(-1)) < self.eps, 249 | "NUFFT direct IDFT (1) vs. NumPy IFFT: error too large") 250 | self.assertTrue(_error(self.c_numpy.reshape(-1), 251 | c_nufft.reshape(-1)) < self.eps, 252 | "NUFFT IFFT (1) vs. NumPy IFFT: error too large") 253 | 254 | def test_type1_rdft(self): 255 | """Is the NUFFT type 1 RDFT correct?""" 256 | f_dir1 = np.roll(np.roll(nufft2d1(self.X[0].reshape(-1), 257 | self.X[1].reshape(-1), 258 | self.c.reshape(-1), 259 | self.N[0], 260 | self.N[1], 261 | iflag=-1, 262 | direct=True), 263 | -int(self.N[0] / 2), 264 | 0), 265 | -int(self.N[1] / 2), 266 | 1)[:, :int(self.N[1] / 2) + 1] * self.N.prod() 267 | f_nufft1 = np.roll(np.roll(nufft2d1(self.X[0].reshape(-1), 268 | self.X[1].reshape(-1), 269 | self.c.reshape(-1), 270 | self.N[0], 271 | self.N[1], 272 | iflag=-1, 273 | direct=False), 274 | -int(self.N[0] / 2), 275 | 0), 276 | -int(self.N[1] / 2), 277 | 1)[:, :int(self.N[1] / 2) + 1] * self.N.prod() 278 | 279 | self.assertTrue(_error(self.fr_numpy.reshape(-1), 280 | f_dir1.reshape(-1)) < self.eps, 281 | "NUFFT direct RDFT (1) vs. NumPy RFFT: error too large") 282 | self.assertTrue(_error(self.fr_numpy.reshape(-1), 283 | f_nufft1.reshape(-1)) < self.eps, 284 | "NUFFT RFFT (1) vs. NumPy RFFT: error too large") 285 | 286 | def test_type1_irdft(self): 287 | """Is the NUFFT type 1 IRDFT correct?""" 288 | 289 | # Trick to make it think it is seeing a full FFT 290 | K = np.meshgrid(-self.kx, 291 | -self.ky[int(self.N[1] / 2) + 1:], 292 | indexing='ij') 293 | f = np.concatenate((self.fr_numpy, 294 | np.conj(self.fr_numpy[K[0], K[1]])), 295 | axis=1) 296 | 297 | c_dir = np.roll(np.roll(nufft2d1(self.X[0].reshape(-1), 298 | self.X[1].reshape(-1), 299 | f.reshape(-1), 300 | self.N[0], 301 | self.N[1], 302 | iflag=1, 303 | direct=True), 304 | -int(self.N[0] / 2), 305 | 0), 306 | -int(self.N[1] / 2), 307 | 1) 308 | c_nufft = np.roll(np.roll(nufft2d1(self.X[0].reshape(-1), 309 | self.X[1].reshape(-1), 310 | f.reshape(-1), 311 | self.N[0], 312 | self.N[1], 313 | iflag=1, 314 | direct=False), 315 | -int(self.N[0] / 2), 316 | 0), 317 | -int(self.N[1] / 2), 318 | 1) 319 | 320 | self.assertTrue(_error(self.cr_numpy.reshape(-1), 321 | c_dir.reshape(-1)) < self.eps, 322 | "NUFFT direct IRDFT (1) vs. NumPy IRFFT: error too large") 323 | self.assertTrue(_error(self.cr_numpy.reshape(-1), 324 | c_nufft.reshape(-1)) < self.eps, 325 | "NUFFT IRFFT (1) vs. NumPy IRFFT: error too large") 326 | 327 | def test_type2_dft(self): 328 | """Is the NUFFT type 2 DFT correct?""" 329 | f_dir2 = nufft2d2(self.X[0].reshape(-1), 330 | self.X[1].reshape(-1), 331 | np.roll(np.roll(self.c, 332 | -int(self.N[0] / 2), 333 | 0), 334 | -int(self.N[1] / 2), 335 | 1), 336 | iflag=-1, 337 | direct=True) 338 | f_nufft2 = nufft2d2(self.X[0].reshape(-1), 339 | self.X[1].reshape(-1), 340 | np.roll(np.roll(self.c, 341 | -int(self.N[0] / 2), 342 | 0), 343 | -int(self.N[1] / 2), 344 | 1), 345 | iflag=-1, 346 | direct=False) 347 | 348 | self.assertTrue(_error(self.f_numpy.reshape(-1), f_dir2) < self.eps, 349 | "NUFFT direct DFT (2) vs. NumPy FFT: error too large") 350 | self.assertTrue(_error(self.f_numpy.reshape(-1), f_nufft2) < self.eps, 351 | "NUFFT FFT (2) vs. NumPy FFT: error too large") 352 | 353 | def test_type2_idft(self): 354 | """Is the NUFFT type 2 IDFT correct?""" 355 | c_dir2 = nufft2d2(self.X[0].reshape(-1), 356 | self.X[1].reshape(-1), 357 | np.roll(np.roll(self.f_numpy, 358 | -int(self.N[0] / 2), 359 | 0), 360 | -int(self.N[1] / 2), 361 | 1), 362 | iflag=1, 363 | direct=True) / self.N.prod() 364 | c_nufft2 = nufft2d2(self.X[0].reshape(-1), 365 | self.X[1].reshape(-1), 366 | np.roll(np.roll(self.f_numpy, 367 | -int(self.N[0] / 2), 368 | 0), 369 | -int(self.N[1] / 2), 370 | 1), 371 | iflag=1, 372 | direct=False) / self.N.prod() 373 | 374 | self.assertTrue(_error(self.c_numpy.reshape(-1), c_dir2) < self.eps, 375 | "NUFFT direct IDFT (2) vs. NumPy IFFT: error too large") 376 | self.assertTrue(_error(self.c_numpy.reshape(-1), c_nufft2) < self.eps, 377 | "NUFFT IFFT (2) vs. NumPy IFFT: error too large") 378 | 379 | def test_type3_dft(self): 380 | """Is the NUFFT type 3 DFT correct?""" 381 | f_dir3 = nufft2d3(self.X[0].reshape(-1), 382 | self.X[1].reshape(-1), 383 | self.c.reshape(-1), 384 | self.st_grid[0].reshape(-1), 385 | self.st_grid[1].reshape(-1), 386 | iflag=-1, 387 | direct=True) * self.N.prod() 388 | f_nufft3 = nufft2d3(self.X[0].reshape(-1), 389 | self.X[1].reshape(-1), 390 | self.c.reshape(-1), 391 | self.st_grid[0].reshape(-1), 392 | self.st_grid[1].reshape(-1), 393 | iflag=-1, 394 | direct=False) * self.N.prod() 395 | 396 | self.assertTrue(_error(self.f_numpy.reshape(-1), f_dir3) < self.eps, 397 | "NUFFT direct DFT (3) vs. NumPy FFT: error too large") 398 | self.assertTrue(_error(self.f_numpy.reshape(-1), f_nufft3) < self.eps, 399 | "NUFFT FFT (3) vs. NumPy FFT: error too large") 400 | 401 | def test_type3_idft(self): 402 | """Is the NUFFT type 3 IDFT correct?""" 403 | c_dir3 = nufft2d3(self.X[0].reshape(-1), 404 | self.X[1].reshape(-1), 405 | self.f_numpy.reshape(-1), 406 | self.st_grid[0].reshape(-1), 407 | self.st_grid[1].reshape(-1), 408 | iflag=1, 409 | direct=True) 410 | c_nufft3 = nufft2d3(self.X[0].reshape(-1), 411 | self.X[1].reshape(-1), 412 | self.f_numpy.reshape(-1), 413 | self.st_grid[0].reshape(-1), 414 | self.st_grid[1].reshape(-1), 415 | iflag=1, 416 | direct=False) 417 | 418 | self.assertTrue(_error(self.c_numpy.reshape(-1), c_dir3) < self.eps, 419 | "NUFFT direct IDFT (2) vs. NumPy IFFT: error too large") 420 | self.assertTrue(_error(self.c_numpy.reshape(-1), c_nufft3) < self.eps, 421 | "NUFFT IFFT (2) error vs. NumPy IFFT: error too large") 422 | 423 | 424 | if __name__ == '__main__': 425 | unittest.main() 426 | -------------------------------------------------------------------------------- /tests/test_nufft3d.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from __future__ import division, print_function 4 | import unittest 5 | import numpy as np 6 | from nufft import nufft3d1, nufft3d2, nufft3d3 7 | 8 | 9 | def _error(exact, approx): 10 | return np.sqrt(np.sum(np.abs(exact - approx) ** 2) / 11 | np.sum(np.abs(exact)**2)) 12 | 13 | 14 | class NUFFT3DTestCase(unittest.TestCase): 15 | """Tests for 3D `nufft.py`. 16 | 17 | The purpose of this script is to test the NUFFT library through 18 | the python-nufft interface. In addition to the usual interface 19 | checks, this seeks to validate the NUFFT implementation for the 20 | special case where it corresponds to a DFT. The script transforms 21 | 3-dimensional arrays between the space/time and the Fourier domain 22 | and compares the output to that of the corresponding FFT 23 | implementation from NumPy. 24 | 25 | """ 26 | 27 | def setUp(self): 28 | 29 | # Parameters 30 | self.N = 16 * np.ones(3, dtype=int) 31 | self.eps = 1e-13 32 | 33 | # Coordinates 34 | x = [2 * np.pi * np.arange(self.N[0]) / self.N[0], 35 | 2 * np.pi * np.arange(self.N[1]) / self.N[1], 36 | 2 * np.pi * np.arange(self.N[2]) / self.N[2]] 37 | self.X = np.meshgrid(x[0], x[1], x[2], indexing='ij') 38 | 39 | self.c = self.X[0] + 2 * self.X[1] + 3 * self.X[2] 40 | 41 | # Frequency points 42 | self.st_grid = np.meshgrid(np.arange(self.N[0]), 43 | np.arange(self.N[1]), 44 | np.arange(self.N[2]), 45 | indexing='ij') 46 | 47 | # Numpy baseline FFT 48 | self.kx = (np.fft.fftfreq(self.N[0]) * self.N[0]).astype(int) 49 | self.ky = (np.fft.fftfreq(self.N[1]) * self.N[1]).astype(int) 50 | self.kz = (np.fft.fftfreq(self.N[2]) * self.N[2]).astype(int) 51 | self.f_numpy = np.fft.fftn(self.c) 52 | self.c_numpy = np.fft.ifftn(self.f_numpy) 53 | self.fr_numpy = np.fft.rfftn(self.c) 54 | self.cr_numpy = np.fft.irfftn(self.fr_numpy) 55 | 56 | def _type_1_even(self, eps=1e-10): 57 | 58 | p2 = nufft3d1(self.X[0].reshape(-1), 59 | self.X[1].reshape(-1), 60 | self.X[2].reshape(-1), 61 | self.c.reshape(-1), 62 | self.N[0], 63 | self.N[1], 64 | self.N[2], 65 | direct=True) 66 | p1 = nufft3d1(self.X[0].reshape(-1), 67 | self.X[1].reshape(-1), 68 | self.X[2].reshape(-1), 69 | self.c.reshape(-1), 70 | self.N[0], 71 | self.N[1], 72 | self.N[2], 73 | direct=False) 74 | self.assertTrue(_error(p1, p2) < eps, 75 | "Type 1: Discrepancy between direct and fft function") 76 | 77 | def _type_1_odd(self, eps=1e-10): 78 | 79 | p2 = nufft3d1(self.X[0].reshape(-1), 80 | self.X[1].reshape(-1), 81 | self.X[2].reshape(-1), 82 | self.c.reshape(-1), 83 | self.N[0] + 1, 84 | self.N[1] + 1, 85 | self.N[2] + 1, 86 | direct=True) 87 | p1 = nufft3d1(self.X[0].reshape(-1), 88 | self.X[1].reshape(-1), 89 | self.X[2].reshape(-1), 90 | self.c.reshape(-1), 91 | self.N[0] + 1, 92 | self.N[1] + 1, 93 | self.N[2] + 1, 94 | eps=eps) 95 | self.assertTrue(_error(p1, p2) < eps, 96 | "Type 1: Discrepancy between direct and fft function") 97 | 98 | def _type_2(self, eps=1e-10): 99 | c2 = nufft3d2(self.X[0].reshape(-1), 100 | self.X[1].reshape(-1), 101 | self.X[2].reshape(-1), 102 | np.roll(np.roll(np.roll(self.c, 103 | -int(self.N[0] / 2), 104 | 0), 105 | -int(self.N[1] / 2), 106 | 1), 107 | -int(self.N[2] / 2), 108 | 2), 109 | direct=True) 110 | c1 = nufft3d2(self.X[0].reshape(-1), 111 | self.X[1].reshape(-1), 112 | self.X[2].reshape(-1), 113 | np.roll(np.roll(np.roll(self.c, 114 | -int(self.N[0] / 2), 115 | 0), 116 | -int(self.N[1] / 2), 117 | 1), 118 | -int(self.N[2] / 2), 119 | 2), 120 | eps=eps) 121 | self.assertTrue(_error(c1, c2) < eps, 122 | "Type 2: Discrepancy between direct and fft function") 123 | 124 | def _type_3(self, eps=1e-10): 125 | p2 = nufft3d3(self.X[0].reshape(-1), 126 | self.X[1].reshape(-1), 127 | self.X[2].reshape(-1), 128 | self.c.reshape(-1), 129 | self.st_grid[0].reshape(-1), 130 | self.st_grid[1].reshape(-1), 131 | self.st_grid[2].reshape(-1), 132 | direct=True) 133 | p1 = nufft3d3(self.X[0].reshape(-1), 134 | self.X[1].reshape(-1), 135 | self.X[2].reshape(-1), 136 | self.c.reshape(-1), 137 | self.st_grid[0].reshape(-1), 138 | self.st_grid[1].reshape(-1), 139 | self.st_grid[2].reshape(-1), 140 | eps=eps) 141 | self.assertTrue(_error(p1, p2) < eps, 142 | "Type 3: Discrepancy between direct and fft function") 143 | 144 | def _type_1_2_roundtrip(self, eps=1e-10): 145 | p = nufft3d1(self.X[0].reshape(-1), 146 | self.X[1].reshape(-1), 147 | self.X[2].reshape(-1), 148 | self.c.reshape(-1), 149 | self.N[0], 150 | self.N[1], 151 | self.N[2], 152 | iflag=-1, 153 | eps=eps) 154 | c2 = nufft3d2(self.X[0].reshape(-1), 155 | self.X[1].reshape(-1), 156 | self.X[2].reshape(-1), 157 | p, 158 | iflag=1, 159 | direct=True) 160 | self.assertTrue(_error(self.c.reshape(-1), c2) < eps, 161 | "Type 1 and 2: roundtrip error.") 162 | 163 | def _type_1_and_3(self, eps=1e-10): 164 | 165 | p2 = nufft3d3(self.X[0].reshape(-1), 166 | self.X[1].reshape(-1), 167 | self.X[2].reshape(-1), 168 | self.c.reshape(-1), 169 | self.st_grid[0].reshape(-1), 170 | self.st_grid[1].reshape(-1), 171 | self.st_grid[2].reshape(-1), 172 | eps=eps) 173 | p1 = np.roll(np.roll(np.roll(nufft3d1(self.X[0].reshape(-1), 174 | self.X[1].reshape(-1), 175 | self.X[2].reshape(-1), 176 | self.c.reshape(-1), 177 | self.N[0], 178 | self.N[1], 179 | self.N[2], 180 | eps=eps), 181 | -int(self.N[0] / 2), 182 | 0), 183 | -int(self.N[1] / 2), 184 | 1), 185 | -int(self.N[2] / 2), 186 | 2) 187 | self.assertTrue(_error(p1.reshape(-1), p2) < eps, 188 | "Type 1 and 3 and not close") 189 | 190 | def test_type_1_even(self): 191 | """Is the 3D type 1 with even data correct?""" 192 | for eps in [1e-2, 1e-5, 1e-10, 1e-12]: 193 | self._type_1_even(eps) 194 | 195 | def test_type_1_odd(self): 196 | """Is the 3D type 1 with odd data correct?""" 197 | for eps in [1e-2, 1e-5, 1e-10, 1e-12]: 198 | self._type_1_odd(eps) 199 | 200 | def test_type_2(self): 201 | """Is the 3D type 2 correct?""" 202 | for eps in [1e-6, 1e-10, 1e-12]: 203 | self._type_2(eps) 204 | 205 | def test_type_3(self): 206 | """Is the 3D type 3 correct?""" 207 | for eps in [1e-2, 1e-5, 1e-10, 1e-12]: 208 | self._type_3(eps) 209 | 210 | def test_type_1_2_roundtrip(self): 211 | """Is the 3D roundtrip using type 1 and 2 correct?""" 212 | for eps in [1e-2, 1e-5, 1e-10, 1e-12]: 213 | self._type_1_2_roundtrip(eps) 214 | 215 | def test_1_and_3(self): 216 | """Are the 3D type 1 and 3 similar?""" 217 | for eps in [1e-2, 1e-5, 1e-10, 1e-12]: 218 | self._type_1_and_3(eps) 219 | 220 | def test_type1_dft(self): 221 | """Is the NUFFT type 1 DFT correct?""" 222 | f_dir1 = np.roll(np.roll(np.roll(nufft3d1(self.X[0].reshape(-1), 223 | self.X[1].reshape(-1), 224 | self.X[2].reshape(-1), 225 | self.c.reshape(-1), 226 | self.N[0], 227 | self.N[1], 228 | self.N[2], 229 | iflag=-1, 230 | direct=True), 231 | -int(self.N[0] / 2), 232 | 0), 233 | -int(self.N[1] / 2), 234 | 1), 235 | -int(self.N[2] / 2), 236 | 2) * self.N.prod() 237 | f_nufft1 = np.roll(np.roll(np.roll(nufft3d1(self.X[0].reshape(-1), 238 | self.X[1].reshape(-1), 239 | self.X[2].reshape(-1), 240 | self.c.reshape(-1), 241 | self.N[0], 242 | self.N[1], 243 | self.N[2], 244 | iflag=-1, 245 | direct=False), 246 | -int(self.N[0] / 2), 247 | 0), 248 | -int(self.N[1] / 2), 249 | 1), 250 | -int(self.N[2] / 2), 251 | 2) * self.N.prod() 252 | 253 | self.assertTrue(_error(self.f_numpy.reshape(-1), 254 | f_dir1.reshape(-1)) < self.eps, 255 | "NUFFT direct DFT (1) vs. NumPy FFT: error too large") 256 | self.assertTrue(_error(self.f_numpy.reshape(-1), 257 | f_nufft1.reshape(-1)) < self.eps, 258 | "NUFFT FFT (1) vs. NumPy FFT: error too large") 259 | 260 | def test_type1_idft(self): 261 | """Is the NUFFT type 1 IDFT correct?""" 262 | c_dir = np.roll(np.roll(np.roll(nufft3d1(self.X[0].reshape(-1), 263 | self.X[1].reshape(-1), 264 | self.X[2].reshape(-1), 265 | self.f_numpy.reshape(-1), 266 | self.N[0], 267 | self.N[1], 268 | self.N[2], 269 | iflag=1, 270 | direct=True), 271 | -int(self.N[0] / 2), 272 | 0), 273 | -int(self.N[1] / 2), 274 | 1), 275 | -int(self.N[2] / 2), 276 | 2) 277 | c_nufft = np.roll(np.roll(np.roll(nufft3d1(self.X[0].reshape(-1), 278 | self.X[1].reshape(-1), 279 | self.X[2].reshape(-1), 280 | self.f_numpy.reshape(-1), 281 | self.N[0], 282 | self.N[1], 283 | self.N[2], 284 | iflag=1, 285 | direct=False), 286 | -int(self.N[0] / 2), 287 | 0), 288 | -int(self.N[1] / 2), 289 | 1), 290 | -int(self.N[2] / 2), 291 | 2) 292 | 293 | self.assertTrue(_error(self.c_numpy.reshape(-1), 294 | c_dir.reshape(-1)) < self.eps, 295 | "NUFFT direct IDFT (1) vs. NumPy IFFT: error too large") 296 | self.assertTrue(_error(self.c_numpy.reshape(-1), 297 | c_nufft.reshape(-1)) < self.eps, 298 | "NUFFT IFFT (1) vs. NumPy IFFT: error too large") 299 | 300 | def test_type1_rdft(self): 301 | """Is the NUFFT type 1 RDFT correct?""" 302 | f_dir1 = np.roll(np.roll(np.roll(nufft3d1(self.X[0].reshape(-1), 303 | self.X[1].reshape(-1), 304 | self.X[2].reshape(-1), 305 | self.c.reshape(-1), 306 | self.N[0], 307 | self.N[1], 308 | self.N[2], 309 | iflag=-1, 310 | direct=True), 311 | -int(self.N[0] / 2), 312 | 0), 313 | -int(self.N[1] / 2), 314 | 1), 315 | -int(self.N[2] / 2), 316 | 2)[:, :, :int(self.N[2] / 2) + 1] * self.N.prod() 317 | f_nufft1 = np.roll(np.roll(np.roll(nufft3d1(self.X[0].reshape(-1), 318 | self.X[1].reshape(-1), 319 | self.X[2].reshape(-1), 320 | self.c.reshape(-1), 321 | self.N[0], 322 | self.N[1], 323 | self.N[2], 324 | iflag=-1, 325 | direct=False), 326 | -int(self.N[0] / 2), 327 | 0), 328 | -int(self.N[1] / 2), 329 | 1), 330 | -int(self.N[2] / 2), 331 | 2)[:, :, :int(self.N[2] / 2) + 1] * self.N.prod() 332 | 333 | self.assertTrue(_error(self.fr_numpy.reshape(-1), 334 | f_dir1.reshape(-1)) < self.eps, 335 | "NUFFT direct RDFT (1) vs. NumPy RFFT: error too large") 336 | self.assertTrue(_error(self.fr_numpy.reshape(-1), 337 | f_nufft1.reshape(-1)) < self.eps, 338 | "NUFFT RFFT (1) vs. NumPy RFFT: error too large") 339 | 340 | def test_type1_irdft(self): 341 | """Is the NUFFT type 1 IRDFT correct?""" 342 | 343 | # Trick to make it think it is seeing a full FFT 344 | K = np.meshgrid(-self.kx, 345 | -self.ky, 346 | -self.kz[int(self.N[2] / 2) + 1:], 347 | indexing='ij') 348 | f = np.concatenate((self.fr_numpy, 349 | np.conj(self.fr_numpy[K[0], K[1], K[2]])), 350 | axis=2) 351 | 352 | c_dir = np.roll(np.roll(np.roll(nufft3d1(self.X[0].reshape(-1), 353 | self.X[1].reshape(-1), 354 | self.X[2].reshape(-1), 355 | f.reshape(-1), 356 | self.N[0], 357 | self.N[1], 358 | self.N[2], 359 | iflag=1, 360 | direct=True), 361 | -int(self.N[0] / 2), 362 | 0), 363 | -int(self.N[1] / 2), 364 | 1), 365 | -int(self.N[2] / 2), 366 | 2) 367 | c_nufft = np.roll(np.roll(np.roll(nufft3d1(self.X[0].reshape(-1), 368 | self.X[1].reshape(-1), 369 | self.X[2].reshape(-1), 370 | f.reshape(-1), 371 | self.N[0], 372 | self.N[1], 373 | self.N[2], 374 | iflag=1, 375 | direct=False), 376 | -int(self.N[0] / 2), 377 | 0), 378 | -int(self.N[1] / 2), 379 | 1), 380 | -int(self.N[2] / 2), 381 | 2) 382 | 383 | self.assertTrue(_error(self.cr_numpy.reshape(-1), 384 | c_dir.reshape(-1)) < self.eps, 385 | "NUFFT direct IRDFT (1) vs. NumPy IRFFT: error too large") 386 | self.assertTrue(_error(self.cr_numpy.reshape(-1), 387 | c_nufft.reshape(-1)) < self.eps, 388 | "NUFFT IRFFT (1) vs. NumPy IRFFT: error too large") 389 | 390 | def test_type2_dft(self): 391 | """Is the NUFFT type 2 DFT correct?""" 392 | f_dir2 = nufft3d2(self.X[0].reshape(-1), 393 | self.X[1].reshape(-1), 394 | self.X[2].reshape(-1), 395 | np.roll(np.roll(np.roll(self.c, 396 | -int(self.N[0] / 2), 397 | 0), 398 | -int(self.N[1] / 2), 399 | 1), 400 | -int(self.N[2] / 2), 401 | 2), 402 | iflag=-1, 403 | direct=True) 404 | f_nufft2 = nufft3d2(self.X[0].reshape(-1), 405 | self.X[1].reshape(-1), 406 | self.X[2].reshape(-1), 407 | np.roll(np.roll(np.roll(self.c, 408 | -int(self.N[0] / 2), 409 | 0), 410 | -int(self.N[1] / 2), 411 | 1), 412 | -int(self.N[2] / 2), 413 | 2), 414 | iflag=-1, 415 | direct=False) 416 | 417 | self.assertTrue(_error(self.f_numpy.reshape(-1), f_dir2) < self.eps, 418 | "NUFFT direct DFT (2) vs. NumPy FFT: error too large") 419 | self.assertTrue(_error(self.f_numpy.reshape(-1), f_nufft2) < self.eps, 420 | "NUFFT FFT (2) vs. NumPy FFT: error too large") 421 | 422 | def test_type2_idft(self): 423 | """Is the NUFFT type 2 IDFT correct?""" 424 | c_dir2 = nufft3d2(self.X[0].reshape(-1), 425 | self.X[1].reshape(-1), 426 | self.X[2].reshape(-1), 427 | np.roll(np.roll(np.roll(self.f_numpy, 428 | -int(self.N[0] / 2), 429 | 0), 430 | -int(self.N[1] / 2), 431 | 1), 432 | -int(self.N[2] / 2), 433 | 2), 434 | iflag=1, 435 | direct=True) / self.N.prod() 436 | c_nufft2 = nufft3d2(self.X[0].reshape(-1), 437 | self.X[1].reshape(-1), 438 | self.X[2].reshape(-1), 439 | np.roll(np.roll(np.roll(self.f_numpy, 440 | -int(self.N[0] / 2), 441 | 0), 442 | -int(self.N[1] / 2), 443 | 1), 444 | -int(self.N[2] / 2), 445 | 2), 446 | iflag=1, 447 | direct=False) / self.N.prod() 448 | 449 | self.assertTrue(_error(self.c_numpy.reshape(-1), c_dir2) < self.eps, 450 | "NUFFT direct IDFT (2) vs. NumPy IFFT: error too large") 451 | self.assertTrue(_error(self.c_numpy.reshape(-1), c_nufft2) < self.eps, 452 | "NUFFT IFFT (2) vs. NumPy IFFT: error too large") 453 | 454 | def test_type3_dft(self): 455 | """Is the NUFFT type 3 DFT correct?""" 456 | f_dir3 = nufft3d3(self.X[0].reshape(-1), 457 | self.X[1].reshape(-1), 458 | self.X[2].reshape(-1), 459 | self.c.reshape(-1), 460 | self.st_grid[0].reshape(-1), 461 | self.st_grid[1].reshape(-1), 462 | self.st_grid[2].reshape(-1), 463 | iflag=-1, 464 | direct=True) * self.N.prod() 465 | f_nufft3 = nufft3d3(self.X[0].reshape(-1), 466 | self.X[1].reshape(-1), 467 | self.X[2].reshape(-1), 468 | self.c.reshape(-1), 469 | self.st_grid[0].reshape(-1), 470 | self.st_grid[1].reshape(-1), 471 | self.st_grid[2].reshape(-1), 472 | iflag=-1, 473 | direct=False) * self.N.prod() 474 | 475 | self.assertTrue(_error(self.f_numpy.reshape(-1), f_dir3) < self.eps, 476 | "NUFFT direct DFT (3) vs. NumPy FFT: error too large") 477 | self.assertTrue(_error(self.f_numpy.reshape(-1), f_nufft3) < self.eps, 478 | "NUFFT FFT (3) vs. NumPy FFT: error too large") 479 | 480 | def test_type3_idft(self): 481 | """Is the NUFFT type 3 IDFT correct?""" 482 | c_dir3 = nufft3d3(self.X[0].reshape(-1), 483 | self.X[1].reshape(-1), 484 | self.X[2].reshape(-1), 485 | self.f_numpy.reshape(-1), 486 | self.st_grid[0].reshape(-1), 487 | self.st_grid[1].reshape(-1), 488 | self.st_grid[2].reshape(-1), 489 | iflag=1, 490 | direct=True) 491 | c_nufft3 = nufft3d3(self.X[0].reshape(-1), 492 | self.X[1].reshape(-1), 493 | self.X[2].reshape(-1), 494 | self.f_numpy.reshape(-1), 495 | self.st_grid[0].reshape(-1), 496 | self.st_grid[1].reshape(-1), 497 | self.st_grid[2].reshape(-1), 498 | iflag=1, 499 | direct=False) 500 | 501 | self.assertTrue(_error(self.c_numpy.reshape(-1), c_dir3) < self.eps, 502 | "NUFFT direct IDFT (2) vs. NumPy IFFT: error too large") 503 | self.assertTrue(_error(self.c_numpy.reshape(-1), c_nufft3) < self.eps, 504 | "NUFFT IFFT (2) error vs. NumPy IFFT: error too large") 505 | 506 | 507 | if __name__ == '__main__': 508 | unittest.main() 509 | --------------------------------------------------------------------------------