pax_global_header00006660000000000000000000000064130007202740014505gustar00rootroot0000000000000052 comment=f67c356ffe204fcb2ed9bfa301d175892d56f181 nfft-3.3.2/000077500000000000000000000000001300072027400124475ustar00rootroot00000000000000nfft-3.3.2/.gitignore000066400000000000000000000045761300072027400144530ustar00rootroot00000000000000# Object files *.o *.ko *.obj *.elf # Precompiled Headers *.gch *.pch # Libraries *.lib *.a *.la *.lo # Shared objects (inc. Windows DLLs) *.dll *.so *.so.* *.dylib # Executables *.exe *.out *.app *.i*86 *.x86_64 *.hex # Debug files *.dSYM/ # Log files *.log # Other .cproject .project .settings aclocal.m4 Makefile.in INSTALL m4/libtool.m4 m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 m4/lt~obsolete.m4 autom4te.cache/* config/* include/config.h.in configure **/.deps/* Makefile applications/fastgauss/fastgauss.c applications/polarFFT/linogram_fft_test.c applications/polarFFT/mpolar_fft_test.c applications/polarFFT/polar_fft_test.c applications/radon/inverse_radon.c applications/radon/radon.c config.log config.status doxygen/doxygen.Doxyfile examples/nfct/simple_test.c examples/nfft/simple_test.c examples/nfft/simple_test_threads.c examples/nfst/simple_test.c examples/solver/glacier.c examples/solver/simple_test.c include/config.h include/stamp-h1 include/ticks.h libtool *.pc **/.libs/* applications/fastgauss/fastgauss applications/fastsum/fastsum_matlab applications/fastsum/fastsum_test applications/fastsumS2/fastsumS2 applications/iterS2/iterS2 applications/mri/mri2d/construct_data_2d applications/mri/mri2d/construct_data_inh_2d1d applications/mri/mri2d/construct_data_inh_3d applications/mri/mri2d/reconstruct_data_2d applications/mri/mri2d/reconstruct_data_gridding applications/mri/mri2d/reconstruct_data_inh_2d1d applications/mri/mri2d/reconstruct_data_inh_3d applications/mri/mri2d/reconstruct_data_inh_nnfft applications/mri/mri3d/construct_data_2d1d applications/mri/mri3d/construct_data_3d applications/mri/mri3d/reconstruct_data_2d1d applications/mri/mri3d/reconstruct_data_3d applications/mri/mri3d/reconstruct_data_gridding applications/polarFFT/linogram_fft_test applications/polarFFT/mpolar_fft_test applications/polarFFT/polar_fft_test applications/quadratureS2/quadratureS2 applications/radon/inverse_radon applications/radon/radon examples/fpt/simple_test examples/nfct/simple_test examples/nfft/flags examples/nfft/ndft_fast examples/nfft/nfft_times examples/nfft/simple_test examples/nfft/taylor_nfft examples/nfsft/simple_test examples/nfsoft/simple_test examples/nfst/simple_test examples/nnfft/accuracy examples/nnfft/simple_test examples/nsfft/nsfft_test examples/nsfft/simple_test examples/solver/glacier examples/solver/simple_test tests/checkall *.trs CUnitAutomated-Results.xml nfft-3.3.2/.travis.yml000066400000000000000000000047421300072027400145670ustar00rootroot00000000000000language: c compiler: - gcc - clang os: linux sudo: false addons: apt: packages: - libfftw3-dev - libcunit1-dev - doxygen env: - WINDOW=kaiserbessel PRECISION= - WINDOW=gaussian PRECISION= - WINDOW=bspline PRECISION= - WINDOW=sinc PRECISION= - WINDOW=kaiserbessel PRECISION=--enable-float - WINDOW=gaussian PRECISION=--enable-float - WINDOW=bspline PRECISION=--enable-float - WINDOW=sinc PRECISION=--enable-float - WINDOW=kaiserbessel PRECISION=--enable-long-double - WINDOW=gaussian PRECISION=--enable-long-double - WINDOW=bspline PRECISION=--enable-long-double - WINDOW=sinc PRECISION=--enable-long-double - WINDOW=kaiserbessel PRECISION= DIST=dist before_script: if [ "x$TRAVIS_TAG" != "x" ]; then NFFT_TRAVIS_TAG=$(sed -e 's/\([0-9]*\.[0-9]*\.[0-9]*\)\(.*\)/\1.\2/' <<< "$TRAVIS_TAG"); a=( ${NFFT_TRAVIS_TAG//./ } ); if [ ${#a[@]} -gt 2 ]; then sed -e "s/\(m4_define(\[nfft_version_major\], \[\).*\(\])\)/\1${a[0]}\2/" -e "s/\(m4_define(\[nfft_version_minor\], \[\).*\(\])\)/\1${a[1]}\2/" -e "s/\(m4_define(\[nfft_version_patch\], \[\).*\(\])\)/\1${a[2]}\2/" -e "s/\(m4_define(\[nfft_version_type\], \[\).*\(\])\)/\1${a[3]}\2/" configure.ac > configure.ac.modified; mv configure.ac.modified configure.ac; fi fi script: ./bootstrap.sh && ./configure --with-window=$WINDOW $PRECISION --enable-all $(if test "$CC" = "clang"; then echo ""; else echo "--enable-openmp"; fi) && make && make check && make $DIST after_failure: cat config.log notifications: email: false before_deploy: - export NFFT_DISTRO=$(ls *.tar.gz) - echo "Deploying $NFFT_DISTRO to GitHub releases..." deploy: provider: releases prerelease: true api_key: secure: RzoI1Acp6lZncLnsINrEByZlL2EecIi9IygLFAklyF4YlMWRNhnu+ePW3AovFI7jU8v0H9LmSM0KYi3dIEUpQbQd46IVErihD2dZmICyxqpn1HUrfmpd3EQ1wFBA3wkCmvOWXcN3n8bCDDDV4HX6d/AQtRCp7G6HK+na8fG7JJqkBah50PytU9rcUCHIvzywg6HKQn1rbYOXhDcJs64Ns2F+z5iMlOHA02lRJgmO+5oU3Q2Bhk1V+JypEmMQ8u7zI9/TOVjMzIA0VVz68GiRHBShSRb5VPsGqhWZqqx0shpQqYVd7S9S50AURaqsSGTMmxM3pgWltkx8kUBGwessuX4uB5MdjyZwa1EJV0qIqCVxkxdX925P1zqR/0CBcbwRl9hIB6NytKodraoUbK7B3SaRF64a+l8h5gYBQfhZZEp5itkdvf+hOKQknCPiULS0yhzFLKYTui3h6iVToA2ncYzsesJdcO3vGRFWFyeFPHR/miuWMU4ZVJPKtyEU2A4SBTUIvaDIac1wvNns1fXXHuG7kiCUuZXRHjKQIhIpTahTy5/1RWolt0UlRo/SrKoW0ZDQF8NWwUy/+trdK9Ksr0aZHUo+q0rLSuJO82lJIs3mZpAGuM1a5rtQO9p7aPnuJy7Df4/1xhygig+00Mxw+D4u+HKsvgeJH01cz1rlybE= file_glob: true file: ${NFFT_DISTRO} skip_cleanup: true on: condition: $DIST = dist && $CC = clang tags: true repo: NFFT/nfft nfft-3.3.2/3rdparty/000077500000000000000000000000001300072027400142175ustar00rootroot00000000000000nfft-3.3.2/3rdparty/Makefile.am000066400000000000000000000002341300072027400162520ustar00rootroot00000000000000SUBDIRS = cstripack . noinst_LTLIBRARIES = lib3rdparty.la lib3rdparty_la_SOURCES = lib3rdparty_la_LIBADD = cstripack/libcstripack.la EXTRA_DIST = READMEnfft-3.3.2/3rdparty/README000066400000000000000000000010201300072027400150700ustar00rootroot00000000000000This directory contains third party code that is needed to build NFFT3. This directory does, however, not contain the FFTW3 library which is also needed to build NFFT3. It is available from http://www.fftw.org as a free download. All code in subpackages is copyright of the respective authors as stated in each package. Currently, the following packages are included: CSTRIPACK - A C-version of Robert J. Renka's the STRIPACK Fortran package to compute Delaunay triangulations and Voronoi partitions on the unit sphere. nfft-3.3.2/3rdparty/cstripack/000077500000000000000000000000001300072027400162025ustar00rootroot00000000000000nfft-3.3.2/3rdparty/cstripack/Makefile.am000066400000000000000000000002051300072027400202330ustar00rootroot00000000000000noinst_LTLIBRARIES = libcstripack.la libcstripack_la_SOURCES = cstripack.c libcstripack_la_LIBADD = noinst_HEADERS = cstripack.h nfft-3.3.2/3rdparty/cstripack/cstripack.c000066400000000000000000005303461300072027400203440ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* src.f -- translated by f2c (version 20060506). You must link the resulting object file with libf2c: on Microsoft Windows system, link with libf2c.lib; on Linux or Unix systems, link with .../path/to/libf2c.a -lm or, if you install libf2c.a in a standard place, with -lf2c -lm -- in that order, at the end of the command line, as in cc *.o -lf2c -lm Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., http://www.netlib.org/f2c/libf2c.zip */ #include #include "cstripack.h" /* Declarations from f2c.h */ #define abs(x) ((x) >= 0 ? (x) : -(x)) #define TRUE_ (1) #define FALSE_ (0) /* Common Block Declarations */ static struct { double y; } stcom; /* Subroutine */ int addnod_(int *nst, int *k, double *x, double *y, double *z__, int *list, int *lptr, int *lend, int *lnew, int *ier) { /* System generated locals */ int i__1; /* Local variables */ static int l; static double p[3], b1, b2, b3; static int i1, i2, i3, kk, lp, in1, io1, io2, km1, lpf, ist, lpo1; static int lpo1s; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 07/08/99 */ /* This subroutine adds node K to a triangulation of the */ /* convex hull of nodes 1,...,K-1, producing a triangulation */ /* of the convex hull of nodes 1,...,K. */ /* The algorithm consists of the following steps: node K */ /* is located relative to the triangulation (TRFIND), its */ /* index is added to the data structure (INTADD or BDYADD), */ /* and a sequence of swaps (SWPTST and SWAP) are applied to */ /* the arcs opposite K so that all arcs incident on node K */ /* and opposite node K are locally optimal (satisfy the cir- */ /* cumcircle test). Thus, if a Delaunay triangulation is */ /* input, a Delaunay triangulation will result. */ /* On input: */ /* NST = Index of a node at which TRFIND begins its */ /* search. Search time depends on the proximity */ /* of this node to K. If NST < 1, the search is */ /* begun at node K-1. */ /* K = Nodal index (index for X, Y, Z, and LEND) of the */ /* new node to be added. K .GE. 4. */ /* X,Y,Z = Arrays of length .GE. K containing Car- */ /* tesian coordinates of the nodes. */ /* (X(I),Y(I),Z(I)) defines node I for */ /* I = 1,...,K. */ /* The above parameters are not altered by this routine. */ /* LIST,LPTR,LEND,LNEW = Data structure associated with */ /* the triangulation of nodes 1 */ /* to K-1. The array lengths are */ /* assumed to be large enough to */ /* add node K. Refer to Subrou- */ /* tine TRMESH. */ /* On output: */ /* LIST,LPTR,LEND,LNEW = Data structure updated with */ /* the addition of node K as the */ /* last entry unless IER .NE. 0 */ /* and IER .NE. -3, in which case */ /* the arrays are not altered. */ /* IER = Error indicator: */ /* IER = 0 if no errors were encountered. */ /* IER = -1 if K is outside its valid range */ /* on input. */ /* IER = -2 if all nodes (including K) are col- */ /* linear (lie on a common geodesic). */ /* IER = L if nodes L and K coincide for some */ /* L < K. */ /* Modules required by ADDNOD: BDYADD, COVSPH, INSERT, */ /* INTADD, JRAND, LSTPTR, */ /* STORE, SWAP, SWPTST, */ /* TRFIND */ /* Intrinsic function called by ADDNOD: ABS */ /* *********************************************************** */ /* Local parameters: */ /* B1,B2,B3 = Unnormalized barycentric coordinates returned */ /* by TRFIND. */ /* I1,I2,I3 = Vertex indexes of a triangle containing K */ /* IN1 = Vertex opposite K: first neighbor of IO2 */ /* that precedes IO1. IN1,IO1,IO2 are in */ /* counterclockwise order. */ /* IO1,IO2 = Adjacent neighbors of K defining an arc to */ /* be tested for a swap */ /* IST = Index of node at which TRFIND begins its search */ /* KK = Local copy of K */ /* KM1 = K-1 */ /* L = Vertex index (I1, I2, or I3) returned in IER */ /* if node K coincides with a vertex */ /* LP = LIST pointer */ /* LPF = LIST pointer to the first neighbor of K */ /* LPO1 = LIST pointer to IO1 */ /* LPO1S = Saved value of LPO1 */ /* P = Cartesian coordinates of node K */ /* Parameter adjustments */ --lend; --z__; --y; --x; --list; --lptr; /* Function Body */ kk = *k; if (kk < 4) { goto L3; } /* Initialization: */ km1 = kk - 1; ist = *nst; if (ist < 1) { ist = km1; } p[0] = x[kk]; p[1] = y[kk]; p[2] = z__[kk]; /* Find a triangle (I1,I2,I3) containing K or the rightmost */ /* (I1) and leftmost (I2) visible boundary nodes as viewed */ /* from node K. */ trfind_(&ist, p, &km1, &x[1], &y[1], &z__[1], &list[1], &lptr[1], &lend[1] , &b1, &b2, &b3, &i1, &i2, &i3); /* Test for collinear or duplicate nodes. */ if (i1 == 0) { goto L4; } if (i3 != 0) { l = i1; if (p[0] == x[l] && p[1] == y[l] && p[2] == z__[l]) { goto L5; } l = i2; if (p[0] == x[l] && p[1] == y[l] && p[2] == z__[l]) { goto L5; } l = i3; if (p[0] == x[l] && p[1] == y[l] && p[2] == z__[l]) { goto L5; } intadd_(&kk, &i1, &i2, &i3, &list[1], &lptr[1], &lend[1], lnew); } else { if (i1 != i2) { bdyadd_(&kk, &i1, &i2, &list[1], &lptr[1], &lend[1], lnew); } else { covsph_(&kk, &i1, &list[1], &lptr[1], &lend[1], lnew); } } *ier = 0; /* Initialize variables for optimization of the */ /* triangulation. */ lp = lend[kk]; lpf = lptr[lp]; io2 = list[lpf]; lpo1 = lptr[lpf]; io1 = (i__1 = list[lpo1], abs(i__1)); /* Begin loop: find the node opposite K. */ L1: lp = lstptr_(&lend[io1], &io2, &list[1], &lptr[1]); if (list[lp] < 0) { goto L2; } lp = lptr[lp]; in1 = (i__1 = list[lp], abs(i__1)); /* Swap test: if a swap occurs, two new arcs are */ /* opposite K and must be tested. */ lpo1s = lpo1; if (! swptst_(&in1, &kk, &io1, &io2, &x[1], &y[1], &z__[1])) { goto L2; } swap_(&in1, &kk, &io1, &io2, &list[1], &lptr[1], &lend[1], &lpo1); if (lpo1 == 0) { /* A swap is not possible because KK and IN1 are already */ /* adjacent. This error in SWPTST only occurs in the */ /* neutral case and when there are nearly duplicate */ /* nodes. */ lpo1 = lpo1s; goto L2; } io1 = in1; goto L1; /* No swap occurred. Test for termination and reset */ /* IO2 and IO1. */ L2: if (lpo1 == lpf || list[lpo1] < 0) { return 0; } io2 = io1; lpo1 = lptr[lpo1]; io1 = (i__1 = list[lpo1], abs(i__1)); goto L1; /* KK < 4. */ L3: *ier = -1; return 0; /* All nodes are collinear. */ L4: *ier = -2; return 0; /* Nodes L and K coincide. */ L5: *ier = l; return 0; } /* addnod_ */ double areas_(double *v1, double *v2, double *v3) { /* System generated locals */ double ret_val; /* Local variables */ static int i__; static double a1, a2, a3, s12, s31, s23, u12[3], u23[3], u31[3], ca1, ca2, ca3, dv1[3], dv2[3], dv3[3]; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 09/18/90 */ /* This function returns the area of a spherical triangle */ /* on the unit sphere. */ /* On input: */ /* V1,V2,V3 = Arrays of length 3 containing the Carte- */ /* sian coordinates of unit vectors (the */ /* three triangle vertices in any order). */ /* These vectors, if nonzero, are implicitly */ /* scaled to have length 1. */ /* Input parameters are not altered by this function. */ /* On output: */ /* AREAS = Area of the spherical triangle defined by */ /* V1, V2, and V3 in the range 0 to 2*PI (the */ /* area of a hemisphere). AREAS = 0 (or 2*PI) */ /* if and only if V1, V2, and V3 lie in (or */ /* close to) a plane containing the origin. */ /* Modules required by AREAS: None */ /* Intrinsic functions called by AREAS: ACOS, DBLE, REAL, */ /* SQRT */ /* *********************************************************** */ /* Local parameters: */ /* A1,A2,A3 = Interior angles of the spherical triangle */ /* CA1,CA2,CA3 = cos(A1), cos(A2), and cos(A3), respectively */ /* DV1,DV2,DV3 = Double Precision copies of V1, V2, and V3 */ /* I = DO-loop index and index for Uij */ /* S12,S23,S31 = Sum of squared components of U12, U23, U31 */ /* U12,U23,U31 = Unit normal vectors to the planes defined by */ /* pairs of triangle vertices */ /* Parameter adjustments */ --v3; --v2; --v1; /* Function Body */ for (i__ = 1; i__ <= 3; ++i__) { dv1[i__ - 1] = v1[i__]; dv2[i__ - 1] = v2[i__]; dv3[i__ - 1] = v3[i__]; /* L1: */ } /* Compute cross products Uij = Vi X Vj. */ u12[0] = dv1[1] * dv2[2] - dv1[2] * dv2[1]; u12[1] = dv1[2] * dv2[0] - dv1[0] * dv2[2]; u12[2] = dv1[0] * dv2[1] - dv1[1] * dv2[0]; u23[0] = dv2[1] * dv3[2] - dv2[2] * dv3[1]; u23[1] = dv2[2] * dv3[0] - dv2[0] * dv3[2]; u23[2] = dv2[0] * dv3[1] - dv2[1] * dv3[0]; u31[0] = dv3[1] * dv1[2] - dv3[2] * dv1[1]; u31[1] = dv3[2] * dv1[0] - dv3[0] * dv1[2]; u31[2] = dv3[0] * dv1[1] - dv3[1] * dv1[0]; /* Normalize Uij to unit vectors. */ s12 = 0.; s23 = 0.; s31 = 0.; for (i__ = 1; i__ <= 3; ++i__) { s12 += u12[i__ - 1] * u12[i__ - 1]; s23 += u23[i__ - 1] * u23[i__ - 1]; s31 += u31[i__ - 1] * u31[i__ - 1]; /* L2: */ } /* Test for a degenerate triangle associated with collinear */ /* vertices. */ if (s12 == 0. || s23 == 0. || s31 == 0.) { ret_val = 0.; return ret_val; } s12 = sqrt(s12); s23 = sqrt(s23); s31 = sqrt(s31); for (i__ = 1; i__ <= 3; ++i__) { u12[i__ - 1] /= s12; u23[i__ - 1] /= s23; u31[i__ - 1] /= s31; /* L3: */ } /* Compute interior angles Ai as the dihedral angles between */ /* planes: */ /* CA1 = cos(A1) = - */ /* CA2 = cos(A2) = - */ /* CA3 = cos(A3) = - */ ca1 = -u12[0] * u31[0] - u12[1] * u31[1] - u12[2] * u31[2]; ca2 = -u23[0] * u12[0] - u23[1] * u12[1] - u23[2] * u12[2]; ca3 = -u31[0] * u23[0] - u31[1] * u23[1] - u31[2] * u23[2]; if (ca1 < -1.) { ca1 = -1.; } if (ca1 > 1.) { ca1 = 1.; } if (ca2 < -1.) { ca2 = -1.; } if (ca2 > 1.) { ca2 = 1.; } if (ca3 < -1.) { ca3 = -1.; } if (ca3 > 1.) { ca3 = 1.; } a1 = acos(ca1); a2 = acos(ca2); a3 = acos(ca3); /* Compute AREAS = A1 + A2 + A3 - PI. */ ret_val = a1 + a2 + a3 - acos(-1.); if (ret_val < 0.) { ret_val = 0.; } return ret_val; } /* areas_ */ /* Subroutine */ int bdyadd_(int *kk, int *i1, int *i2, int * list, int *lptr, int *lend, int *lnew) { static int k, n1, n2, lp, lsav, nsav, next; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 07/11/96 */ /* This subroutine adds a boundary node to a triangulation */ /* of a set of KK-1 points on the unit sphere. The data */ /* structure is updated with the insertion of node KK, but no */ /* optimization is performed. */ /* This routine is identical to the similarly named routine */ /* in TRIPACK. */ /* On input: */ /* KK = Index of a node to be connected to the sequence */ /* of all visible boundary nodes. KK .GE. 1 and */ /* KK must not be equal to I1 or I2. */ /* I1 = First (rightmost as viewed from KK) boundary */ /* node in the triangulation that is visible from */ /* node KK (the line segment KK-I1 intersects no */ /* arcs. */ /* I2 = Last (leftmost) boundary node that is visible */ /* from node KK. I1 and I2 may be determined by */ /* Subroutine TRFIND. */ /* The above parameters are not altered by this routine. */ /* LIST,LPTR,LEND,LNEW = Triangulation data structure */ /* created by Subroutine TRMESH. */ /* Nodes I1 and I2 must be in- */ /* cluded in the triangulation. */ /* On output: */ /* LIST,LPTR,LEND,LNEW = Data structure updated with */ /* the addition of node KK. Node */ /* KK is connected to I1, I2, and */ /* all boundary nodes in between. */ /* Module required by BDYADD: INSERT */ /* *********************************************************** */ /* Local parameters: */ /* K = Local copy of KK */ /* LP = LIST pointer */ /* LSAV = LIST pointer */ /* N1,N2 = Local copies of I1 and I2, respectively */ /* NEXT = Boundary node visible from K */ /* NSAV = Boundary node visible from K */ /* Parameter adjustments */ --lend; --lptr; --list; /* Function Body */ k = *kk; n1 = *i1; n2 = *i2; /* Add K as the last neighbor of N1. */ lp = lend[n1]; lsav = lptr[lp]; lptr[lp] = *lnew; list[*lnew] = -k; lptr[*lnew] = lsav; lend[n1] = *lnew; ++(*lnew); next = -list[lp]; list[lp] = next; nsav = next; /* Loop on the remaining boundary nodes between N1 and N2, */ /* adding K as the first neighbor. */ L1: lp = lend[next]; insert_(&k, &lp, &list[1], &lptr[1], lnew); if (next == n2) { goto L2; } next = -list[lp]; list[lp] = next; goto L1; /* Add the boundary nodes between N1 and N2 as neighbors */ /* of node K. */ L2: lsav = *lnew; list[*lnew] = n1; lptr[*lnew] = *lnew + 1; ++(*lnew); next = nsav; L3: if (next == n2) { goto L4; } list[*lnew] = next; lptr[*lnew] = *lnew + 1; ++(*lnew); lp = lend[next]; next = list[lp]; goto L3; L4: list[*lnew] = -n2; lptr[*lnew] = lsav; lend[k] = *lnew; ++(*lnew); return 0; } /* bdyadd_ */ /* Subroutine */ int bnodes_(int *n, int *list, int *lptr, int *lend, int *nodes, int *nb, int *na, int *nt) { /* System generated locals */ int i__1; /* Local variables */ static int k, n0, lp, nn, nst; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 06/26/96 */ /* Given a triangulation of N nodes on the unit sphere */ /* created by Subroutine TRMESH, this subroutine returns an */ /* array containing the indexes (if any) of the counterclock- */ /* wise-ordered sequence of boundary nodes -- the nodes on */ /* the boundary of the convex hull of the set of nodes. (The */ /* boundary is empty if the nodes do not lie in a single */ /* hemisphere.) The numbers of boundary nodes, arcs, and */ /* triangles are also returned. */ /* On input: */ /* N = Number of nodes in the triangulation. N .GE. 3. */ /* LIST,LPTR,LEND = Data structure defining the trian- */ /* gulation. Refer to Subroutine */ /* TRMESH. */ /* The above parameters are not altered by this routine. */ /* NODES = int array of length at least NB */ /* (NB .LE. N). */ /* On output: */ /* NODES = Ordered sequence of boundary node indexes */ /* in the range 1 to N (in the first NB loca- */ /* tions). */ /* NB = Number of boundary nodes. */ /* NA,NT = Number of arcs and triangles, respectively, */ /* in the triangulation. */ /* Modules required by BNODES: None */ /* *********************************************************** */ /* Local parameters: */ /* K = NODES index */ /* LP = LIST pointer */ /* N0 = Boundary node to be added to NODES */ /* NN = Local copy of N */ /* NST = First element of nodes (arbitrarily chosen to be */ /* the one with smallest index) */ /* Parameter adjustments */ --lend; --list; --lptr; --nodes; /* Function Body */ nn = *n; /* Search for a boundary node. */ i__1 = nn; for (nst = 1; nst <= i__1; ++nst) { lp = lend[nst]; if (list[lp] < 0) { goto L2; } /* L1: */ } /* The triangulation contains no boundary nodes. */ *nb = 0; *na = (nn - 2) * 3; *nt = (nn - 2) << 1; return 0; /* NST is the first boundary node encountered. Initialize */ /* for traversal of the boundary. */ L2: nodes[1] = nst; k = 1; n0 = nst; /* Traverse the boundary in counterclockwise order. */ L3: lp = lend[n0]; lp = lptr[lp]; n0 = list[lp]; if (n0 == nst) { goto L4; } ++k; nodes[k] = n0; goto L3; /* Store the counts. */ L4: *nb = k; *nt = (*n << 1) - *nb - 2; *na = *nt + *n - 1; return 0; } /* bnodes_ */ /* Subroutine */ int circum_(double *v1, double *v2, double *v3, double *c__, int *ier) { /* Local variables */ static int i__; static double e1[3], e2[3], cu[3], cnorm; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 06/29/95 */ /* This subroutine returns the circumcenter of a spherical */ /* triangle on the unit sphere: the point on the sphere sur- */ /* face that is equally distant from the three triangle */ /* vertices and lies in the same hemisphere, where distance */ /* is taken to be arc-length on the sphere surface. */ /* On input: */ /* V1,V2,V3 = Arrays of length 3 containing the Carte- */ /* sian coordinates of the three triangle */ /* vertices (unit vectors) in CCW order. */ /* The above parameters are not altered by this routine. */ /* C = Array of length 3. */ /* On output: */ /* C = Cartesian coordinates of the circumcenter unless */ /* IER > 0, in which case C is not defined. C = */ /* (V2-V1) X (V3-V1) normalized to a unit vector. */ /* IER = Error indicator: */ /* IER = 0 if no errors were encountered. */ /* IER = 1 if V1, V2, and V3 lie on a common */ /* line: (V2-V1) X (V3-V1) = 0. */ /* (The vertices are not tested for validity.) */ /* Modules required by CIRCUM: None */ /* Intrinsic function called by CIRCUM: SQRT */ /* *********************************************************** */ /* Local parameters: */ /* CNORM = Norm of CU: used to compute C */ /* CU = Scalar multiple of C: E1 X E2 */ /* E1,E2 = Edges of the underlying planar triangle: */ /* V2-V1 and V3-V1, respectively */ /* I = DO-loop index */ /* Parameter adjustments */ --c__; --v3; --v2; --v1; /* Function Body */ for (i__ = 1; i__ <= 3; ++i__) { e1[i__ - 1] = v2[i__] - v1[i__]; e2[i__ - 1] = v3[i__] - v1[i__]; /* L1: */ } /* Compute CU = E1 X E2 and CNORM**2. */ cu[0] = e1[1] * e2[2] - e1[2] * e2[1]; cu[1] = e1[2] * e2[0] - e1[0] * e2[2]; cu[2] = e1[0] * e2[1] - e1[1] * e2[0]; cnorm = cu[0] * cu[0] + cu[1] * cu[1] + cu[2] * cu[2]; /* The vertices lie on a common line if and only if CU is */ /* the zero vector. */ if (cnorm != 0.) { /* No error: compute C. */ cnorm = sqrt(cnorm); for (i__ = 1; i__ <= 3; ++i__) { c__[i__] = cu[i__ - 1] / cnorm; /* L2: */ } *ier = 0; } else { /* CU = 0. */ *ier = 1; } return 0; } /* circum_ */ /* Subroutine */ int covsph_(int *kk, int *n0, int *list, int *lptr, int *lend, int *lnew) { static int k, lp, nst, lsav, next; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 07/17/96 */ /* This subroutine connects an exterior node KK to all */ /* boundary nodes of a triangulation of KK-1 points on the */ /* unit sphere, producing a triangulation that covers the */ /* sphere. The data structure is updated with the addition */ /* of node KK, but no optimization is performed. All boun- */ /* dary nodes must be visible from node KK. */ /* On input: */ /* KK = Index of the node to be connected to the set of */ /* all boundary nodes. KK .GE. 4. */ /* N0 = Index of a boundary node (in the range 1 to */ /* KK-1). N0 may be determined by Subroutine */ /* TRFIND. */ /* The above parameters are not altered by this routine. */ /* LIST,LPTR,LEND,LNEW = Triangulation data structure */ /* created by Subroutine TRMESH. */ /* Node N0 must be included in */ /* the triangulation. */ /* On output: */ /* LIST,LPTR,LEND,LNEW = Data structure updated with */ /* the addition of node KK as the */ /* last entry. The updated */ /* triangulation contains no */ /* boundary nodes. */ /* Module required by COVSPH: INSERT */ /* *********************************************************** */ /* Local parameters: */ /* K = Local copy of KK */ /* LP = LIST pointer */ /* LSAV = LIST pointer */ /* NEXT = Boundary node visible from K */ /* NST = Local copy of N0 */ /* Parameter adjustments */ --lend; --lptr; --list; /* Function Body */ k = *kk; nst = *n0; /* Traverse the boundary in clockwise order, inserting K as */ /* the first neighbor of each boundary node, and converting */ /* the boundary node to an interior node. */ next = nst; L1: lp = lend[next]; insert_(&k, &lp, &list[1], &lptr[1], lnew); next = -list[lp]; list[lp] = next; if (next != nst) { goto L1; } /* Traverse the boundary again, adding each node to K's */ /* adjacency list. */ lsav = *lnew; L2: lp = lend[next]; list[*lnew] = next; lptr[*lnew] = *lnew + 1; ++(*lnew); next = list[lp]; if (next != nst) { goto L2; } lptr[*lnew - 1] = lsav; lend[k] = *lnew - 1; return 0; } /* covsph_ */ /* Subroutine */ int crlist_(int *n, int *ncol, double *x, double *y, double *z__, int *list, int *lend, int *lptr, int *lnew, int *ltri, int *listc, int *nb, double *xc, double *yc, double *zc, double *rc, int *ier) { /* System generated locals */ int i__1, i__2; /* Local variables */ static double c__[3], t; static int i1, i2, i3, i4, n0, n1, n2, n3, n4; static double v1[3], v2[3], v3[3]; static int lp, kt, nn, nt, nm2, kt1, kt2, kt11, kt12, kt21, kt22, lpl, lpn; static int swp; static int ierr; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 07/05/98 */ /* Given a Delaunay triangulation of nodes on the surface */ /* of the unit sphere, this subroutine returns the set of */ /* triangle circumcenters corresponding to Voronoi vertices, */ /* along with the circumradii and a list of triangle indexes */ /* LISTC stored in one-to-one correspondence with LIST/LPTR */ /* entries. */ /* A triangle circumcenter is the point (unit vector) lying */ /* at the same angular distance from the three vertices and */ /* contained in the same hemisphere as the vertices. (Note */ /* that the negative of a circumcenter is also equidistant */ /* from the vertices.) If the triangulation covers the sur- */ /* face, the Voronoi vertices are the circumcenters of the */ /* triangles in the Delaunay triangulation. LPTR, LEND, and */ /* LNEW are not altered in this case. */ /* On the other hand, if the nodes are contained in a sin- */ /* gle hemisphere, the triangulation is implicitly extended */ /* to the entire surface by adding pseudo-arcs (of length */ /* greater than 180 degrees) between boundary nodes forming */ /* pseudo-triangles whose 'circumcenters' are included in the */ /* list. This extension to the triangulation actually con- */ /* sists of a triangulation of the set of boundary nodes in */ /* which the swap test is reversed (a non-empty circumcircle */ /* test). The negative circumcenters are stored as the */ /* pseudo-triangle 'circumcenters'. LISTC, LPTR, LEND, and */ /* LNEW contain a data structure corresponding to the ex- */ /* tended triangulation (Voronoi diagram), but LIST is not */ /* altered in this case. Thus, if it is necessary to retain */ /* the original (unextended) triangulation data structure, */ /* copies of LPTR and LNEW must be saved before calling this */ /* routine. */ /* On input: */ /* N = Number of nodes in the triangulation. N .GE. 3. */ /* Note that, if N = 3, there are only two Voronoi */ /* vertices separated by 180 degrees, and the */ /* Voronoi regions are not well defined. */ /* NCOL = Number of columns reserved for LTRI. This */ /* must be at least NB-2, where NB is the number */ /* of boundary nodes. */ /* X,Y,Z = Arrays of length N containing the Cartesian */ /* coordinates of the nodes (unit vectors). */ /* LIST = int array containing the set of adjacency */ /* lists. Refer to Subroutine TRMESH. */ /* LEND = Set of pointers to ends of adjacency lists. */ /* Refer to Subroutine TRMESH. */ /* The above parameters are not altered by this routine. */ /* LPTR = Array of pointers associated with LIST. Re- */ /* fer to Subroutine TRMESH. */ /* LNEW = Pointer to the first empty location in LIST */ /* and LPTR (list length plus one). */ /* LTRI = int work space array dimensioned 6 by */ /* NCOL, or unused dummy parameter if NB = 0. */ /* LISTC = int array of length at least 3*NT, where */ /* NT = 2*N-4 is the number of triangles in the */ /* triangulation (after extending it to cover */ /* the entire surface if necessary). */ /* XC,YC,ZC,RC = Arrays of length NT = 2*N-4. */ /* On output: */ /* LPTR = Array of pointers associated with LISTC: */ /* updated for the addition of pseudo-triangles */ /* if the original triangulation contains */ /* boundary nodes (NB > 0). */ /* LNEW = Pointer to the first empty location in LISTC */ /* and LPTR (list length plus one). LNEW is not */ /* altered if NB = 0. */ /* LTRI = Triangle list whose first NB-2 columns con- */ /* tain the indexes of a clockwise-ordered */ /* sequence of vertices (first three rows) */ /* followed by the LTRI column indexes of the */ /* triangles opposite the vertices (or 0 */ /* denoting the exterior region) in the last */ /* three rows. This array is not generally of */ /* any use. */ /* LISTC = Array containing triangle indexes (indexes */ /* to XC, YC, ZC, and RC) stored in 1-1 corres- */ /* pondence with LIST/LPTR entries (or entries */ /* that would be stored in LIST for the */ /* extended triangulation): the index of tri- */ /* angle (N1,N2,N3) is stored in LISTC(K), */ /* LISTC(L), and LISTC(M), where LIST(K), */ /* LIST(L), and LIST(M) are the indexes of N2 */ /* as a neighbor of N1, N3 as a neighbor of N2, */ /* and N1 as a neighbor of N3. The Voronoi */ /* region associated with a node is defined by */ /* the CCW-ordered sequence of circumcenters in */ /* one-to-one correspondence with its adjacency */ /* list (in the extended triangulation). */ /* NB = Number of boundary nodes unless IER = 1. */ /* XC,YC,ZC = Arrays containing the Cartesian coordi- */ /* nates of the triangle circumcenters */ /* (Voronoi vertices). XC(I)**2 + YC(I)**2 */ /* + ZC(I)**2 = 1. The first NB-2 entries */ /* correspond to pseudo-triangles if NB > 0. */ /* RC = Array containing circumradii (the arc lengths */ /* or angles between the circumcenters and associ- */ /* ated triangle vertices) in 1-1 correspondence */ /* with circumcenters. */ /* IER = Error indicator: */ /* IER = 0 if no errors were encountered. */ /* IER = 1 if N < 3. */ /* IER = 2 if NCOL < NB-2. */ /* IER = 3 if a triangle is degenerate (has ver- */ /* tices lying on a common geodesic). */ /* Modules required by CRLIST: CIRCUM, LSTPTR, SWPTST */ /* Intrinsic functions called by CRLIST: ABS, ACOS */ /* *********************************************************** */ /* Local parameters: */ /* C = Circumcenter returned by Subroutine CIRCUM */ /* I1,I2,I3 = Permutation of (1,2,3): LTRI row indexes */ /* I4 = LTRI row index in the range 1 to 3 */ /* IERR = Error flag for calls to CIRCUM */ /* KT = Triangle index */ /* KT1,KT2 = Indexes of a pair of adjacent pseudo-triangles */ /* KT11,KT12 = Indexes of the pseudo-triangles opposite N1 */ /* and N2 as vertices of KT1 */ /* KT21,KT22 = Indexes of the pseudo-triangles opposite N1 */ /* and N2 as vertices of KT2 */ /* LP,LPN = LIST pointers */ /* LPL = LIST pointer of the last neighbor of N1 */ /* N0 = Index of the first boundary node (initial */ /* value of N1) in the loop on boundary nodes */ /* used to store the pseudo-triangle indexes */ /* in LISTC */ /* N1,N2,N3 = Nodal indexes defining a triangle (CCW order) */ /* or pseudo-triangle (clockwise order) */ /* N4 = Index of the node opposite N2 -> N1 */ /* NM2 = N-2 */ /* NN = Local copy of N */ /* NT = Number of pseudo-triangles: NB-2 */ /* SWP = Logical variable set to TRUE in each optimiza- */ /* tion loop (loop on pseudo-arcs) iff a swap */ /* is performed */ /* V1,V2,V3 = Vertices of triangle KT = (N1,N2,N3) sent to */ /* Subroutine CIRCUM */ /* Parameter adjustments */ --lend; --z__; --y; --x; ltri -= 7; --list; --lptr; --listc; --xc; --yc; --zc; --rc; /* Function Body */ nn = *n; *nb = 0; nt = 0; if (nn < 3) { goto L21; } /* Search for a boundary node N1. */ i__1 = nn; for (n1 = 1; n1 <= i__1; ++n1) { lp = lend[n1]; if (list[lp] < 0) { goto L2; } /* L1: */ } /* The triangulation already covers the sphere. */ goto L9; /* There are NB .GE. 3 boundary nodes. Add NB-2 pseudo- */ /* triangles (N1,N2,N3) by connecting N3 to the NB-3 */ /* boundary nodes to which it is not already adjacent. */ /* Set N3 and N2 to the first and last neighbors, */ /* respectively, of N1. */ L2: n2 = -list[lp]; lp = lptr[lp]; n3 = list[lp]; /* Loop on boundary arcs N1 -> N2 in clockwise order, */ /* storing triangles (N1,N2,N3) in column NT of LTRI */ /* along with the indexes of the triangles opposite */ /* the vertices. */ L3: ++nt; if (nt <= *ncol) { ltri[nt * 6 + 1] = n1; ltri[nt * 6 + 2] = n2; ltri[nt * 6 + 3] = n3; ltri[nt * 6 + 4] = nt + 1; ltri[nt * 6 + 5] = nt - 1; ltri[nt * 6 + 6] = 0; } n1 = n2; lp = lend[n1]; n2 = -list[lp]; if (n2 != n3) { goto L3; } *nb = nt + 2; if (*ncol < nt) { goto L22; } ltri[nt * 6 + 4] = 0; if (nt == 1) { goto L7; } /* Optimize the exterior triangulation (set of pseudo- */ /* triangles) by applying swaps to the pseudo-arcs N1-N2 */ /* (pairs of adjacent pseudo-triangles KT1 and KT2 > KT1). */ /* The loop on pseudo-arcs is repeated until no swaps are */ /* performed. */ L4: swp = FALSE_; i__1 = nt - 1; for (kt1 = 1; kt1 <= i__1; ++kt1) { for (i3 = 1; i3 <= 3; ++i3) { kt2 = ltri[i3 + 3 + kt1 * 6]; if (kt2 <= kt1) { goto L5; } /* The LTRI row indexes (I1,I2,I3) of triangle KT1 = */ /* (N1,N2,N3) are a cyclical permutation of (1,2,3). */ if (i3 == 1) { i1 = 2; i2 = 3; } else if (i3 == 2) { i1 = 3; i2 = 1; } else { i1 = 1; i2 = 2; } n1 = ltri[i1 + kt1 * 6]; n2 = ltri[i2 + kt1 * 6]; n3 = ltri[i3 + kt1 * 6]; /* KT2 = (N2,N1,N4) for N4 = LTRI(I,KT2), where */ /* LTRI(I+3,KT2) = KT1. */ if (ltri[kt2 * 6 + 4] == kt1) { i4 = 1; } else if (ltri[kt2 * 6 + 5] == kt1) { i4 = 2; } else { i4 = 3; } n4 = ltri[i4 + kt2 * 6]; /* The empty circumcircle test is reversed for the pseudo- */ /* triangles. The reversal is implicit in the clockwise */ /* ordering of the vertices. */ if (! swptst_(&n1, &n2, &n3, &n4, &x[1], &y[1], &z__[1])) { goto L5; } /* Swap arc N1-N2 for N3-N4. KTij is the triangle opposite */ /* Nj as a vertex of KTi. */ swp = TRUE_; kt11 = ltri[i1 + 3 + kt1 * 6]; kt12 = ltri[i2 + 3 + kt1 * 6]; if (i4 == 1) { i2 = 2; i1 = 3; } else if (i4 == 2) { i2 = 3; i1 = 1; } else { i2 = 1; i1 = 2; } kt21 = ltri[i1 + 3 + kt2 * 6]; kt22 = ltri[i2 + 3 + kt2 * 6]; ltri[kt1 * 6 + 1] = n4; ltri[kt1 * 6 + 2] = n3; ltri[kt1 * 6 + 3] = n1; ltri[kt1 * 6 + 4] = kt12; ltri[kt1 * 6 + 5] = kt22; ltri[kt1 * 6 + 6] = kt2; ltri[kt2 * 6 + 1] = n3; ltri[kt2 * 6 + 2] = n4; ltri[kt2 * 6 + 3] = n2; ltri[kt2 * 6 + 4] = kt21; ltri[kt2 * 6 + 5] = kt11; ltri[kt2 * 6 + 6] = kt1; /* Correct the KT11 and KT22 entries that changed. */ if (kt11 != 0) { i4 = 4; if (ltri[kt11 * 6 + 4] != kt1) { i4 = 5; if (ltri[kt11 * 6 + 5] != kt1) { i4 = 6; } } ltri[i4 + kt11 * 6] = kt2; } if (kt22 != 0) { i4 = 4; if (ltri[kt22 * 6 + 4] != kt2) { i4 = 5; if (ltri[kt22 * 6 + 5] != kt2) { i4 = 6; } } ltri[i4 + kt22 * 6] = kt1; } L5: ; } /* L6: */ } if (swp) { goto L4; } /* Compute and store the negative circumcenters and radii of */ /* the pseudo-triangles in the first NT positions. */ L7: i__1 = nt; for (kt = 1; kt <= i__1; ++kt) { n1 = ltri[kt * 6 + 1]; n2 = ltri[kt * 6 + 2]; n3 = ltri[kt * 6 + 3]; v1[0] = x[n1]; v1[1] = y[n1]; v1[2] = z__[n1]; v2[0] = x[n2]; v2[1] = y[n2]; v2[2] = z__[n2]; v3[0] = x[n3]; v3[1] = y[n3]; v3[2] = z__[n3]; circum_(v1, v2, v3, c__, &ierr); if (ierr != 0) { goto L23; } /* Store the negative circumcenter and radius (computed */ /* from ). */ xc[kt] = c__[0]; yc[kt] = c__[1]; zc[kt] = c__[2]; t = v1[0] * c__[0] + v1[1] * c__[1] + v1[2] * c__[2]; if (t < -1.) { t = -1.; } if (t > 1.) { t = 1.; } rc[kt] = acos(t); /* L8: */ } /* Compute and store the circumcenters and radii of the */ /* actual triangles in positions KT = NT+1, NT+2, ... */ /* Also, store the triangle indexes KT in the appropriate */ /* LISTC positions. */ L9: kt = nt; /* Loop on nodes N1. */ nm2 = nn - 2; i__1 = nm2; for (n1 = 1; n1 <= i__1; ++n1) { lpl = lend[n1]; lp = lpl; n3 = list[lp]; /* Loop on adjacent neighbors N2,N3 of N1 for which N2 > N1 */ /* and N3 > N1. */ L10: lp = lptr[lp]; n2 = n3; n3 = (i__2 = list[lp], abs(i__2)); if (n2 <= n1 || n3 <= n1) { goto L11; } ++kt; /* Compute the circumcenter C of triangle KT = (N1,N2,N3). */ v1[0] = x[n1]; v1[1] = y[n1]; v1[2] = z__[n1]; v2[0] = x[n2]; v2[1] = y[n2]; v2[2] = z__[n2]; v3[0] = x[n3]; v3[1] = y[n3]; v3[2] = z__[n3]; circum_(v1, v2, v3, c__, &ierr); if (ierr != 0) { goto L23; } /* Store the circumcenter, radius and triangle index. */ xc[kt] = c__[0]; yc[kt] = c__[1]; zc[kt] = c__[2]; t = v1[0] * c__[0] + v1[1] * c__[1] + v1[2] * c__[2]; if (t < -1.) { t = -1.; } if (t > 1.) { t = 1.; } rc[kt] = acos(t); /* Store KT in LISTC(LPN), where Abs(LIST(LPN)) is the */ /* index of N2 as a neighbor of N1, N3 as a neighbor */ /* of N2, and N1 as a neighbor of N3. */ lpn = lstptr_(&lpl, &n2, &list[1], &lptr[1]); listc[lpn] = kt; lpn = lstptr_(&lend[n2], &n3, &list[1], &lptr[1]); listc[lpn] = kt; lpn = lstptr_(&lend[n3], &n1, &list[1], &lptr[1]); listc[lpn] = kt; L11: if (lp != lpl) { goto L10; } /* L12: */ } if (nt == 0) { goto L20; } /* Store the first NT triangle indexes in LISTC. */ /* Find a boundary triangle KT1 = (N1,N2,N3) with a */ /* boundary arc opposite N3. */ kt1 = 0; L13: ++kt1; if (ltri[kt1 * 6 + 4] == 0) { i1 = 2; i2 = 3; i3 = 1; goto L14; } else if (ltri[kt1 * 6 + 5] == 0) { i1 = 3; i2 = 1; i3 = 2; goto L14; } else if (ltri[kt1 * 6 + 6] == 0) { i1 = 1; i2 = 2; i3 = 3; goto L14; } goto L13; L14: n1 = ltri[i1 + kt1 * 6]; n0 = n1; /* Loop on boundary nodes N1 in CCW order, storing the */ /* indexes of the clockwise-ordered sequence of triangles */ /* that contain N1. The first triangle overwrites the */ /* last neighbor position, and the remaining triangles, */ /* if any, are appended to N1's adjacency list. */ /* A pointer to the first neighbor of N1 is saved in LPN. */ L15: lp = lend[n1]; lpn = lptr[lp]; listc[lp] = kt1; /* Loop on triangles KT2 containing N1. */ L16: kt2 = ltri[i2 + 3 + kt1 * 6]; if (kt2 != 0) { /* Append KT2 to N1's triangle list. */ lptr[lp] = *lnew; lp = *lnew; listc[lp] = kt2; ++(*lnew); /* Set KT1 to KT2 and update (I1,I2,I3) such that */ /* LTRI(I1,KT1) = N1. */ kt1 = kt2; if (ltri[kt1 * 6 + 1] == n1) { i1 = 1; i2 = 2; i3 = 3; } else if (ltri[kt1 * 6 + 2] == n1) { i1 = 2; i2 = 3; i3 = 1; } else { i1 = 3; i2 = 1; i3 = 2; } goto L16; } /* Store the saved first-triangle pointer in LPTR(LP), set */ /* N1 to the next boundary node, test for termination, */ /* and permute the indexes: the last triangle containing */ /* a boundary node is the first triangle containing the */ /* next boundary node. */ lptr[lp] = lpn; n1 = ltri[i3 + kt1 * 6]; if (n1 != n0) { i4 = i3; i3 = i2; i2 = i1; i1 = i4; goto L15; } /* No errors encountered. */ L20: *ier = 0; return 0; /* N < 3. */ L21: *ier = 1; return 0; /* Insufficient space reserved for LTRI. */ L22: *ier = 2; return 0; /* Error flag returned by CIRCUM: KT indexes a null triangle. */ L23: *ier = 3; return 0; } /* crlist_ */ /* Subroutine */ int delarc_(int *n, int *io1, int *io2, int * list, int *lptr, int *lend, int *lnew, int *ier) { /* System generated locals */ int i__1; /* Local variables */ static int n1, n2, n3, lp, lph, lpl; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 07/17/96 */ /* This subroutine deletes a boundary arc from a triangula- */ /* tion. It may be used to remove a null triangle from the */ /* convex hull boundary. Note, however, that if the union of */ /* triangles is rendered nonconvex, Subroutines DELNOD, EDGE, */ /* and TRFIND (and hence ADDNOD) may fail. Also, Function */ /* NEARND should not be called following an arc deletion. */ /* This routine is identical to the similarly named routine */ /* in TRIPACK. */ /* On input: */ /* N = Number of nodes in the triangulation. N .GE. 4. */ /* IO1,IO2 = Indexes (in the range 1 to N) of a pair of */ /* adjacent boundary nodes defining the arc */ /* to be removed. */ /* The above parameters are not altered by this routine. */ /* LIST,LPTR,LEND,LNEW = Triangulation data structure */ /* created by Subroutine TRMESH. */ /* On output: */ /* LIST,LPTR,LEND,LNEW = Data structure updated with */ /* the removal of arc IO1-IO2 */ /* unless IER > 0. */ /* IER = Error indicator: */ /* IER = 0 if no errors were encountered. */ /* IER = 1 if N, IO1, or IO2 is outside its valid */ /* range, or IO1 = IO2. */ /* IER = 2 if IO1-IO2 is not a boundary arc. */ /* IER = 3 if the node opposite IO1-IO2 is al- */ /* ready a boundary node, and thus IO1 */ /* or IO2 has only two neighbors or a */ /* deletion would result in two triangu- */ /* lations sharing a single node. */ /* IER = 4 if one of the nodes is a neighbor of */ /* the other, but not vice versa, imply- */ /* ing an invalid triangulation data */ /* structure. */ /* Module required by DELARC: DELNB, LSTPTR */ /* Intrinsic function called by DELARC: ABS */ /* *********************************************************** */ /* Local parameters: */ /* LP = LIST pointer */ /* LPH = LIST pointer or flag returned by DELNB */ /* LPL = Pointer to the last neighbor of N1, N2, or N3 */ /* N1,N2,N3 = Nodal indexes of a triangle such that N1->N2 */ /* is the directed boundary edge associated */ /* with IO1-IO2 */ /* Parameter adjustments */ --lend; --list; --lptr; /* Function Body */ n1 = *io1; n2 = *io2; /* Test for errors, and set N1->N2 to the directed boundary */ /* edge associated with IO1-IO2: (N1,N2,N3) is a triangle */ /* for some N3. */ if (*n < 4 || n1 < 1 || n1 > *n || n2 < 1 || n2 > *n || n1 == n2) { *ier = 1; return 0; } lpl = lend[n2]; if (-list[lpl] != n1) { n1 = n2; n2 = *io1; lpl = lend[n2]; if (-list[lpl] != n1) { *ier = 2; return 0; } } /* Set N3 to the node opposite N1->N2 (the second neighbor */ /* of N1), and test for error 3 (N3 already a boundary */ /* node). */ lpl = lend[n1]; lp = lptr[lpl]; lp = lptr[lp]; n3 = (i__1 = list[lp], abs(i__1)); lpl = lend[n3]; if (list[lpl] <= 0) { *ier = 3; return 0; } /* Delete N2 as a neighbor of N1, making N3 the first */ /* neighbor, and test for error 4 (N2 not a neighbor */ /* of N1). Note that previously computed pointers may */ /* no longer be valid following the call to DELNB. */ delnb_(&n1, &n2, n, &list[1], &lptr[1], &lend[1], lnew, &lph); if (lph < 0) { *ier = 4; return 0; } /* Delete N1 as a neighbor of N2, making N3 the new last */ /* neighbor. */ delnb_(&n2, &n1, n, &list[1], &lptr[1], &lend[1], lnew, &lph); /* Make N3 a boundary node with first neighbor N2 and last */ /* neighbor N1. */ lp = lstptr_(&lend[n3], &n1, &list[1], &lptr[1]); lend[n3] = lp; list[lp] = -n1; /* No errors encountered. */ *ier = 0; return 0; } /* delarc_ */ /* Subroutine */ int delnb_(int *n0, int *nb, int *n, int * list, int *lptr, int *lend, int *lnew, int *lph) { /* System generated locals */ int i__1; /* Local variables */ static int i__, lp, nn, lpb, lpl, lpp, lnw; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 07/29/98 */ /* This subroutine deletes a neighbor NB from the adjacency */ /* list of node N0 (but N0 is not deleted from the adjacency */ /* list of NB) and, if NB is a boundary node, makes N0 a */ /* boundary node. For pointer (LIST index) LPH to NB as a */ /* neighbor of N0, the empty LIST,LPTR location LPH is filled */ /* in with the values at LNEW-1, pointer LNEW-1 (in LPTR and */ /* possibly in LEND) is changed to LPH, and LNEW is decremen- */ /* ted. This requires a search of LEND and LPTR entailing an */ /* expected operation count of O(N). */ /* This routine is identical to the similarly named routine */ /* in TRIPACK. */ /* On input: */ /* N0,NB = Indexes, in the range 1 to N, of a pair of */ /* nodes such that NB is a neighbor of N0. */ /* (N0 need not be a neighbor of NB.) */ /* N = Number of nodes in the triangulation. N .GE. 3. */ /* The above parameters are not altered by this routine. */ /* LIST,LPTR,LEND,LNEW = Data structure defining the */ /* triangulation. */ /* On output: */ /* LIST,LPTR,LEND,LNEW = Data structure updated with */ /* the removal of NB from the ad- */ /* jacency list of N0 unless */ /* LPH < 0. */ /* LPH = List pointer to the hole (NB as a neighbor of */ /* N0) filled in by the values at LNEW-1 or error */ /* indicator: */ /* LPH > 0 if no errors were encountered. */ /* LPH = -1 if N0, NB, or N is outside its valid */ /* range. */ /* LPH = -2 if NB is not a neighbor of N0. */ /* Modules required by DELNB: None */ /* Intrinsic function called by DELNB: ABS */ /* *********************************************************** */ /* Local parameters: */ /* I = DO-loop index */ /* LNW = LNEW-1 (output value of LNEW) */ /* LP = LIST pointer of the last neighbor of NB */ /* LPB = Pointer to NB as a neighbor of N0 */ /* LPL = Pointer to the last neighbor of N0 */ /* LPP = Pointer to the neighbor of N0 that precedes NB */ /* NN = Local copy of N */ /* Parameter adjustments */ --lend; --list; --lptr; /* Function Body */ nn = *n; /* Test for error 1. */ if (*n0 < 1 || *n0 > nn || *nb < 1 || *nb > nn || nn < 3) { *lph = -1; return 0; } /* Find pointers to neighbors of N0: */ /* LPL points to the last neighbor, */ /* LPP points to the neighbor NP preceding NB, and */ /* LPB points to NB. */ lpl = lend[*n0]; lpp = lpl; lpb = lptr[lpp]; L1: if (list[lpb] == *nb) { goto L2; } lpp = lpb; lpb = lptr[lpp]; if (lpb != lpl) { goto L1; } /* Test for error 2 (NB not found). */ if ((i__1 = list[lpb], abs(i__1)) != *nb) { *lph = -2; return 0; } /* NB is the last neighbor of N0. Make NP the new last */ /* neighbor and, if NB is a boundary node, then make N0 */ /* a boundary node. */ lend[*n0] = lpp; lp = lend[*nb]; if (list[lp] < 0) { list[lpp] = -list[lpp]; } goto L3; /* NB is not the last neighbor of N0. If NB is a boundary */ /* node and N0 is not, then make N0 a boundary node with */ /* last neighbor NP. */ L2: lp = lend[*nb]; if (list[lp] < 0 && list[lpl] > 0) { lend[*n0] = lpp; list[lpp] = -list[lpp]; } /* Update LPTR so that the neighbor following NB now fol- */ /* lows NP, and fill in the hole at location LPB. */ L3: lptr[lpp] = lptr[lpb]; lnw = *lnew - 1; list[lpb] = list[lnw]; lptr[lpb] = lptr[lnw]; for (i__ = nn; i__ >= 1; --i__) { if (lend[i__] == lnw) { lend[i__] = lpb; goto L5; } /* L4: */ } L5: i__1 = lnw - 1; for (i__ = 1; i__ <= i__1; ++i__) { if (lptr[i__] == lnw) { lptr[i__] = lpb; } /* L6: */ } /* No errors encountered. */ *lnew = lnw; *lph = lpb; return 0; } /* delnb_ */ /* Subroutine */ int delnod_(int *k, int *n, double *x, double *y, double *z__, int *list, int *lptr, int *lend, int *lnew, int *lwk, int *iwk, int *ier) { /* System generated locals */ int i__1; /* Local variables */ static int i__, j, n1, n2; static double x1, x2, y11, y2, z1, z2; static int nl, lp, nn, nr; static double xl, yl, zl, xr, yr, zr; static int nnb, lp21, lpf, lph, lpl, lpn, iwl, nit, lnw, lpl2; static int bdry; static int ierr, lwkl; static int nfrst; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 11/30/99 */ /* This subroutine deletes node K (along with all arcs */ /* incident on node K) from a triangulation of N nodes on the */ /* unit sphere, and inserts arcs as necessary to produce a */ /* triangulation of the remaining N-1 nodes. If a Delaunay */ /* triangulation is input, a Delaunay triangulation will */ /* result, and thus, DELNOD reverses the effect of a call to */ /* Subroutine ADDNOD. */ /* On input: */ /* K = Index (for X, Y, and Z) of the node to be */ /* deleted. 1 .LE. K .LE. N. */ /* K is not altered by this routine. */ /* N = Number of nodes in the triangulation on input. */ /* N .GE. 4. Note that N will be decremented */ /* following the deletion. */ /* X,Y,Z = Arrays of length N containing the Cartesian */ /* coordinates of the nodes in the triangula- */ /* tion. */ /* LIST,LPTR,LEND,LNEW = Data structure defining the */ /* triangulation. Refer to Sub- */ /* routine TRMESH. */ /* LWK = Number of columns reserved for IWK. LWK must */ /* be at least NNB-3, where NNB is the number of */ /* neighbors of node K, including an extra */ /* pseudo-node if K is a boundary node. */ /* IWK = int work array dimensioned 2 by LWK (or */ /* array of length .GE. 2*LWK). */ /* On output: */ /* N = Number of nodes in the triangulation on output. */ /* The input value is decremented unless 1 .LE. IER */ /* .LE. 4. */ /* X,Y,Z = Updated arrays containing nodal coordinates */ /* (with elements K+1,...,N+1 shifted up one */ /* position, thus overwriting element K) unless */ /* 1 .LE. IER .LE. 4. */ /* LIST,LPTR,LEND,LNEW = Updated triangulation data */ /* structure reflecting the dele- */ /* tion unless 1 .LE. IER .LE. 4. */ /* Note that the data structure */ /* may have been altered if IER > */ /* 3. */ /* LWK = Number of IWK columns required unless IER = 1 */ /* or IER = 3. */ /* IWK = Indexes of the endpoints of the new arcs added */ /* unless LWK = 0 or 1 .LE. IER .LE. 4. (Arcs */ /* are associated with columns, or pairs of */ /* adjacent elements if IWK is declared as a */ /* singly-subscripted array.) */ /* IER = Error indicator: */ /* IER = 0 if no errors were encountered. */ /* IER = 1 if K or N is outside its valid range */ /* or LWK < 0 on input. */ /* IER = 2 if more space is required in IWK. */ /* Refer to LWK. */ /* IER = 3 if the triangulation data structure is */ /* invalid on input. */ /* IER = 4 if K indexes an interior node with */ /* four or more neighbors, none of which */ /* can be swapped out due to collineari- */ /* ty, and K cannot therefore be deleted. */ /* IER = 5 if an error flag (other than IER = 1) */ /* was returned by OPTIM. An error */ /* message is written to the standard */ /* output unit in this case. */ /* IER = 6 if error flag 1 was returned by OPTIM. */ /* This is not necessarily an error, but */ /* the arcs may not be optimal. */ /* Note that the deletion may result in all remaining nodes */ /* being collinear. This situation is not flagged. */ /* Modules required by DELNOD: DELNB, LEFT, LSTPTR, NBCNT, */ /* OPTIM, SWAP, SWPTST */ /* Intrinsic function called by DELNOD: ABS */ /* *********************************************************** */ /* Local parameters: */ /* BDRY = Logical variable with value TRUE iff N1 is a */ /* boundary node */ /* I,J = DO-loop indexes */ /* IERR = Error flag returned by OPTIM */ /* IWL = Number of IWK columns containing arcs */ /* LNW = Local copy of LNEW */ /* LP = LIST pointer */ /* LP21 = LIST pointer returned by SWAP */ /* LPF,LPL = Pointers to the first and last neighbors of N1 */ /* LPH = Pointer (or flag) returned by DELNB */ /* LPL2 = Pointer to the last neighbor of N2 */ /* LPN = Pointer to a neighbor of N1 */ /* LWKL = Input value of LWK */ /* N1 = Local copy of K */ /* N2 = Neighbor of N1 */ /* NFRST = First neighbor of N1: LIST(LPF) */ /* NIT = Number of iterations in OPTIM */ /* NR,NL = Neighbors of N1 preceding (to the right of) and */ /* following (to the left of) N2, respectively */ /* NN = Number of nodes in the triangulation */ /* NNB = Number of neighbors of N1 (including a pseudo- */ /* node representing the boundary if N1 is a */ /* boundary node) */ /* X1,Y1,Z1 = Coordinates of N1 */ /* X2,Y2,Z2 = Coordinates of N2 */ /* XL,YL,ZL = Coordinates of NL */ /* XR,YR,ZR = Coordinates of NR */ /* Set N1 to K and NNB to the number of neighbors of N1 (plus */ /* one if N1 is a boundary node), and test for errors. LPF */ /* and LPL are LIST indexes of the first and last neighbors */ /* of N1, IWL is the number of IWK columns containing arcs, */ /* and BDRY is TRUE iff N1 is a boundary node. */ /* Parameter adjustments */ iwk -= 3; --lend; --lptr; --list; --z__; --y; --x; /* Function Body */ n1 = *k; nn = *n; if (n1 < 1 || n1 > nn || nn < 4 || *lwk < 0) { goto L21; } lpl = lend[n1]; lpf = lptr[lpl]; nnb = nbcnt_(&lpl, &lptr[1]); bdry = list[lpl] < 0; if (bdry) { ++nnb; } if (nnb < 3) { goto L23; } lwkl = *lwk; *lwk = nnb - 3; if (lwkl < *lwk) { goto L22; } iwl = 0; if (nnb == 3) { goto L3; } /* Initialize for loop on arcs N1-N2 for neighbors N2 of N1, */ /* beginning with the second neighbor. NR and NL are the */ /* neighbors preceding and following N2, respectively, and */ /* LP indexes NL. The loop is exited when all possible */ /* swaps have been applied to arcs incident on N1. */ x1 = x[n1]; y11 = y[n1]; z1 = z__[n1]; nfrst = list[lpf]; nr = nfrst; xr = x[nr]; yr = y[nr]; zr = z__[nr]; lp = lptr[lpf]; n2 = list[lp]; x2 = x[n2]; y2 = y[n2]; z2 = z__[n2]; lp = lptr[lp]; /* Top of loop: set NL to the neighbor following N2. */ L1: nl = (i__1 = list[lp], abs(i__1)); if (nl == nfrst && bdry) { goto L3; } xl = x[nl]; yl = y[nl]; zl = z__[nl]; /* Test for a convex quadrilateral. To avoid an incorrect */ /* test caused by collinearity, use the fact that if N1 */ /* is a boundary node, then N1 LEFT NR->NL and if N2 is */ /* a boundary node, then N2 LEFT NL->NR. */ lpl2 = lend[n2]; if (! ((bdry || left_(&xr, &yr, &zr, &xl, &yl, &zl, &x1, &y11, &z1)) && ( list[lpl2] < 0 || left_(&xl, &yl, &zl, &xr, &yr, &zr, &x2, &y2, & z2)))) { /* Nonconvex quadrilateral -- no swap is possible. */ nr = n2; xr = x2; yr = y2; zr = z2; goto L2; } /* The quadrilateral defined by adjacent triangles */ /* (N1,N2,NL) and (N2,N1,NR) is convex. Swap in */ /* NL-NR and store it in IWK unless NL and NR are */ /* already adjacent, in which case the swap is not */ /* possible. Indexes larger than N1 must be decremented */ /* since N1 will be deleted from X, Y, and Z. */ swap_(&nl, &nr, &n1, &n2, &list[1], &lptr[1], &lend[1], &lp21); if (lp21 == 0) { nr = n2; xr = x2; yr = y2; zr = z2; goto L2; } ++iwl; if (nl <= n1) { iwk[(iwl << 1) + 1] = nl; } else { iwk[(iwl << 1) + 1] = nl - 1; } if (nr <= n1) { iwk[(iwl << 1) + 2] = nr; } else { iwk[(iwl << 1) + 2] = nr - 1; } /* Recompute the LIST indexes and NFRST, and decrement NNB. */ lpl = lend[n1]; --nnb; if (nnb == 3) { goto L3; } lpf = lptr[lpl]; nfrst = list[lpf]; lp = lstptr_(&lpl, &nl, &list[1], &lptr[1]); if (nr == nfrst) { goto L2; } /* NR is not the first neighbor of N1. */ /* Back up and test N1-NR for a swap again: Set N2 to */ /* NR and NR to the previous neighbor of N1 -- the */ /* neighbor of NR which follows N1. LP21 points to NL */ /* as a neighbor of NR. */ n2 = nr; x2 = xr; y2 = yr; z2 = zr; lp21 = lptr[lp21]; lp21 = lptr[lp21]; nr = (i__1 = list[lp21], abs(i__1)); xr = x[nr]; yr = y[nr]; zr = z__[nr]; goto L1; /* Bottom of loop -- test for termination of loop. */ L2: if (n2 == nfrst) { goto L3; } n2 = nl; x2 = xl; y2 = yl; z2 = zl; lp = lptr[lp]; goto L1; /* Delete N1 and all its incident arcs. If N1 is an interior */ /* node and either NNB > 3 or NNB = 3 and N2 LEFT NR->NL, */ /* then N1 must be separated from its neighbors by a plane */ /* containing the origin -- its removal reverses the effect */ /* of a call to COVSPH, and all its neighbors become */ /* boundary nodes. This is achieved by treating it as if */ /* it were a boundary node (setting BDRY to TRUE, changing */ /* a sign in LIST, and incrementing NNB). */ L3: if (! bdry) { if (nnb > 3) { bdry = TRUE_; } else { lpf = lptr[lpl]; nr = list[lpf]; lp = lptr[lpf]; n2 = list[lp]; nl = list[lpl]; bdry = left_(&x[nr], &y[nr], &z__[nr], &x[nl], &y[nl], &z__[nl], & x[n2], &y[n2], &z__[n2]); } if (bdry) { /* IF a boundary node already exists, then N1 and its */ /* neighbors cannot be converted to boundary nodes. */ /* (They must be collinear.) This is a problem if */ /* NNB > 3. */ i__1 = nn; for (i__ = 1; i__ <= i__1; ++i__) { if (list[lend[i__]] < 0) { bdry = FALSE_; goto L5; } /* L4: */ } list[lpl] = -list[lpl]; ++nnb; } } L5: if (! bdry && nnb > 3) { goto L24; } /* Initialize for loop on neighbors. LPL points to the last */ /* neighbor of N1. LNEW is stored in local variable LNW. */ lp = lpl; lnw = *lnew; /* Loop on neighbors N2 of N1, beginning with the first. */ L6: lp = lptr[lp]; n2 = (i__1 = list[lp], abs(i__1)); delnb_(&n2, &n1, n, &list[1], &lptr[1], &lend[1], &lnw, &lph); if (lph < 0) { goto L23; } /* LP and LPL may require alteration. */ if (lpl == lnw) { lpl = lph; } if (lp == lnw) { lp = lph; } if (lp != lpl) { goto L6; } /* Delete N1 from X, Y, Z, and LEND, and remove its adjacency */ /* list from LIST and LPTR. LIST entries (nodal indexes) */ /* which are larger than N1 must be decremented. */ --nn; if (n1 > nn) { goto L9; } i__1 = nn; for (i__ = n1; i__ <= i__1; ++i__) { x[i__] = x[i__ + 1]; y[i__] = y[i__ + 1]; z__[i__] = z__[i__ + 1]; lend[i__] = lend[i__ + 1]; /* L7: */ } i__1 = lnw - 1; for (i__ = 1; i__ <= i__1; ++i__) { if (list[i__] > n1) { --list[i__]; } if (list[i__] < -n1) { ++list[i__]; } /* L8: */ } /* For LPN = first to last neighbors of N1, delete the */ /* preceding neighbor (indexed by LP). */ /* Each empty LIST,LPTR location LP is filled in with the */ /* values at LNW-1, and LNW is decremented. All pointers */ /* (including those in LPTR and LEND) with value LNW-1 */ /* must be changed to LP. */ /* LPL points to the last neighbor of N1. */ L9: if (bdry) { --nnb; } lpn = lpl; i__1 = nnb; for (j = 1; j <= i__1; ++j) { --lnw; lp = lpn; lpn = lptr[lp]; list[lp] = list[lnw]; lptr[lp] = lptr[lnw]; if (lptr[lpn] == lnw) { lptr[lpn] = lp; } if (lpn == lnw) { lpn = lp; } for (i__ = nn; i__ >= 1; --i__) { if (lend[i__] == lnw) { lend[i__] = lp; goto L11; } /* L10: */ } L11: for (i__ = lnw - 1; i__ >= 1; --i__) { if (lptr[i__] == lnw) { lptr[i__] = lp; } /* L12: */ } /* L13: */ } /* Update N and LNEW, and optimize the patch of triangles */ /* containing K (on input) by applying swaps to the arcs */ /* in IWK. */ *n = nn; *lnew = lnw; if (iwl > 0) { nit = iwl << 2; optim_(&x[1], &y[1], &z__[1], &iwl, &list[1], &lptr[1], &lend[1], & nit, &iwk[3], &ierr); if (ierr != 0 && ierr != 1) { goto L25; } if (ierr == 1) { goto L26; } } /* Successful termination. */ *ier = 0; return 0; /* Invalid input parameter. */ L21: *ier = 1; return 0; /* Insufficient space reserved for IWK. */ L22: *ier = 2; return 0; /* Invalid triangulation data structure. NNB < 3 on input or */ /* N2 is a neighbor of N1 but N1 is not a neighbor of N2. */ L23: *ier = 3; return 0; /* N1 is interior but NNB could not be reduced to 3. */ L24: *ier = 4; return 0; /* Error flag (other than 1) returned by OPTIM. */ L25: *ier = 5; return 0; /* Error flag 1 returned by OPTIM. */ L26: *ier = 6; return 0; } /* delnod_ */ /* Subroutine */ int edge_(int *in1, int *in2, double *x, double *y, double *z__, int *lwk, int *iwk, int * list, int *lptr, int *lend, int *ier) { /* System generated locals */ int i__1; /* Local variables */ static int i__, n0, n1, n2; static double x0, x1, x2, y00, y11, y2, z0, z1, z2; static int nl, lp, nr; static double dp12; static int lp21, iwc, iwf, lft, lpl, iwl, nit; static double dp1l, dp2l, dp1r, dp2r; static int ierr; static int next, iwcp1, n1lst, iwend; static int n1frst; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 07/30/98 */ /* Given a triangulation of N nodes and a pair of nodal */ /* indexes IN1 and IN2, this routine swaps arcs as necessary */ /* to force IN1 and IN2 to be adjacent. Only arcs which */ /* intersect IN1-IN2 are swapped out. If a Delaunay triangu- */ /* lation is input, the resulting triangulation is as close */ /* as possible to a Delaunay triangulation in the sense that */ /* all arcs other than IN1-IN2 are locally optimal. */ /* A sequence of calls to EDGE may be used to force the */ /* presence of a set of edges defining the boundary of a non- */ /* convex and/or multiply connected region, or to introduce */ /* barriers into the triangulation. Note that Subroutine */ /* GETNP will not necessarily return closest nodes if the */ /* triangulation has been constrained by a call to EDGE. */ /* However, this is appropriate in some applications, such */ /* as triangle-based interpolation on a nonconvex domain. */ /* On input: */ /* IN1,IN2 = Indexes (of X, Y, and Z) in the range 1 to */ /* N defining a pair of nodes to be connected */ /* by an arc. */ /* X,Y,Z = Arrays of length N containing the Cartesian */ /* coordinates of the nodes. */ /* The above parameters are not altered by this routine. */ /* LWK = Number of columns reserved for IWK. This must */ /* be at least NI -- the number of arcs that */ /* intersect IN1-IN2. (NI is bounded by N-3.) */ /* IWK = int work array of length at least 2*LWK. */ /* LIST,LPTR,LEND = Data structure defining the trian- */ /* gulation. Refer to Subroutine */ /* TRMESH. */ /* On output: */ /* LWK = Number of arcs which intersect IN1-IN2 (but */ /* not more than the input value of LWK) unless */ /* IER = 1 or IER = 3. LWK = 0 if and only if */ /* IN1 and IN2 were adjacent (or LWK=0) on input. */ /* IWK = Array containing the indexes of the endpoints */ /* of the new arcs other than IN1-IN2 unless */ /* IER > 0 or LWK = 0. New arcs to the left of */ /* IN1->IN2 are stored in the first K-1 columns */ /* (left portion of IWK), column K contains */ /* zeros, and new arcs to the right of IN1->IN2 */ /* occupy columns K+1,...,LWK. (K can be deter- */ /* mined by searching IWK for the zeros.) */ /* LIST,LPTR,LEND = Data structure updated if necessary */ /* to reflect the presence of an arc */ /* connecting IN1 and IN2 unless IER > */ /* 0. The data structure has been */ /* altered if IER >= 4. */ /* IER = Error indicator: */ /* IER = 0 if no errors were encountered. */ /* IER = 1 if IN1 < 1, IN2 < 1, IN1 = IN2, */ /* or LWK < 0 on input. */ /* IER = 2 if more space is required in IWK. */ /* Refer to LWK. */ /* IER = 3 if IN1 and IN2 could not be connected */ /* due to either an invalid data struc- */ /* ture or collinear nodes (and floating */ /* point error). */ /* IER = 4 if an error flag other than IER = 1 */ /* was returned by OPTIM. */ /* IER = 5 if error flag 1 was returned by OPTIM. */ /* This is not necessarily an error, but */ /* the arcs other than IN1-IN2 may not */ /* be optimal. */ /* An error message is written to the standard output unit */ /* in the case of IER = 3 or IER = 4. */ /* Modules required by EDGE: LEFT, LSTPTR, OPTIM, SWAP, */ /* SWPTST */ /* Intrinsic function called by EDGE: ABS */ /* *********************************************************** */ /* Local parameters: */ /* DPij = Dot product */ /* I = DO-loop index and column index for IWK */ /* IERR = Error flag returned by Subroutine OPTIM */ /* IWC = IWK index between IWF and IWL -- NL->NR is */ /* stored in IWK(1,IWC)->IWK(2,IWC) */ /* IWCP1 = IWC + 1 */ /* IWEND = Input or output value of LWK */ /* IWF = IWK (column) index of the first (leftmost) arc */ /* which intersects IN1->IN2 */ /* IWL = IWK (column) index of the last (rightmost) are */ /* which intersects IN1->IN2 */ /* LFT = Flag used to determine if a swap results in the */ /* new arc intersecting IN1-IN2 -- LFT = 0 iff */ /* N0 = IN1, LFT = -1 implies N0 LEFT IN1->IN2, */ /* and LFT = 1 implies N0 LEFT IN2->IN1 */ /* LP = List pointer (index for LIST and LPTR) */ /* LP21 = Unused parameter returned by SWAP */ /* LPL = Pointer to the last neighbor of IN1 or NL */ /* N0 = Neighbor of N1 or node opposite NR->NL */ /* N1,N2 = Local copies of IN1 and IN2 */ /* N1FRST = First neighbor of IN1 */ /* N1LST = (Signed) last neighbor of IN1 */ /* NEXT = Node opposite NL->NR */ /* NIT = Flag or number of iterations employed by OPTIM */ /* NL,NR = Endpoints of an arc which intersects IN1-IN2 */ /* with NL LEFT IN1->IN2 */ /* X0,Y0,Z0 = Coordinates of N0 */ /* X1,Y1,Z1 = Coordinates of IN1 */ /* X2,Y2,Z2 = Coordinates of IN2 */ /* Store IN1, IN2, and LWK in local variables and test for */ /* errors. */ /* Parameter adjustments */ --lend; --lptr; --list; iwk -= 3; --z__; --y; --x; /* Function Body */ n1 = *in1; n2 = *in2; iwend = *lwk; if (n1 < 1 || n2 < 1 || n1 == n2 || iwend < 0) { goto L31; } /* Test for N2 as a neighbor of N1. LPL points to the last */ /* neighbor of N1. */ lpl = lend[n1]; n0 = (i__1 = list[lpl], abs(i__1)); lp = lpl; L1: if (n0 == n2) { goto L30; } lp = lptr[lp]; n0 = list[lp]; if (lp != lpl) { goto L1; } /* Initialize parameters. */ iwl = 0; nit = 0; /* Store the coordinates of N1 and N2. */ L2: x1 = x[n1]; y11 = y[n1]; z1 = z__[n1]; x2 = x[n2]; y2 = y[n2]; z2 = z__[n2]; /* Set NR and NL to adjacent neighbors of N1 such that */ /* NR LEFT N2->N1 and NL LEFT N1->N2, */ /* (NR Forward N1->N2 or NL Forward N1->N2), and */ /* (NR Forward N2->N1 or NL Forward N2->N1). */ /* Initialization: Set N1FRST and N1LST to the first and */ /* (signed) last neighbors of N1, respectively, and */ /* initialize NL to N1FRST. */ lpl = lend[n1]; n1lst = list[lpl]; lp = lptr[lpl]; n1frst = list[lp]; nl = n1frst; if (n1lst < 0) { goto L4; } /* N1 is an interior node. Set NL to the first candidate */ /* for NR (NL LEFT N2->N1). */ L3: if (left_(&x2, &y2, &z2, &x1, &y11, &z1, &x[nl], &y[nl], &z__[nl])) { goto L4; } lp = lptr[lp]; nl = list[lp]; if (nl != n1frst) { goto L3; } /* All neighbors of N1 are strictly left of N1->N2. */ goto L5; /* NL = LIST(LP) LEFT N2->N1. Set NR to NL and NL to the */ /* following neighbor of N1. */ L4: nr = nl; lp = lptr[lp]; nl = (i__1 = list[lp], abs(i__1)); if (left_(&x1, &y11, &z1, &x2, &y2, &z2, &x[nl], &y[nl], &z__[nl])) { /* NL LEFT N1->N2 and NR LEFT N2->N1. The Forward tests */ /* are employed to avoid an error associated with */ /* collinear nodes. */ dp12 = x1 * x2 + y11 * y2 + z1 * z2; dp1l = x1 * x[nl] + y11 * y[nl] + z1 * z__[nl]; dp2l = x2 * x[nl] + y2 * y[nl] + z2 * z__[nl]; dp1r = x1 * x[nr] + y11 * y[nr] + z1 * z__[nr]; dp2r = x2 * x[nr] + y2 * y[nr] + z2 * z__[nr]; if ((dp2l - dp12 * dp1l >= 0. || dp2r - dp12 * dp1r >= 0.) && (dp1l - dp12 * dp2l >= 0. || dp1r - dp12 * dp2r >= 0.)) { goto L6; } /* NL-NR does not intersect N1-N2. However, there is */ /* another candidate for the first arc if NL lies on */ /* the line N1-N2. */ if (! left_(&x2, &y2, &z2, &x1, &y11, &z1, &x[nl], &y[nl], &z__[nl])) { goto L5; } } /* Bottom of loop. */ if (nl != n1frst) { goto L4; } /* Either the triangulation is invalid or N1-N2 lies on the */ /* convex hull boundary and an edge NR->NL (opposite N1 and */ /* intersecting N1-N2) was not found due to floating point */ /* error. Try interchanging N1 and N2 -- NIT > 0 iff this */ /* has already been done. */ L5: if (nit > 0) { goto L33; } nit = 1; n1 = n2; n2 = *in1; goto L2; /* Store the ordered sequence of intersecting edges NL->NR in */ /* IWK(1,IWL)->IWK(2,IWL). */ L6: ++iwl; if (iwl > iwend) { goto L32; } iwk[(iwl << 1) + 1] = nl; iwk[(iwl << 1) + 2] = nr; /* Set NEXT to the neighbor of NL which follows NR. */ lpl = lend[nl]; lp = lptr[lpl]; /* Find NR as a neighbor of NL. The search begins with */ /* the first neighbor. */ L7: if (list[lp] == nr) { goto L8; } lp = lptr[lp]; if (lp != lpl) { goto L7; } /* NR must be the last neighbor, and NL->NR cannot be a */ /* boundary edge. */ if (list[lp] != nr) { goto L33; } /* Set NEXT to the neighbor following NR, and test for */ /* termination of the store loop. */ L8: lp = lptr[lp]; next = (i__1 = list[lp], abs(i__1)); if (next == n2) { goto L9; } /* Set NL or NR to NEXT. */ if (left_(&x1, &y11, &z1, &x2, &y2, &z2, &x[next], &y[next], &z__[next])) { nl = next; } else { nr = next; } goto L6; /* IWL is the number of arcs which intersect N1-N2. */ /* Store LWK. */ L9: *lwk = iwl; iwend = iwl; /* Initialize for edge swapping loop -- all possible swaps */ /* are applied (even if the new arc again intersects */ /* N1-N2), arcs to the left of N1->N2 are stored in the */ /* left portion of IWK, and arcs to the right are stored in */ /* the right portion. IWF and IWL index the first and last */ /* intersecting arcs. */ iwf = 1; /* Top of loop -- set N0 to N1 and NL->NR to the first edge. */ /* IWC points to the arc currently being processed. LFT */ /* .LE. 0 iff N0 LEFT N1->N2. */ L10: lft = 0; n0 = n1; x0 = x1; y00 = y11; z0 = z1; nl = iwk[(iwf << 1) + 1]; nr = iwk[(iwf << 1) + 2]; iwc = iwf; /* Set NEXT to the node opposite NL->NR unless IWC is the */ /* last arc. */ L11: if (iwc == iwl) { goto L21; } iwcp1 = iwc + 1; next = iwk[(iwcp1 << 1) + 1]; if (next != nl) { goto L16; } next = iwk[(iwcp1 << 1) + 2]; /* NEXT RIGHT N1->N2 and IWC .LT. IWL. Test for a possible */ /* swap. */ if (! left_(&x0, &y00, &z0, &x[nr], &y[nr], &z__[nr], &x[next], &y[next], & z__[next])) { goto L14; } if (lft >= 0) { goto L12; } if (! left_(&x[nl], &y[nl], &z__[nl], &x0, &y00, &z0, &x[next], &y[next], & z__[next])) { goto L14; } /* Replace NL->NR with N0->NEXT. */ swap_(&next, &n0, &nl, &nr, &list[1], &lptr[1], &lend[1], &lp21); iwk[(iwc << 1) + 1] = n0; iwk[(iwc << 1) + 2] = next; goto L15; /* Swap NL-NR for N0-NEXT, shift columns IWC+1,...,IWL to */ /* the left, and store N0-NEXT in the right portion of */ /* IWK. */ L12: swap_(&next, &n0, &nl, &nr, &list[1], &lptr[1], &lend[1], &lp21); i__1 = iwl; for (i__ = iwcp1; i__ <= i__1; ++i__) { iwk[((i__ - 1) << 1) + 1] = iwk[(i__ << 1) + 1]; iwk[((i__ - 1) << 1) + 2] = iwk[(i__ << 1) + 2]; /* L13: */ } iwk[(iwl << 1) + 1] = n0; iwk[(iwl << 1) + 2] = next; --iwl; nr = next; goto L11; /* A swap is not possible. Set N0 to NR. */ L14: n0 = nr; x0 = x[n0]; y00 = y[n0]; z0 = z__[n0]; lft = 1; /* Advance to the next arc. */ L15: nr = next; ++iwc; goto L11; /* NEXT LEFT N1->N2, NEXT .NE. N2, and IWC .LT. IWL. */ /* Test for a possible swap. */ L16: if (! left_(&x[nl], &y[nl], &z__[nl], &x0, &y00, &z0, &x[next], &y[next], & z__[next])) { goto L19; } if (lft <= 0) { goto L17; } if (! left_(&x0, &y00, &z0, &x[nr], &y[nr], &z__[nr], &x[next], &y[next], & z__[next])) { goto L19; } /* Replace NL->NR with NEXT->N0. */ swap_(&next, &n0, &nl, &nr, &list[1], &lptr[1], &lend[1], &lp21); iwk[(iwc << 1) + 1] = next; iwk[(iwc << 1) + 2] = n0; goto L20; /* Swap NL-NR for N0-NEXT, shift columns IWF,...,IWC-1 to */ /* the right, and store N0-NEXT in the left portion of */ /* IWK. */ L17: swap_(&next, &n0, &nl, &nr, &list[1], &lptr[1], &lend[1], &lp21); i__1 = iwf; for (i__ = iwc - 1; i__ >= i__1; --i__) { iwk[((i__ + 1) << 1) + 1] = iwk[(i__ << 1) + 1]; iwk[((i__ + 1) << 1) + 2] = iwk[(i__ << 1) + 2]; /* L18: */ } iwk[(iwf << 1) + 1] = n0; iwk[(iwf << 1) + 2] = next; ++iwf; goto L20; /* A swap is not possible. Set N0 to NL. */ L19: n0 = nl; x0 = x[n0]; y00 = y[n0]; z0 = z__[n0]; lft = -1; /* Advance to the next arc. */ L20: nl = next; ++iwc; goto L11; /* N2 is opposite NL->NR (IWC = IWL). */ L21: if (n0 == n1) { goto L24; } if (lft < 0) { goto L22; } /* N0 RIGHT N1->N2. Test for a possible swap. */ if (! left_(&x0, &y00, &z0, &x[nr], &y[nr], &z__[nr], &x2, &y2, &z2)) { goto L10; } /* Swap NL-NR for N0-N2 and store N0-N2 in the right */ /* portion of IWK. */ swap_(&n2, &n0, &nl, &nr, &list[1], &lptr[1], &lend[1], &lp21); iwk[(iwl << 1) + 1] = n0; iwk[(iwl << 1) + 2] = n2; --iwl; goto L10; /* N0 LEFT N1->N2. Test for a possible swap. */ L22: if (! left_(&x[nl], &y[nl], &z__[nl], &x0, &y00, &z0, &x2, &y2, &z2)) { goto L10; } /* Swap NL-NR for N0-N2, shift columns IWF,...,IWL-1 to the */ /* right, and store N0-N2 in the left portion of IWK. */ swap_(&n2, &n0, &nl, &nr, &list[1], &lptr[1], &lend[1], &lp21); i__ = iwl; L23: iwk[(i__ << 1) + 1] = iwk[((i__ - 1) << 1) + 1]; iwk[(i__ << 1) + 2] = iwk[((i__ - 1) << 1) + 2]; --i__; if (i__ > iwf) { goto L23; } iwk[(iwf << 1) + 1] = n0; iwk[(iwf << 1) + 2] = n2; ++iwf; goto L10; /* IWF = IWC = IWL. Swap out the last arc for N1-N2 and */ /* store zeros in IWK. */ L24: swap_(&n2, &n1, &nl, &nr, &list[1], &lptr[1], &lend[1], &lp21); iwk[(iwc << 1) + 1] = 0; iwk[(iwc << 1) + 2] = 0; /* Optimization procedure -- */ *ier = 0; if (iwc > 1) { /* Optimize the set of new arcs to the left of IN1->IN2. */ nit = (iwc - 1) << 2; i__1 = iwc - 1; optim_(&x[1], &y[1], &z__[1], &i__1, &list[1], &lptr[1], &lend[1], & nit, &iwk[3], &ierr); if (ierr != 0 && ierr != 1) { goto L34; } if (ierr == 1) { *ier = 5; } } if (iwc < iwend) { /* Optimize the set of new arcs to the right of IN1->IN2. */ nit = (iwend - iwc) << 2; i__1 = iwend - iwc; optim_(&x[1], &y[1], &z__[1], &i__1, &list[1], &lptr[1], &lend[1], & nit, &iwk[((iwc + 1) << 1) + 1], &ierr); if (ierr != 0 && ierr != 1) { goto L34; } if (ierr == 1) { goto L35; } } if (*ier == 5) { goto L35; } /* Successful termination (IER = 0). */ return 0; /* IN1 and IN2 were adjacent on input. */ L30: *ier = 0; return 0; /* Invalid input parameter. */ L31: *ier = 1; return 0; /* Insufficient space reserved for IWK. */ L32: *ier = 2; return 0; /* Invalid triangulation data structure or collinear nodes */ /* on convex hull boundary. */ L33: *ier = 3; return 0; /* Error flag (other than 1) returned by OPTIM. */ L34: *ier = 4; return 0; /* Error flag 1 returned by OPTIM. */ L35: *ier = 5; return 0; } /* edge_ */ /* Subroutine */ int getnp_(double *x, double *y, double *z__, int *list, int *lptr, int *lend, int *l, int * npts, double *df, int *ier) { /* System generated locals */ int i__1, i__2; /* Local variables */ static int i__, n1; static double x1, y11, z1; static int nb, ni, lp, np, lm1; static double dnb, dnp; static int lpl; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 07/28/98 */ /* Given a Delaunay triangulation of N nodes on the unit */ /* sphere and an array NPTS containing the indexes of L-1 */ /* nodes ordered by angular distance from NPTS(1), this sub- */ /* routine sets NPTS(L) to the index of the next node in the */ /* sequence -- the node, other than NPTS(1),...,NPTS(L-1), */ /* that is closest to NPTS(1). Thus, the ordered sequence */ /* of K closest nodes to N1 (including N1) may be determined */ /* by K-1 calls to GETNP with NPTS(1) = N1 and L = 2,3,...,K */ /* for K .GE. 2. */ /* The algorithm uses the property of a Delaunay triangula- */ /* tion that the K-th closest node to N1 is a neighbor of one */ /* of the K-1 closest nodes to N1. */ /* On input: */ /* X,Y,Z = Arrays of length N containing the Cartesian */ /* coordinates of the nodes. */ /* LIST,LPTR,LEND = Triangulation data structure. Re- */ /* fer to Subroutine TRMESH. */ /* L = Number of nodes in the sequence on output. 2 */ /* .LE. L .LE. N. */ /* The above parameters are not altered by this routine. */ /* NPTS = Array of length .GE. L containing the indexes */ /* of the L-1 closest nodes to NPTS(1) in the */ /* first L-1 locations. */ /* On output: */ /* NPTS = Array updated with the index of the L-th */ /* closest node to NPTS(1) in position L unless */ /* IER = 1. */ /* DF = Value of an increasing function (negative cos- */ /* ine) of the angular distance between NPTS(1) */ /* and NPTS(L) unless IER = 1. */ /* IER = Error indicator: */ /* IER = 0 if no errors were encountered. */ /* IER = 1 if L < 2. */ /* Modules required by GETNP: None */ /* Intrinsic function called by GETNP: ABS */ /* *********************************************************** */ /* Local parameters: */ /* DNB,DNP = Negative cosines of the angular distances from */ /* N1 to NB and to NP, respectively */ /* I = NPTS index and DO-loop index */ /* LM1 = L-1 */ /* LP = LIST pointer of a neighbor of NI */ /* LPL = Pointer to the last neighbor of NI */ /* N1 = NPTS(1) */ /* NB = Neighbor of NI and candidate for NP */ /* NI = NPTS(I) */ /* NP = Candidate for NPTS(L) */ /* X1,Y1,Z1 = Coordinates of N1 */ /* Parameter adjustments */ --x; --y; --z__; --list; --lptr; --lend; --npts; /* Function Body */ lm1 = *l - 1; if (lm1 < 1) { goto L6; } *ier = 0; /* Store N1 = NPTS(1) and mark the elements of NPTS. */ n1 = npts[1]; x1 = x[n1]; y11 = y[n1]; z1 = z__[n1]; i__1 = lm1; for (i__ = 1; i__ <= i__1; ++i__) { ni = npts[i__]; lend[ni] = -lend[ni]; /* L1: */ } /* Candidates for NP = NPTS(L) are the unmarked neighbors */ /* of nodes in NPTS. DNP is initially greater than -cos(PI) */ /* (the maximum distance). */ dnp = 2.; /* Loop on nodes NI in NPTS. */ i__1 = lm1; for (i__ = 1; i__ <= i__1; ++i__) { ni = npts[i__]; lpl = -lend[ni]; lp = lpl; /* Loop on neighbors NB of NI. */ L2: nb = (i__2 = list[lp], abs(i__2)); if (lend[nb] < 0) { goto L3; } /* NB is an unmarked neighbor of NI. Replace NP if NB is */ /* closer to N1. */ dnb = -(x[nb] * x1 + y[nb] * y11 + z__[nb] * z1); if (dnb >= dnp) { goto L3; } np = nb; dnp = dnb; L3: lp = lptr[lp]; if (lp != lpl) { goto L2; } /* L4: */ } npts[*l] = np; *df = dnp; /* Unmark the elements of NPTS. */ i__1 = lm1; for (i__ = 1; i__ <= i__1; ++i__) { ni = npts[i__]; lend[ni] = -lend[ni]; /* L5: */ } return 0; /* L is outside its valid range. */ L6: *ier = 1; return 0; } /* getnp_ */ /* Subroutine */ int insert_(int *k, int *lp, int *list, int * lptr, int *lnew) { static int lsav; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 07/17/96 */ /* This subroutine inserts K as a neighbor of N1 following */ /* N2, where LP is the LIST pointer of N2 as a neighbor of */ /* N1. Note that, if N2 is the last neighbor of N1, K will */ /* become the first neighbor (even if N1 is a boundary node). */ /* This routine is identical to the similarly named routine */ /* in TRIPACK. */ /* On input: */ /* K = Index of the node to be inserted. */ /* LP = LIST pointer of N2 as a neighbor of N1. */ /* The above parameters are not altered by this routine. */ /* LIST,LPTR,LNEW = Data structure defining the trian- */ /* gulation. Refer to Subroutine */ /* TRMESH. */ /* On output: */ /* LIST,LPTR,LNEW = Data structure updated with the */ /* addition of node K. */ /* Modules required by INSERT: None */ /* *********************************************************** */ /* Parameter adjustments */ --lptr; --list; /* Function Body */ lsav = lptr[*lp]; lptr[*lp] = *lnew; list[*lnew] = *k; lptr[*lnew] = lsav; ++(*lnew); return 0; } /* insert_ */ int inside_(double *p, int *lv, double *xv, double *yv, double *zv, int *nv, int *listv, int *ier) { /* Initialized data */ static double eps = .001; /* System generated locals */ int i__1; int ret_val = 0; /* Local variables */ static double b[3], d__; static int k, n; static double q[3]; static int i1, i2, k0; static double v1[3], v2[3], cn[3], bp, bq; static int ni; static double pn[3], qn[3], vn[3]; static int imx; static int lft1, lft2, even; static int ierr; static int pinr, qinr; static double qnrm, vnrm; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 12/27/93 */ /* This function locates a point P relative to a polygonal */ /* region R on the surface of the unit sphere, returning */ /* INSIDE = TRUE if and only if P is contained in R. R is */ /* defined by a cyclically ordered sequence of vertices which */ /* form a positively-oriented simple closed curve. Adjacent */ /* vertices need not be distinct but the curve must not be */ /* self-intersecting. Also, while polygon edges are by defi- */ /* nition restricted to a single hemisphere, R is not so */ /* restricted. Its interior is the region to the left as the */ /* vertices are traversed in order. */ /* The algorithm consists of selecting a point Q in R and */ /* then finding all points at which the great circle defined */ /* by P and Q intersects the boundary of R. P lies inside R */ /* if and only if there is an even number of intersection */ /* points between Q and P. Q is taken to be a point immedi- */ /* ately to the left of a directed boundary edge -- the first */ /* one that results in no consistency-check failures. */ /* If P is close to the polygon boundary, the problem is */ /* ill-conditioned and the decision may be incorrect. Also, */ /* an incorrect decision may result from a poor choice of Q */ /* (if, for example, a boundary edge lies on the great cir- */ /* cle defined by P and Q). A more reliable result could be */ /* obtained by a sequence of calls to INSIDE with the ver- */ /* tices cyclically permuted before each call (to alter the */ /* choice of Q). */ /* On input: */ /* P = Array of length 3 containing the Cartesian */ /* coordinates of the point (unit vector) to be */ /* located. */ /* LV = Length of arrays XV, YV, and ZV. */ /* XV,YV,ZV = Arrays of length LV containing the Carte- */ /* sian coordinates of unit vectors (points */ /* on the unit sphere). These values are */ /* not tested for validity. */ /* NV = Number of vertices in the polygon. 3 .LE. NV */ /* .LE. LV. */ /* LISTV = Array of length NV containing the indexes */ /* (for XV, YV, and ZV) of a cyclically-ordered */ /* (and CCW-ordered) sequence of vertices that */ /* define R. The last vertex (indexed by */ /* LISTV(NV)) is followed by the first (indexed */ /* by LISTV(1)). LISTV entries must be in the */ /* range 1 to LV. */ /* Input parameters are not altered by this function. */ /* On output: */ /* INSIDE = TRUE if and only if P lies inside R unless */ /* IER .NE. 0, in which case the value is not */ /* altered. */ /* IER = Error indicator: */ /* IER = 0 if no errors were encountered. */ /* IER = 1 if LV or NV is outside its valid */ /* range. */ /* IER = 2 if a LISTV entry is outside its valid */ /* range. */ /* IER = 3 if the polygon boundary was found to */ /* be self-intersecting. This error will */ /* not necessarily be detected. */ /* IER = 4 if every choice of Q (one for each */ /* boundary edge) led to failure of some */ /* internal consistency check. The most */ /* likely cause of this error is invalid */ /* input: P = (0,0,0), a null or self- */ /* intersecting polygon, etc. */ /* Module required by INSIDE: INTRSC */ /* Intrinsic function called by INSIDE: SQRT */ /* *********************************************************** */ /* Local parameters: */ /* B = Intersection point between the boundary and */ /* the great circle defined by P and Q */ /* BP,BQ = and , respectively, maximized over */ /* intersection points B that lie between P and */ /* Q (on the shorter arc) -- used to find the */ /* closest intersection points to P and Q */ /* CN = Q X P = normal to the plane of P and Q */ /* D = Dot product or */ /* EPS = Parameter used to define Q as the point whose */ /* orthogonal distance to (the midpoint of) */ /* boundary edge V1->V2 is approximately EPS/ */ /* (2*Cos(A/2)), where = Cos(A). */ /* EVEN = TRUE iff an even number of intersection points */ /* lie between P and Q (on the shorter arc) */ /* I1,I2 = Indexes (LISTV elements) of a pair of adjacent */ /* boundary vertices (endpoints of a boundary */ /* edge) */ /* IERR = Error flag for calls to INTRSC (not tested) */ /* IMX = Local copy of LV and maximum value of I1 and */ /* I2 */ /* K = DO-loop index and LISTV index */ /* K0 = LISTV index of the first endpoint of the */ /* boundary edge used to compute Q */ /* LFT1,LFT2 = Logical variables associated with I1 and I2 in */ /* the boundary traversal: TRUE iff the vertex */ /* is strictly to the left of Q->P ( > 0) */ /* N = Local copy of NV */ /* NI = Number of intersections (between the boundary */ /* curve and the great circle P-Q) encountered */ /* PINR = TRUE iff P is to the left of the directed */ /* boundary edge associated with the closest */ /* intersection point to P that lies between P */ /* and Q (a left-to-right intersection as */ /* viewed from Q), or there is no intersection */ /* between P and Q (on the shorter arc) */ /* PN,QN = P X CN and CN X Q, respectively: used to */ /* locate intersections B relative to arc Q->P */ /* Q = (V1 + V2 + EPS*VN/VNRM)/QNRM, where V1->V2 is */ /* the boundary edge indexed by LISTV(K0) -> */ /* LISTV(K0+1) */ /* QINR = TRUE iff Q is to the left of the directed */ /* boundary edge associated with the closest */ /* intersection point to Q that lies between P */ /* and Q (a right-to-left intersection as */ /* viewed from Q), or there is no intersection */ /* between P and Q (on the shorter arc) */ /* QNRM = Euclidean norm of V1+V2+EPS*VN/VNRM used to */ /* compute (normalize) Q */ /* V1,V2 = Vertices indexed by I1 and I2 in the boundary */ /* traversal */ /* VN = V1 X V2, where V1->V2 is the boundary edge */ /* indexed by LISTV(K0) -> LISTV(K0+1) */ /* VNRM = Euclidean norm of VN */ /* Parameter adjustments */ --p; --zv; --yv; --xv; --listv; /* Function Body */ /* Store local parameters, test for error 1, and initialize */ /* K0. */ imx = *lv; n = *nv; if (n < 3 || n > imx) { goto L11; } k0 = 0; i1 = listv[1]; if (i1 < 1 || i1 > imx) { goto L12; } /* Increment K0 and set Q to a point immediately to the left */ /* of the midpoint of edge V1->V2 = LISTV(K0)->LISTV(K0+1): */ /* Q = (V1 + V2 + EPS*VN/VNRM)/QNRM, where VN = V1 X V2. */ L1: ++k0; if (k0 > n) { goto L14; } i1 = listv[k0]; if (k0 < n) { i2 = listv[k0 + 1]; } else { i2 = listv[1]; } if (i2 < 1 || i2 > imx) { goto L12; } vn[0] = yv[i1] * zv[i2] - zv[i1] * yv[i2]; vn[1] = zv[i1] * xv[i2] - xv[i1] * zv[i2]; vn[2] = xv[i1] * yv[i2] - yv[i1] * xv[i2]; vnrm = sqrt(vn[0] * vn[0] + vn[1] * vn[1] + vn[2] * vn[2]); if (vnrm == 0.) { goto L1; } q[0] = xv[i1] + xv[i2] + eps * vn[0] / vnrm; q[1] = yv[i1] + yv[i2] + eps * vn[1] / vnrm; q[2] = zv[i1] + zv[i2] + eps * vn[2] / vnrm; qnrm = sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2]); q[0] /= qnrm; q[1] /= qnrm; q[2] /= qnrm; /* Compute CN = Q X P, PN = P X CN, and QN = CN X Q. */ cn[0] = q[1] * p[3] - q[2] * p[2]; cn[1] = q[2] * p[1] - q[0] * p[3]; cn[2] = q[0] * p[2] - q[1] * p[1]; if (cn[0] == 0. && cn[1] == 0. && cn[2] == 0.) { goto L1; } pn[0] = p[2] * cn[2] - p[3] * cn[1]; pn[1] = p[3] * cn[0] - p[1] * cn[2]; pn[2] = p[1] * cn[1] - p[2] * cn[0]; qn[0] = cn[1] * q[2] - cn[2] * q[1]; qn[1] = cn[2] * q[0] - cn[0] * q[2]; qn[2] = cn[0] * q[1] - cn[1] * q[0]; /* Initialize parameters for the boundary traversal. */ ni = 0; even = TRUE_; bp = -2.; bq = -2.; pinr = TRUE_; qinr = TRUE_; i2 = listv[n]; if (i2 < 1 || i2 > imx) { goto L12; } lft2 = cn[0] * xv[i2] + cn[1] * yv[i2] + cn[2] * zv[i2] > 0.; /* Loop on boundary arcs I1->I2. */ i__1 = n; for (k = 1; k <= i__1; ++k) { i1 = i2; lft1 = lft2; i2 = listv[k]; if (i2 < 1 || i2 > imx) { goto L12; } lft2 = cn[0] * xv[i2] + cn[1] * yv[i2] + cn[2] * zv[i2] > 0.; if (lft1 == lft2) { goto L2; } /* I1 and I2 are on opposite sides of Q->P. Compute the */ /* point of intersection B. */ ++ni; v1[0] = xv[i1]; v1[1] = yv[i1]; v1[2] = zv[i1]; v2[0] = xv[i2]; v2[1] = yv[i2]; v2[2] = zv[i2]; intrsc_(v1, v2, cn, b, &ierr); /* B is between Q and P (on the shorter arc) iff */ /* B Forward Q->P and B Forward P->Q iff */ /* > 0 and > 0. */ if (b[0] * qn[0] + b[1] * qn[1] + b[2] * qn[2] > 0. && b[0] * pn[0] + b[1] * pn[1] + b[2] * pn[2] > 0.) { /* Update EVEN, BQ, QINR, BP, and PINR. */ even = ! even; d__ = b[0] * q[0] + b[1] * q[1] + b[2] * q[2]; if (d__ > bq) { bq = d__; qinr = lft2; } d__ = b[0] * p[1] + b[1] * p[2] + b[2] * p[3]; if (d__ > bp) { bp = d__; pinr = lft1; } } L2: ; } /* Test for consistency: NI must be even and QINR must be */ /* TRUE. */ if (ni != ni / 2 << 1 || ! qinr) { goto L1; } /* Test for error 3: different values of PINR and EVEN. */ if (pinr != even) { goto L13; } /* No error encountered. */ *ier = 0; ret_val = even; return ret_val; /* LV or NV is outside its valid range. */ L11: *ier = 1; return ret_val; /* A LISTV entry is outside its valid range. */ L12: *ier = 2; return ret_val; /* The polygon boundary is self-intersecting. */ L13: *ier = 3; return ret_val; /* Consistency tests failed for all values of Q. */ L14: *ier = 4; return ret_val; } /* inside_ */ /* Subroutine */ int intadd_(int *kk, int *i1, int *i2, int * i3, int *list, int *lptr, int *lend, int *lnew) { static int k, n1, n2, n3, lp; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 07/17/96 */ /* This subroutine adds an interior node to a triangulation */ /* of a set of points on the unit sphere. The data structure */ /* is updated with the insertion of node KK into the triangle */ /* whose vertices are I1, I2, and I3. No optimization of the */ /* triangulation is performed. */ /* This routine is identical to the similarly named routine */ /* in TRIPACK. */ /* On input: */ /* KK = Index of the node to be inserted. KK .GE. 1 */ /* and KK must not be equal to I1, I2, or I3. */ /* I1,I2,I3 = Indexes of the counterclockwise-ordered */ /* sequence of vertices of a triangle which */ /* contains node KK. */ /* The above parameters are not altered by this routine. */ /* LIST,LPTR,LEND,LNEW = Data structure defining the */ /* triangulation. Refer to Sub- */ /* routine TRMESH. Triangle */ /* (I1,I2,I3) must be included */ /* in the triangulation. */ /* On output: */ /* LIST,LPTR,LEND,LNEW = Data structure updated with */ /* the addition of node KK. KK */ /* will be connected to nodes I1, */ /* I2, and I3. */ /* Modules required by INTADD: INSERT, LSTPTR */ /* *********************************************************** */ /* Local parameters: */ /* K = Local copy of KK */ /* LP = LIST pointer */ /* N1,N2,N3 = Local copies of I1, I2, and I3 */ /* Parameter adjustments */ --lend; --lptr; --list; /* Function Body */ k = *kk; /* Initialization. */ n1 = *i1; n2 = *i2; n3 = *i3; /* Add K as a neighbor of I1, I2, and I3. */ lp = lstptr_(&lend[n1], &n2, &list[1], &lptr[1]); insert_(&k, &lp, &list[1], &lptr[1], lnew); lp = lstptr_(&lend[n2], &n3, &list[1], &lptr[1]); insert_(&k, &lp, &list[1], &lptr[1], lnew); lp = lstptr_(&lend[n3], &n1, &list[1], &lptr[1]); insert_(&k, &lp, &list[1], &lptr[1], lnew); /* Add I1, I2, and I3 as neighbors of K. */ list[*lnew] = n1; list[*lnew + 1] = n2; list[*lnew + 2] = n3; lptr[*lnew] = *lnew + 1; lptr[*lnew + 1] = *lnew + 2; lptr[*lnew + 2] = *lnew; lend[k] = *lnew + 2; *lnew += 3; return 0; } /* intadd_ */ /* Subroutine */ int intrsc_(double *p1, double *p2, double *cn, double *p, int *ier) { /* Local variables */ static int i__; static double t, d1, d2, pp[3], ppn; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 07/19/90 */ /* Given a great circle C and points P1 and P2 defining an */ /* arc A on the surface of the unit sphere, where A is the */ /* shorter of the two portions of the great circle C12 assoc- */ /* iated with P1 and P2, this subroutine returns the point */ /* of intersection P between C and C12 that is closer to A. */ /* Thus, if P1 and P2 lie in opposite hemispheres defined by */ /* C, P is the point of intersection of C with A. */ /* On input: */ /* P1,P2 = Arrays of length 3 containing the Cartesian */ /* coordinates of unit vectors. */ /* CN = Array of length 3 containing the Cartesian */ /* coordinates of a nonzero vector which defines C */ /* as the intersection of the plane whose normal */ /* is CN with the unit sphere. Thus, if C is to */ /* be the great circle defined by P and Q, CN */ /* should be P X Q. */ /* The above parameters are not altered by this routine. */ /* P = Array of length 3. */ /* On output: */ /* P = Point of intersection defined above unless IER */ /* .NE. 0, in which case P is not altered. */ /* IER = Error indicator. */ /* IER = 0 if no errors were encountered. */ /* IER = 1 if = . This occurs */ /* iff P1 = P2 or CN = 0 or there are */ /* two intersection points at the same */ /* distance from A. */ /* IER = 2 if P2 = -P1 and the definition of A is */ /* therefore ambiguous. */ /* Modules required by INTRSC: None */ /* Intrinsic function called by INTRSC: SQRT */ /* *********************************************************** */ /* Local parameters: */ /* D1 = */ /* D2 = */ /* I = DO-loop index */ /* PP = P1 + T*(P2-P1) = Parametric representation of the */ /* line defined by P1 and P2 */ /* PPN = Norm of PP */ /* T = D1/(D1-D2) = Parameter value chosen so that PP lies */ /* in the plane of C */ /* Parameter adjustments */ --p; --cn; --p2; --p1; /* Function Body */ d1 = cn[1] * p1[1] + cn[2] * p1[2] + cn[3] * p1[3]; d2 = cn[1] * p2[1] + cn[2] * p2[2] + cn[3] * p2[3]; if (d1 == d2) { *ier = 1; return 0; } /* Solve for T such that = 0 and compute PP and PPN. */ t = d1 / (d1 - d2); ppn = 0.; for (i__ = 1; i__ <= 3; ++i__) { pp[i__ - 1] = p1[i__] + t * (p2[i__] - p1[i__]); ppn += pp[i__ - 1] * pp[i__ - 1]; /* L1: */ } /* PPN = 0 iff PP = 0 iff P2 = -P1 (and T = .5). */ if (ppn == 0.) { *ier = 2; return 0; } ppn = sqrt(ppn); /* Compute P = PP/PPN. */ for (i__ = 1; i__ <= 3; ++i__) { p[i__] = pp[i__ - 1] / ppn; /* L2: */ } *ier = 0; return 0; } /* intrsc_ */ int jrand_(int *n, int *ix, int *iy, int *iz) { /* System generated locals */ int ret_val; /* Local variables */ static double u, x; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 07/28/98 */ /* This function returns a uniformly distributed pseudo- */ /* random int in the range 1 to N. */ /* On input: */ /* N = Maximum value to be returned. */ /* N is not altered by this function. */ /* IX,IY,IZ = int seeds initialized to values in */ /* the range 1 to 30,000 before the first */ /* call to JRAND, and not altered between */ /* subsequent calls (unless a sequence of */ /* random numbers is to be repeated by */ /* reinitializing the seeds). */ /* On output: */ /* IX,IY,IZ = Updated int seeds. */ /* JRAND = Random int in the range 1 to N. */ /* Reference: B. A. Wichmann and I. D. Hill, "An Efficient */ /* and Portable Pseudo-random Number Generator", */ /* Applied Statistics, Vol. 31, No. 2, 1982, */ /* pp. 188-190. */ /* Modules required by JRAND: None */ /* Intrinsic functions called by JRAND: INT, MOD, REAL */ /* *********************************************************** */ /* Local parameters: */ /* U = Pseudo-random number uniformly distributed in the */ /* interval (0,1). */ /* X = Pseudo-random number in the range 0 to 3 whose frac- */ /* tional part is U. */ *ix = *ix * 171 % 30269; *iy = *iy * 172 % 30307; *iz = *iz * 170 % 30323; x = (double) (*ix) / 30269. + (double) (*iy) / 30307. + ( double) (*iz) / 30323.; u = x - (int) x; ret_val = (int) ((double) (*n) * u + 1.); return ret_val; } /* jrand_ */ int left_(double *x1, double *y11, double *z1, double *x2, double *y2, double *z2, double *x0, double *y00, double *z0) { /* System generated locals */ int ret_val; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 07/15/96 */ /* This function determines whether node N0 is in the */ /* (closed) left hemisphere defined by the plane containing */ /* N1, N2, and the origin, where left is defined relative to */ /* an observer at N1 facing N2. */ /* On input: */ /* X1,Y1,Z1 = Coordinates of N1. */ /* X2,Y2,Z2 = Coordinates of N2. */ /* X0,Y0,Z0 = Coordinates of N0. */ /* Input parameters are not altered by this function. */ /* On output: */ /* LEFT = TRUE if and only if N0 is in the closed */ /* left hemisphere. */ /* Modules required by LEFT: None */ /* *********************************************************** */ /* LEFT = TRUE iff = det(N0,N1,N2) .GE. 0. */ ret_val = *x0 * (*y11 * *z2 - *y2 * *z1) - *y00 * (*x1 * *z2 - *x2 * *z1) + *z0 * (*x1 * *y2 - *x2 * *y11) >= 0.; return ret_val; } /* left_ */ int lstptr_(int *lpl, int *nb, int *list, int *lptr) { /* System generated locals */ int ret_val; /* Local variables */ static int nd, lp; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 07/15/96 */ /* This function returns the index (LIST pointer) of NB in */ /* the adjacency list for N0, where LPL = LEND(N0). */ /* This function is identical to the similarly named */ /* function in TRIPACK. */ /* On input: */ /* LPL = LEND(N0) */ /* NB = Index of the node whose pointer is to be re- */ /* turned. NB must be connected to N0. */ /* LIST,LPTR = Data structure defining the triangula- */ /* tion. Refer to Subroutine TRMESH. */ /* Input parameters are not altered by this function. */ /* On output: */ /* LSTPTR = Pointer such that LIST(LSTPTR) = NB or */ /* LIST(LSTPTR) = -NB, unless NB is not a */ /* neighbor of N0, in which case LSTPTR = LPL. */ /* Modules required by LSTPTR: None */ /* *********************************************************** */ /* Local parameters: */ /* LP = LIST pointer */ /* ND = Nodal index */ /* Parameter adjustments */ --lptr; --list; /* Function Body */ lp = lptr[*lpl]; L1: nd = list[lp]; if (nd == *nb) { goto L2; } lp = lptr[lp]; if (lp != *lpl) { goto L1; } L2: ret_val = lp; return ret_val; } /* lstptr_ */ int nbcnt_(int *lpl, int *lptr) { /* System generated locals */ int ret_val; /* Local variables */ static int k, lp; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 07/15/96 */ /* This function returns the number of neighbors of a node */ /* N0 in a triangulation created by Subroutine TRMESH. */ /* This function is identical to the similarly named */ /* function in TRIPACK. */ /* On input: */ /* LPL = LIST pointer to the last neighbor of N0 -- */ /* LPL = LEND(N0). */ /* LPTR = Array of pointers associated with LIST. */ /* Input parameters are not altered by this function. */ /* On output: */ /* NBCNT = Number of neighbors of N0. */ /* Modules required by NBCNT: None */ /* *********************************************************** */ /* Local parameters: */ /* K = Counter for computing the number of neighbors */ /* LP = LIST pointer */ /* Parameter adjustments */ --lptr; /* Function Body */ lp = *lpl; k = 1; L1: lp = lptr[lp]; if (lp == *lpl) { goto L2; } ++k; goto L1; L2: ret_val = k; return ret_val; } /* nbcnt_ */ int nearnd_(double *p, int *ist, int *n, double *x, double *y, double *z__, int *list, int *lptr, int *lend, double *al) { /* System generated locals */ int ret_val, i__1; /* Local variables */ static int l; static double b1, b2, b3; static int i1, i2, i3, n1, n2, n3, lp, nn, nr; static double ds1; static int lp1, lp2; static double dx1, dx2, dx3, dy1, dy2, dy3, dz1, dz2, dz3; static int lpl; static double dsr; static int nst, listp[25], lptrp[25]; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 07/28/98 */ /* Given a point P on the surface of the unit sphere and a */ /* Delaunay triangulation created by Subroutine TRMESH, this */ /* function returns the index of the nearest triangulation */ /* node to P. */ /* The algorithm consists of implicitly adding P to the */ /* triangulation, finding the nearest neighbor to P, and */ /* implicitly deleting P from the triangulation. Thus, it */ /* is based on the fact that, if P is a node in a Delaunay */ /* triangulation, the nearest node to P is a neighbor of P. */ /* On input: */ /* P = Array of length 3 containing the Cartesian coor- */ /* dinates of the point P to be located relative to */ /* the triangulation. It is assumed without a test */ /* that P(1)**2 + P(2)**2 + P(3)**2 = 1. */ /* IST = Index of a node at which TRFIND begins the */ /* search. Search time depends on the proximity */ /* of this node to P. */ /* N = Number of nodes in the triangulation. N .GE. 3. */ /* X,Y,Z = Arrays of length N containing the Cartesian */ /* coordinates of the nodes. */ /* LIST,LPTR,LEND = Data structure defining the trian- */ /* gulation. Refer to TRMESH. */ /* Input parameters are not altered by this function. */ /* On output: */ /* NEARND = Nodal index of the nearest node to P, or 0 */ /* if N < 3 or the triangulation data struc- */ /* ture is invalid. */ /* AL = Arc length (angular distance in radians) be- */ /* tween P and NEARND unless NEARND = 0. */ /* Note that the number of candidates for NEARND */ /* (neighbors of P) is limited to LMAX defined in */ /* the PARAMETER statement below. */ /* Modules required by NEARND: JRAND, LSTPTR, TRFIND, STORE */ /* Intrinsic functions called by NEARND: ABS, ACOS */ /* *********************************************************** */ /* Local parameters: */ /* B1,B2,B3 = Unnormalized barycentric coordinates returned */ /* by TRFIND */ /* DS1 = (Negative cosine of the) distance from P to N1 */ /* DSR = (Negative cosine of the) distance from P to NR */ /* DX1,..DZ3 = Components of vectors used by the swap test */ /* I1,I2,I3 = Nodal indexes of a triangle containing P, or */ /* the rightmost (I1) and leftmost (I2) visible */ /* boundary nodes as viewed from P */ /* L = Length of LISTP/LPTRP and number of neighbors */ /* of P */ /* LMAX = Maximum value of L */ /* LISTP = Indexes of the neighbors of P */ /* LPTRP = Array of pointers in 1-1 correspondence with */ /* LISTP elements */ /* LP = LIST pointer to a neighbor of N1 and LISTP */ /* pointer */ /* LP1,LP2 = LISTP indexes (pointers) */ /* LPL = Pointer to the last neighbor of N1 */ /* N1 = Index of a node visible from P */ /* N2 = Index of an endpoint of an arc opposite P */ /* N3 = Index of the node opposite N1->N2 */ /* NN = Local copy of N */ /* NR = Index of a candidate for the nearest node to P */ /* NST = Index of the node at which TRFIND begins the */ /* search */ /* Store local parameters and test for N invalid. */ /* Parameter adjustments */ --p; --lend; --z__; --y; --x; --list; --lptr; /* Function Body */ nn = *n; if (nn < 3) { goto L6; } nst = *ist; if (nst < 1 || nst > nn) { nst = 1; } /* Find a triangle (I1,I2,I3) containing P, or the rightmost */ /* (I1) and leftmost (I2) visible boundary nodes as viewed */ /* from P. */ trfind_(&nst, &p[1], n, &x[1], &y[1], &z__[1], &list[1], &lptr[1], &lend[ 1], &b1, &b2, &b3, &i1, &i2, &i3); /* Test for collinear nodes. */ if (i1 == 0) { goto L6; } /* Store the linked list of 'neighbors' of P in LISTP and */ /* LPTRP. I1 is the first neighbor, and 0 is stored as */ /* the last neighbor if P is not contained in a triangle. */ /* L is the length of LISTP and LPTRP, and is limited to */ /* LMAX. */ if (i3 != 0) { listp[0] = i1; lptrp[0] = 2; listp[1] = i2; lptrp[1] = 3; listp[2] = i3; lptrp[2] = 1; l = 3; } else { n1 = i1; l = 1; lp1 = 2; listp[l - 1] = n1; lptrp[l - 1] = lp1; /* Loop on the ordered sequence of visible boundary nodes */ /* N1 from I1 to I2. */ L1: lpl = lend[n1]; n1 = -list[lpl]; l = lp1; lp1 = l + 1; listp[l - 1] = n1; lptrp[l - 1] = lp1; if (n1 != i2 && lp1 < 25) { goto L1; } l = lp1; listp[l - 1] = 0; lptrp[l - 1] = 1; } /* Initialize variables for a loop on arcs N1-N2 opposite P */ /* in which new 'neighbors' are 'swapped' in. N1 follows */ /* N2 as a neighbor of P, and LP1 and LP2 are the LISTP */ /* indexes of N1 and N2. */ lp2 = 1; n2 = i1; lp1 = lptrp[0]; n1 = listp[lp1 - 1]; /* Begin loop: find the node N3 opposite N1->N2. */ L2: lp = lstptr_(&lend[n1], &n2, &list[1], &lptr[1]); if (list[lp] < 0) { goto L3; } lp = lptr[lp]; n3 = (i__1 = list[lp], abs(i__1)); /* Swap test: Exit the loop if L = LMAX. */ if (l == 25) { goto L4; } dx1 = x[n1] - p[1]; dy1 = y[n1] - p[2]; dz1 = z__[n1] - p[3]; dx2 = x[n2] - p[1]; dy2 = y[n2] - p[2]; dz2 = z__[n2] - p[3]; dx3 = x[n3] - p[1]; dy3 = y[n3] - p[2]; dz3 = z__[n3] - p[3]; if (dx3 * (dy2 * dz1 - dy1 * dz2) - dy3 * (dx2 * dz1 - dx1 * dz2) + dz3 * (dx2 * dy1 - dx1 * dy2) <= 0.) { goto L3; } /* Swap: Insert N3 following N2 in the adjacency list for P. */ /* The two new arcs opposite P must be tested. */ ++l; lptrp[lp2 - 1] = l; listp[l - 1] = n3; lptrp[l - 1] = lp1; lp1 = l; n1 = n3; goto L2; /* No swap: Advance to the next arc and test for termination */ /* on N1 = I1 (LP1 = 1) or N1 followed by 0. */ L3: if (lp1 == 1) { goto L4; } lp2 = lp1; n2 = n1; lp1 = lptrp[lp1 - 1]; n1 = listp[lp1 - 1]; if (n1 == 0) { goto L4; } goto L2; /* Set NR and DSR to the index of the nearest node to P and */ /* an increasing function (negative cosine) of its distance */ /* from P, respectively. */ L4: nr = i1; dsr = -(x[nr] * p[1] + y[nr] * p[2] + z__[nr] * p[3]); i__1 = l; for (lp = 2; lp <= i__1; ++lp) { n1 = listp[lp - 1]; if (n1 == 0) { goto L5; } ds1 = -(x[n1] * p[1] + y[n1] * p[2] + z__[n1] * p[3]); if (ds1 < dsr) { nr = n1; dsr = ds1; } L5: ; } dsr = -dsr; if (dsr > 1.) { dsr = 1.; } *al = acos(dsr); ret_val = nr; return ret_val; /* Invalid input. */ L6: ret_val = 0; return ret_val; } /* nearnd_ */ /* Subroutine */ int optim_(double *x, double *y, double *z__, int *na, int *list, int *lptr, int *lend, int * nit, int *iwk, int *ier) { /* System generated locals */ int i__1, i__2; /* Local variables */ static int i__, n1, n2, lp, io1, io2, nna, lp21, lpl, lpp; static int swp; static int iter; static int maxit; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 07/30/98 */ /* Given a set of NA triangulation arcs, this subroutine */ /* optimizes the portion of the triangulation consisting of */ /* the quadrilaterals (pairs of adjacent triangles) which */ /* have the arcs as diagonals by applying the circumcircle */ /* test and appropriate swaps to the arcs. */ /* An iteration consists of applying the swap test and */ /* swaps to all NA arcs in the order in which they are */ /* stored. The iteration is repeated until no swap occurs */ /* or NIT iterations have been performed. The bound on the */ /* number of iterations may be necessary to prevent an */ /* infinite loop caused by cycling (reversing the effect of a */ /* previous swap) due to floating point inaccuracy when four */ /* or more nodes are nearly cocircular. */ /* On input: */ /* X,Y,Z = Arrays containing the nodal coordinates. */ /* NA = Number of arcs in the set. NA .GE. 0. */ /* The above parameters are not altered by this routine. */ /* LIST,LPTR,LEND = Data structure defining the trian- */ /* gulation. Refer to Subroutine */ /* TRMESH. */ /* NIT = Maximum number of iterations to be performed. */ /* NIT = 4*NA should be sufficient. NIT .GE. 1. */ /* IWK = int array dimensioned 2 by NA containing */ /* the nodal indexes of the arc endpoints (pairs */ /* of endpoints are stored in columns). */ /* On output: */ /* LIST,LPTR,LEND = Updated triangulation data struc- */ /* ture reflecting the swaps. */ /* NIT = Number of iterations performed. */ /* IWK = Endpoint indexes of the new set of arcs */ /* reflecting the swaps. */ /* IER = Error indicator: */ /* IER = 0 if no errors were encountered. */ /* IER = 1 if a swap occurred on the last of */ /* MAXIT iterations, where MAXIT is the */ /* value of NIT on input. The new set */ /* of arcs is not necessarily optimal */ /* in this case. */ /* IER = 2 if NA < 0 or NIT < 1 on input. */ /* IER = 3 if IWK(2,I) is not a neighbor of */ /* IWK(1,I) for some I in the range 1 */ /* to NA. A swap may have occurred in */ /* this case. */ /* IER = 4 if a zero pointer was returned by */ /* Subroutine SWAP. */ /* Modules required by OPTIM: LSTPTR, SWAP, SWPTST */ /* Intrinsic function called by OPTIM: ABS */ /* *********************************************************** */ /* Local parameters: */ /* I = Column index for IWK */ /* IO1,IO2 = Nodal indexes of the endpoints of an arc in IWK */ /* ITER = Iteration count */ /* LP = LIST pointer */ /* LP21 = Parameter returned by SWAP (not used) */ /* LPL = Pointer to the last neighbor of IO1 */ /* LPP = Pointer to the node preceding IO2 as a neighbor */ /* of IO1 */ /* MAXIT = Input value of NIT */ /* N1,N2 = Nodes opposite IO1->IO2 and IO2->IO1, */ /* respectively */ /* NNA = Local copy of NA */ /* SWP = Flag set to TRUE iff a swap occurs in the */ /* optimization loop */ /* Parameter adjustments */ --x; --y; --z__; iwk -= 3; --list; --lptr; --lend; /* Function Body */ nna = *na; maxit = *nit; if (nna < 0 || maxit < 1) { goto L7; } /* Initialize iteration count ITER and test for NA = 0. */ iter = 0; if (nna == 0) { goto L5; } /* Top of loop -- */ /* SWP = TRUE iff a swap occurred in the current iteration. */ L1: if (iter == maxit) { goto L6; } ++iter; swp = FALSE_; /* Inner loop on arcs IO1-IO2 -- */ i__1 = nna; for (i__ = 1; i__ <= i__1; ++i__) { io1 = iwk[(i__ << 1) + 1]; io2 = iwk[(i__ << 1) + 2]; /* Set N1 and N2 to the nodes opposite IO1->IO2 and */ /* IO2->IO1, respectively. Determine the following: */ /* LPL = pointer to the last neighbor of IO1, */ /* LP = pointer to IO2 as a neighbor of IO1, and */ /* LPP = pointer to the node N2 preceding IO2. */ lpl = lend[io1]; lpp = lpl; lp = lptr[lpp]; L2: if (list[lp] == io2) { goto L3; } lpp = lp; lp = lptr[lpp]; if (lp != lpl) { goto L2; } /* IO2 should be the last neighbor of IO1. Test for no */ /* arc and bypass the swap test if IO1 is a boundary */ /* node. */ if ((i__2 = list[lp], abs(i__2)) != io2) { goto L8; } if (list[lp] < 0) { goto L4; } /* Store N1 and N2, or bypass the swap test if IO1 is a */ /* boundary node and IO2 is its first neighbor. */ L3: n2 = list[lpp]; if (n2 < 0) { goto L4; } lp = lptr[lp]; n1 = (i__2 = list[lp], abs(i__2)); /* Test IO1-IO2 for a swap, and update IWK if necessary. */ if (! swptst_(&n1, &n2, &io1, &io2, &x[1], &y[1], &z__[1])) { goto L4; } swap_(&n1, &n2, &io1, &io2, &list[1], &lptr[1], &lend[1], &lp21); if (lp21 == 0) { goto L9; } swp = TRUE_; iwk[(i__ << 1) + 1] = n1; iwk[(i__ << 1) + 2] = n2; L4: ; } if (swp) { goto L1; } /* Successful termination. */ L5: *nit = iter; *ier = 0; return 0; /* MAXIT iterations performed without convergence. */ L6: *nit = maxit; *ier = 1; return 0; /* Invalid input parameter. */ L7: *nit = 0; *ier = 2; return 0; /* IO2 is not a neighbor of IO1. */ L8: *nit = iter; *ier = 3; return 0; /* Zero pointer returned by SWAP. */ L9: *nit = iter; *ier = 4; return 0; } /* optim_ */ /* Subroutine */ int scoord_(double *px, double *py, double *pz, double *plat, double *plon, double *pnrm) { /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 08/27/90 */ /* This subroutine converts a point P from Cartesian coor- */ /* dinates to spherical coordinates. */ /* On input: */ /* PX,PY,PZ = Cartesian coordinates of P. */ /* Input parameters are not altered by this routine. */ /* On output: */ /* PLAT = Latitude of P in the range -PI/2 to PI/2, or */ /* 0 if PNRM = 0. PLAT should be scaled by */ /* 180/PI to obtain the value in degrees. */ /* PLON = Longitude of P in the range -PI to PI, or 0 */ /* if P lies on the Z-axis. PLON should be */ /* scaled by 180/PI to obtain the value in */ /* degrees. */ /* PNRM = Magnitude (Euclidean norm) of P. */ /* Modules required by SCOORD: None */ /* Intrinsic functions called by SCOORD: ASIN, ATAN2, SQRT */ /* *********************************************************** */ *pnrm = sqrt(*px * *px + *py * *py + *pz * *pz); if (*px != 0. || *py != 0.) { *plon = atan2(*py, *px); } else { *plon = 0.; } if (*pnrm != 0.) { *plat = asin(*pz / *pnrm); } else { *plat = 0.; } return 0; } /* scoord_ */ double store_(double *x) { /* System generated locals */ double ret_val; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 05/09/92 */ /* This function forces its argument X to be stored in a */ /* memory location, thus providing a means of determining */ /* floating point number characteristics (such as the machine */ /* precision) when it is necessary to avoid computation in */ /* high precision registers. */ /* On input: */ /* X = Value to be stored. */ /* X is not altered by this function. */ /* On output: */ /* STORE = Value of X after it has been stored and */ /* possibly truncated or rounded to the single */ /* precision word length. */ /* Modules required by STORE: None */ /* *********************************************************** */ stcom.y = *x; ret_val = stcom.y; return ret_val; } /* store_ */ /* Subroutine */ int swap_(int *in1, int *in2, int *io1, int * io2, int *list, int *lptr, int *lend, int *lp21) { /* System generated locals */ int i__1; /* Local variables */ static int lp, lph, lpsav; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 06/22/98 */ /* Given a triangulation of a set of points on the unit */ /* sphere, this subroutine replaces a diagonal arc in a */ /* strictly convex quadrilateral (defined by a pair of adja- */ /* cent triangles) with the other diagonal. Equivalently, a */ /* pair of adjacent triangles is replaced by another pair */ /* having the same union. */ /* On input: */ /* IN1,IN2,IO1,IO2 = Nodal indexes of the vertices of */ /* the quadrilateral. IO1-IO2 is re- */ /* placed by IN1-IN2. (IO1,IO2,IN1) */ /* and (IO2,IO1,IN2) must be trian- */ /* gles on input. */ /* The above parameters are not altered by this routine. */ /* LIST,LPTR,LEND = Data structure defining the trian- */ /* gulation. Refer to Subroutine */ /* TRMESH. */ /* On output: */ /* LIST,LPTR,LEND = Data structure updated with the */ /* swap -- triangles (IO1,IO2,IN1) and */ /* (IO2,IO1,IN2) are replaced by */ /* (IN1,IN2,IO2) and (IN2,IN1,IO1) */ /* unless LP21 = 0. */ /* LP21 = Index of IN1 as a neighbor of IN2 after the */ /* swap is performed unless IN1 and IN2 are */ /* adjacent on input, in which case LP21 = 0. */ /* Module required by SWAP: LSTPTR */ /* Intrinsic function called by SWAP: ABS */ /* *********************************************************** */ /* Local parameters: */ /* LP,LPH,LPSAV = LIST pointers */ /* Test for IN1 and IN2 adjacent. */ /* Parameter adjustments */ --lend; --lptr; --list; /* Function Body */ lp = lstptr_(&lend[*in1], in2, &list[1], &lptr[1]); if ((i__1 = list[lp], abs(i__1)) == *in2) { *lp21 = 0; return 0; } /* Delete IO2 as a neighbor of IO1. */ lp = lstptr_(&lend[*io1], in2, &list[1], &lptr[1]); lph = lptr[lp]; lptr[lp] = lptr[lph]; /* If IO2 is the last neighbor of IO1, make IN2 the */ /* last neighbor. */ if (lend[*io1] == lph) { lend[*io1] = lp; } /* Insert IN2 as a neighbor of IN1 following IO1 */ /* using the hole created above. */ lp = lstptr_(&lend[*in1], io1, &list[1], &lptr[1]); lpsav = lptr[lp]; lptr[lp] = lph; list[lph] = *in2; lptr[lph] = lpsav; /* Delete IO1 as a neighbor of IO2. */ lp = lstptr_(&lend[*io2], in1, &list[1], &lptr[1]); lph = lptr[lp]; lptr[lp] = lptr[lph]; /* If IO1 is the last neighbor of IO2, make IN1 the */ /* last neighbor. */ if (lend[*io2] == lph) { lend[*io2] = lp; } /* Insert IN1 as a neighbor of IN2 following IO2. */ lp = lstptr_(&lend[*in2], io2, &list[1], &lptr[1]); lpsav = lptr[lp]; lptr[lp] = lph; list[lph] = *in1; lptr[lph] = lpsav; *lp21 = lph; return 0; } /* swap_ */ int swptst_(int *n1, int *n2, int *n3, int *n4, double *x, double *y, double *z__) { /* System generated locals */ int ret_val; /* Local variables */ static double x4, y4, z4, dx1, dx2, dx3, dy1, dy2, dy3, dz1, dz2, dz3; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 03/29/91 */ /* This function decides whether or not to replace a */ /* diagonal arc in a quadrilateral with the other diagonal. */ /* The decision will be to swap (SWPTST = TRUE) if and only */ /* if N4 lies above the plane (in the half-space not contain- */ /* ing the origin) defined by (N1,N2,N3), or equivalently, if */ /* the projection of N4 onto this plane is interior to the */ /* circumcircle of (N1,N2,N3). The decision will be for no */ /* swap if the quadrilateral is not strictly convex. */ /* On input: */ /* N1,N2,N3,N4 = Indexes of the four nodes defining the */ /* quadrilateral with N1 adjacent to N2, */ /* and (N1,N2,N3) in counterclockwise */ /* order. The arc connecting N1 to N2 */ /* should be replaced by an arc connec- */ /* ting N3 to N4 if SWPTST = TRUE. Refer */ /* to Subroutine SWAP. */ /* X,Y,Z = Arrays of length N containing the Cartesian */ /* coordinates of the nodes. (X(I),Y(I),Z(I)) */ /* define node I for I = N1, N2, N3, and N4. */ /* Input parameters are not altered by this routine. */ /* On output: */ /* SWPTST = TRUE if and only if the arc connecting N1 */ /* and N2 should be swapped for an arc con- */ /* necting N3 and N4. */ /* Modules required by SWPTST: None */ /* *********************************************************** */ /* Local parameters: */ /* DX1,DY1,DZ1 = Coordinates of N4->N1 */ /* DX2,DY2,DZ2 = Coordinates of N4->N2 */ /* DX3,DY3,DZ3 = Coordinates of N4->N3 */ /* X4,Y4,Z4 = Coordinates of N4 */ /* Parameter adjustments */ --z__; --y; --x; /* Function Body */ x4 = x[*n4]; y4 = y[*n4]; z4 = z__[*n4]; dx1 = x[*n1] - x4; dx2 = x[*n2] - x4; dx3 = x[*n3] - x4; dy1 = y[*n1] - y4; dy2 = y[*n2] - y4; dy3 = y[*n3] - y4; dz1 = z__[*n1] - z4; dz2 = z__[*n2] - z4; dz3 = z__[*n3] - z4; /* N4 lies above the plane of (N1,N2,N3) iff N3 lies above */ /* the plane of (N2,N1,N4) iff Det(N3-N4,N2-N4,N1-N4) = */ /* (N3-N4,N2-N4 X N1-N4) > 0. */ ret_val = dx3 * (dy2 * dz1 - dy1 * dz2) - dy3 * (dx2 * dz1 - dx1 * dz2) + dz3 * (dx2 * dy1 - dx1 * dy2) > 0.; return ret_val; } /* swptst_ */ /* Subroutine */ int trans_(int *n, double *rlat, double *rlon, double *x, double *y, double *z__) { /* System generated locals */ int i__1; /* Local variables */ static int i__, nn; static double phi, theta, cosphi; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 04/08/90 */ /* This subroutine transforms spherical coordinates into */ /* Cartesian coordinates on the unit sphere for input to */ /* Subroutine TRMESH. Storage for X and Y may coincide with */ /* storage for RLAT and RLON if the latter need not be saved. */ /* On input: */ /* N = Number of nodes (points on the unit sphere) */ /* whose coordinates are to be transformed. */ /* RLAT = Array of length N containing latitudinal */ /* coordinates of the nodes in radians. */ /* RLON = Array of length N containing longitudinal */ /* coordinates of the nodes in radians. */ /* The above parameters are not altered by this routine. */ /* X,Y,Z = Arrays of length at least N. */ /* On output: */ /* X,Y,Z = Cartesian coordinates in the range -1 to 1. */ /* X(I)**2 + Y(I)**2 + Z(I)**2 = 1 for I = 1 */ /* to N. */ /* Modules required by TRANS: None */ /* Intrinsic functions called by TRANS: COS, SIN */ /* *********************************************************** */ /* Local parameters: */ /* COSPHI = cos(PHI) */ /* I = DO-loop index */ /* NN = Local copy of N */ /* PHI = Latitude */ /* THETA = Longitude */ /* Parameter adjustments */ --z__; --y; --x; --rlon; --rlat; /* Function Body */ nn = *n; i__1 = nn; for (i__ = 1; i__ <= i__1; ++i__) { phi = rlat[i__]; theta = rlon[i__]; cosphi = cos(phi); x[i__] = cosphi * cos(theta); y[i__] = cosphi * sin(theta); z__[i__] = sin(phi); /* L1: */ } return 0; } /* trans_ */ /* Subroutine */ int trfind_(int *nst, double *p, int *n, double *x, double *y, double *z__, int *list, int *lptr, int *lend, double *b1, double *b2, double *b3, int *i1, int *i2, int *i3) { /* Initialized data */ static int ix = 1; static int iy = 2; static int iz = 3; /* System generated locals */ int i__1; double d__1, d__2; /* Local variables */ static double q[3]; static int n0, n1, n2, n3, n4, nf; static double s12; static int nl, lp; static double xp, yp, zp; static int n1s, n2s; static double eps, tol, ptn1, ptn2; static int next; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 11/30/99 */ /* This subroutine locates a point P relative to a triangu- */ /* lation created by Subroutine TRMESH. If P is contained in */ /* a triangle, the three vertex indexes and barycentric coor- */ /* dinates are returned. Otherwise, the indexes of the */ /* visible boundary nodes are returned. */ /* On input: */ /* NST = Index of a node at which TRFIND begins its */ /* search. Search time depends on the proximity */ /* of this node to P. */ /* P = Array of length 3 containing the x, y, and z */ /* coordinates (in that order) of the point P to be */ /* located. */ /* N = Number of nodes in the triangulation. N .GE. 3. */ /* X,Y,Z = Arrays of length N containing the Cartesian */ /* coordinates of the triangulation nodes (unit */ /* vectors). (X(I),Y(I),Z(I)) defines node I */ /* for I = 1 to N. */ /* LIST,LPTR,LEND = Data structure defining the trian- */ /* gulation. Refer to Subroutine */ /* TRMESH. */ /* Input parameters are not altered by this routine. */ /* On output: */ /* B1,B2,B3 = Unnormalized barycentric coordinates of */ /* the central projection of P onto the un- */ /* derlying planar triangle if P is in the */ /* convex hull of the nodes. These parame- */ /* ters are not altered if I1 = 0. */ /* I1,I2,I3 = Counterclockwise-ordered vertex indexes */ /* of a triangle containing P if P is con- */ /* tained in a triangle. If P is not in the */ /* convex hull of the nodes, I1 and I2 are */ /* the rightmost and leftmost (boundary) */ /* nodes that are visible from P, and */ /* I3 = 0. (If all boundary nodes are vis- */ /* ible from P, then I1 and I2 coincide.) */ /* I1 = I2 = I3 = 0 if P and all of the */ /* nodes are coplanar (lie on a common great */ /* circle. */ /* Modules required by TRFIND: JRAND, LSTPTR, STORE */ /* Intrinsic function called by TRFIND: ABS */ /* *********************************************************** */ /* Parameter adjustments */ --p; --lend; --z__; --y; --x; --list; --lptr; /* Function Body */ /* Local parameters: */ /* EPS = Machine precision */ /* IX,IY,IZ = int seeds for JRAND */ /* LP = LIST pointer */ /* N0,N1,N2 = Nodes in counterclockwise order defining a */ /* cone (with vertex N0) containing P, or end- */ /* points of a boundary edge such that P Right */ /* N1->N2 */ /* N1S,N2S = Initially-determined values of N1 and N2 */ /* N3,N4 = Nodes opposite N1->N2 and N2->N1, respectively */ /* NEXT = Candidate for I1 or I2 when P is exterior */ /* NF,NL = First and last neighbors of N0, or first */ /* (rightmost) and last (leftmost) nodes */ /* visible from P when P is exterior to the */ /* triangulation */ /* PTN1 = Scalar product */ /* PTN2 = Scalar product */ /* Q = (N2 X N1) X N2 or N1 X (N2 X N1) -- used in */ /* the boundary traversal when P is exterior */ /* S12 = Scalar product */ /* TOL = Tolerance (multiple of EPS) defining an upper */ /* bound on the magnitude of a negative bary- */ /* centric coordinate (B1 or B2) for P in a */ /* triangle -- used to avoid an infinite number */ /* of restarts with 0 <= B3 < EPS and B1 < 0 or */ /* B2 < 0 but small in magnitude */ /* XP,YP,ZP = Local variables containing P(1), P(2), and P(3) */ /* X0,Y0,Z0 = Dummy arguments for DET */ /* X1,Y1,Z1 = Dummy arguments for DET */ /* X2,Y2,Z2 = Dummy arguments for DET */ /* Statement function: */ /* DET(X1,...,Z0) .GE. 0 if and only if (X0,Y0,Z0) is in the */ /* (closed) left hemisphere defined by */ /* the plane containing (0,0,0), */ /* (X1,Y1,Z1), and (X2,Y2,Z2), where */ /* left is defined relative to an ob- */ /* server at (X1,Y1,Z1) facing */ /* (X2,Y2,Z2). */ /* Initialize variables. */ xp = p[1]; yp = p[2]; zp = p[3]; n0 = *nst; if (n0 < 1 || n0 > *n) { n0 = jrand_(n, &ix, &iy, &iz); } /* Compute the relative machine precision EPS and TOL. */ eps = 1.; L1: eps /= 2.; d__1 = eps + 1.; if (store_(&d__1) > 1.) { goto L1; } eps *= 2.; tol = eps * 100.; /* Set NF and NL to the first and last neighbors of N0, and */ /* initialize N1 = NF. */ L2: lp = lend[n0]; nl = list[lp]; lp = lptr[lp]; nf = list[lp]; n1 = nf; /* Find a pair of adjacent neighbors N1,N2 of N0 that define */ /* a wedge containing P: P LEFT N0->N1 and P RIGHT N0->N2. */ if (nl > 0) { /* N0 is an interior node. Find N1. */ L3: if (xp * (y[n0] * z__[n1] - y[n1] * z__[n0]) - yp * (x[n0] * z__[n1] - x[n1] * z__[n0]) + zp * (x[n0] * y[n1] - x[n1] * y[n0]) < 0.) { lp = lptr[lp]; n1 = list[lp]; if (n1 == nl) { goto L6; } goto L3; } } else { /* N0 is a boundary node. Test for P exterior. */ nl = -nl; if (xp * (y[n0] * z__[nf] - y[nf] * z__[n0]) - yp * (x[n0] * z__[nf] - x[nf] * z__[n0]) + zp * (x[n0] * y[nf] - x[nf] * y[n0]) < 0.) { /* P is to the right of the boundary edge N0->NF. */ n1 = n0; n2 = nf; goto L9; } if (xp * (y[nl] * z__[n0] - y[n0] * z__[nl]) - yp * (x[nl] * z__[n0] - x[n0] * z__[nl]) + zp * (x[nl] * y[n0] - x[n0] * y[nl]) < 0.) { /* P is to the right of the boundary edge NL->N0. */ n1 = nl; n2 = n0; goto L9; } } /* P is to the left of arcs N0->N1 and NL->N0. Set N2 to the */ /* next neighbor of N0 (following N1). */ L4: lp = lptr[lp]; n2 = (i__1 = list[lp], abs(i__1)); if (xp * (y[n0] * z__[n2] - y[n2] * z__[n0]) - yp * (x[n0] * z__[n2] - x[ n2] * z__[n0]) + zp * (x[n0] * y[n2] - x[n2] * y[n0]) < 0.) { goto L7; } n1 = n2; if (n1 != nl) { goto L4; } if (xp * (y[n0] * z__[nf] - y[nf] * z__[n0]) - yp * (x[n0] * z__[nf] - x[ nf] * z__[n0]) + zp * (x[n0] * y[nf] - x[nf] * y[n0]) < 0.) { goto L6; } /* P is left of or on arcs N0->NB for all neighbors NB */ /* of N0. Test for P = +/-N0. */ d__2 = (d__1 = x[n0] * xp + y[n0] * yp + z__[n0] * zp, abs(d__1)); if (store_(&d__2) < 1. - eps * 4.) { /* All points are collinear iff P Left NB->N0 for all */ /* neighbors NB of N0. Search the neighbors of N0. */ /* Note: N1 = NL and LP points to NL. */ L5: if (xp * (y[n1] * z__[n0] - y[n0] * z__[n1]) - yp * (x[n1] * z__[n0] - x[n0] * z__[n1]) + zp * (x[n1] * y[n0] - x[n0] * y[n1]) >= 0.) { lp = lptr[lp]; n1 = (i__1 = list[lp], abs(i__1)); if (n1 == nl) { goto L14; } goto L5; } } /* P is to the right of N1->N0, or P = +/-N0. Set N0 to N1 */ /* and start over. */ n0 = n1; goto L2; /* P is between arcs N0->N1 and N0->NF. */ L6: n2 = nf; /* P is contained in a wedge defined by geodesics N0-N1 and */ /* N0-N2, where N1 is adjacent to N2. Save N1 and N2 to */ /* test for cycling. */ L7: n3 = n0; n1s = n1; n2s = n2; /* Top of edge-hopping loop: */ L8: *b3 = xp * (y[n1] * z__[n2] - y[n2] * z__[n1]) - yp * (x[n1] * z__[n2] - x[n2] * z__[n1]) + zp * (x[n1] * y[n2] - x[n2] * y[n1]); if (*b3 < 0.) { /* Set N4 to the first neighbor of N2 following N1 (the */ /* node opposite N2->N1) unless N1->N2 is a boundary arc. */ lp = lstptr_(&lend[n2], &n1, &list[1], &lptr[1]); if (list[lp] < 0) { goto L9; } lp = lptr[lp]; n4 = (i__1 = list[lp], abs(i__1)); /* Define a new arc N1->N2 which intersects the geodesic */ /* N0-P. */ if (xp * (y[n0] * z__[n4] - y[n4] * z__[n0]) - yp * (x[n0] * z__[n4] - x[n4] * z__[n0]) + zp * (x[n0] * y[n4] - x[n4] * y[n0]) < 0.) { n3 = n2; n2 = n4; n1s = n1; if (n2 != n2s && n2 != n0) { goto L8; } } else { n3 = n1; n1 = n4; n2s = n2; if (n1 != n1s && n1 != n0) { goto L8; } } /* The starting node N0 or edge N1-N2 was encountered */ /* again, implying a cycle (infinite loop). Restart */ /* with N0 randomly selected. */ n0 = jrand_(n, &ix, &iy, &iz); goto L2; } /* P is in (N1,N2,N3) unless N0, N1, N2, and P are collinear */ /* or P is close to -N0. */ if (*b3 >= eps) { /* B3 .NE. 0. */ *b1 = xp * (y[n2] * z__[n3] - y[n3] * z__[n2]) - yp * (x[n2] * z__[n3] - x[n3] * z__[n2]) + zp * (x[n2] * y[n3] - x[n3] * y[n2]); *b2 = xp * (y[n3] * z__[n1] - y[n1] * z__[n3]) - yp * (x[n3] * z__[n1] - x[n1] * z__[n3]) + zp * (x[n3] * y[n1] - x[n1] * y[n3]); if (*b1 < -tol || *b2 < -tol) { /* Restart with N0 randomly selected. */ n0 = jrand_(n, &ix, &iy, &iz); goto L2; } } else { /* B3 = 0 and thus P lies on N1->N2. Compute */ /* B1 = Det(P,N2 X N1,N2) and B2 = Det(P,N1,N2 X N1). */ *b3 = 0.; s12 = x[n1] * x[n2] + y[n1] * y[n2] + z__[n1] * z__[n2]; ptn1 = xp * x[n1] + yp * y[n1] + zp * z__[n1]; ptn2 = xp * x[n2] + yp * y[n2] + zp * z__[n2]; *b1 = ptn1 - s12 * ptn2; *b2 = ptn2 - s12 * ptn1; if (*b1 < -tol || *b2 < -tol) { /* Restart with N0 randomly selected. */ n0 = jrand_(n, &ix, &iy, &iz); goto L2; } } /* P is in (N1,N2,N3). */ *i1 = n1; *i2 = n2; *i3 = n3; if (*b1 < 0.) { *b1 = 0.; } if (*b2 < 0.) { *b2 = 0.; } return 0; /* P Right N1->N2, where N1->N2 is a boundary edge. */ /* Save N1 and N2, and set NL = 0 to indicate that */ /* NL has not yet been found. */ L9: n1s = n1; n2s = n2; nl = 0; /* Counterclockwise Boundary Traversal: */ L10: lp = lend[n2]; lp = lptr[lp]; next = list[lp]; if (xp * (y[n2] * z__[next] - y[next] * z__[n2]) - yp * (x[n2] * z__[next] - x[next] * z__[n2]) + zp * (x[n2] * y[next] - x[next] * y[n2]) >= 0.) { /* N2 is the rightmost visible node if P Forward N2->N1 */ /* or NEXT Forward N2->N1. Set Q to (N2 X N1) X N2. */ s12 = x[n1] * x[n2] + y[n1] * y[n2] + z__[n1] * z__[n2]; q[0] = x[n1] - s12 * x[n2]; q[1] = y[n1] - s12 * y[n2]; q[2] = z__[n1] - s12 * z__[n2]; if (xp * q[0] + yp * q[1] + zp * q[2] >= 0.) { goto L11; } if (x[next] * q[0] + y[next] * q[1] + z__[next] * q[2] >= 0.) { goto L11; } /* N1, N2, NEXT, and P are nearly collinear, and N2 is */ /* the leftmost visible node. */ nl = n2; } /* Bottom of counterclockwise loop: */ n1 = n2; n2 = next; if (n2 != n1s) { goto L10; } /* All boundary nodes are visible from P. */ *i1 = n1s; *i2 = n1s; *i3 = 0; return 0; /* N2 is the rightmost visible node. */ L11: nf = n2; if (nl == 0) { /* Restore initial values of N1 and N2, and begin the search */ /* for the leftmost visible node. */ n2 = n2s; n1 = n1s; /* Clockwise Boundary Traversal: */ L12: lp = lend[n1]; next = -list[lp]; if (xp * (y[next] * z__[n1] - y[n1] * z__[next]) - yp * (x[next] * z__[n1] - x[n1] * z__[next]) + zp * (x[next] * y[n1] - x[n1] * y[next]) >= 0.) { /* N1 is the leftmost visible node if P or NEXT is */ /* forward of N1->N2. Compute Q = N1 X (N2 X N1). */ s12 = x[n1] * x[n2] + y[n1] * y[n2] + z__[n1] * z__[n2]; q[0] = x[n2] - s12 * x[n1]; q[1] = y[n2] - s12 * y[n1]; q[2] = z__[n2] - s12 * z__[n1]; if (xp * q[0] + yp * q[1] + zp * q[2] >= 0.) { goto L13; } if (x[next] * q[0] + y[next] * q[1] + z__[next] * q[2] >= 0.) { goto L13; } /* P, NEXT, N1, and N2 are nearly collinear and N1 is the */ /* rightmost visible node. */ nf = n1; } /* Bottom of clockwise loop: */ n2 = n1; n1 = next; if (n1 != n1s) { goto L12; } /* All boundary nodes are visible from P. */ *i1 = n1; *i2 = n1; *i3 = 0; return 0; /* N1 is the leftmost visible node. */ L13: nl = n1; } /* NF and NL have been found. */ *i1 = nf; *i2 = nl; *i3 = 0; return 0; /* All points are collinear (coplanar). */ L14: *i1 = 0; *i2 = 0; *i3 = 0; return 0; } /* trfind_ */ /* Subroutine */ int trlist_(int *n, int *list, int *lptr, int *lend, int *nrow, int *nt, int *ltri, int * ier) { /* System generated locals */ int ltri_dim1, ltri_offset, i__1, i__2; /* Local variables */ static int i__, j, i1, i2, i3, n1, n2, n3, ka, kn, lp, kt, nm2, lp2, lpl, isv; static int arcs; static int lpln1; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 07/20/96 */ /* This subroutine converts a triangulation data structure */ /* from the linked list created by Subroutine TRMESH to a */ /* triangle list. */ /* On input: */ /* N = Number of nodes in the triangulation. N .GE. 3. */ /* LIST,LPTR,LEND = Linked list data structure defin- */ /* ing the triangulation. Refer to */ /* Subroutine TRMESH. */ /* NROW = Number of rows (entries per triangle) re- */ /* served for the triangle list LTRI. The value */ /* must be 6 if only the vertex indexes and */ /* neighboring triangle indexes are to be */ /* stored, or 9 if arc indexes are also to be */ /* assigned and stored. Refer to LTRI. */ /* The above parameters are not altered by this routine. */ /* LTRI = int array of length at least NROW*NT, */ /* where NT is at most 2N-4. (A sufficient */ /* length is 12N if NROW=6 or 18N if NROW=9.) */ /* On output: */ /* NT = Number of triangles in the triangulation unless */ /* IER .NE. 0, in which case NT = 0. NT = 2N-NB-2 */ /* if NB .GE. 3 or 2N-4 if NB = 0, where NB is the */ /* number of boundary nodes. */ /* LTRI = NROW by NT array whose J-th column contains */ /* the vertex nodal indexes (first three rows), */ /* neighboring triangle indexes (second three */ /* rows), and, if NROW = 9, arc indexes (last */ /* three rows) associated with triangle J for */ /* J = 1,...,NT. The vertices are ordered */ /* counterclockwise with the first vertex taken */ /* to be the one with smallest index. Thus, */ /* LTRI(2,J) and LTRI(3,J) are larger than */ /* LTRI(1,J) and index adjacent neighbors of */ /* node LTRI(1,J). For I = 1,2,3, LTRI(I+3,J) */ /* and LTRI(I+6,J) index the triangle and arc, */ /* respectively, which are opposite (not shared */ /* by) node LTRI(I,J), with LTRI(I+3,J) = 0 if */ /* LTRI(I+6,J) indexes a boundary arc. Vertex */ /* indexes range from 1 to N, triangle indexes */ /* from 0 to NT, and, if included, arc indexes */ /* from 1 to NA, where NA = 3N-NB-3 if NB .GE. 3 */ /* or 3N-6 if NB = 0. The triangles are or- */ /* dered on first (smallest) vertex indexes. */ /* IER = Error indicator. */ /* IER = 0 if no errors were encountered. */ /* IER = 1 if N or NROW is outside its valid */ /* range on input. */ /* IER = 2 if the triangulation data structure */ /* (LIST,LPTR,LEND) is invalid. Note, */ /* however, that these arrays are not */ /* completely tested for validity. */ /* Modules required by TRLIST: None */ /* Intrinsic function called by TRLIST: ABS */ /* *********************************************************** */ /* Local parameters: */ /* ARCS = int variable with value TRUE iff are */ /* indexes are to be stored */ /* I,J = LTRI row indexes (1 to 3) associated with */ /* triangles KT and KN, respectively */ /* I1,I2,I3 = Nodal indexes of triangle KN */ /* ISV = Variable used to permute indexes I1,I2,I3 */ /* KA = Arc index and number of currently stored arcs */ /* KN = Index of the triangle that shares arc I1-I2 */ /* with KT */ /* KT = Triangle index and number of currently stored */ /* triangles */ /* LP = LIST pointer */ /* LP2 = Pointer to N2 as a neighbor of N1 */ /* LPL = Pointer to the last neighbor of I1 */ /* LPLN1 = Pointer to the last neighbor of N1 */ /* N1,N2,N3 = Nodal indexes of triangle KT */ /* NM2 = N-2 */ /* Test for invalid input parameters. */ /* Parameter adjustments */ --lend; --list; --lptr; ltri_dim1 = *nrow; ltri_offset = 1 + ltri_dim1; ltri -= ltri_offset; /* Function Body */ if (*n < 3 || (*nrow != 6 && *nrow != 9)) { goto L11; } /* Initialize parameters for loop on triangles KT = (N1,N2, */ /* N3), where N1 < N2 and N1 < N3. */ /* ARCS = TRUE iff arc indexes are to be stored. */ /* KA,KT = Numbers of currently stored arcs and triangles. */ /* NM2 = Upper bound on candidates for N1. */ arcs = *nrow == 9; ka = 0; kt = 0; nm2 = *n - 2; /* Loop on nodes N1. */ i__1 = nm2; for (n1 = 1; n1 <= i__1; ++n1) { /* Loop on pairs of adjacent neighbors (N2,N3). LPLN1 points */ /* to the last neighbor of N1, and LP2 points to N2. */ lpln1 = lend[n1]; lp2 = lpln1; L1: lp2 = lptr[lp2]; n2 = list[lp2]; lp = lptr[lp2]; n3 = (i__2 = list[lp], abs(i__2)); if (n2 < n1 || n3 < n1) { goto L8; } /* Add a new triangle KT = (N1,N2,N3). */ ++kt; ltri[kt * ltri_dim1 + 1] = n1; ltri[kt * ltri_dim1 + 2] = n2; ltri[kt * ltri_dim1 + 3] = n3; /* Loop on triangle sides (I2,I1) with neighboring triangles */ /* KN = (I1,I2,I3). */ for (i__ = 1; i__ <= 3; ++i__) { if (i__ == 1) { i1 = n3; i2 = n2; } else if (i__ == 2) { i1 = n1; i2 = n3; } else { i1 = n2; i2 = n1; } /* Set I3 to the neighbor of I1 that follows I2 unless */ /* I2->I1 is a boundary arc. */ lpl = lend[i1]; lp = lptr[lpl]; L2: if (list[lp] == i2) { goto L3; } lp = lptr[lp]; if (lp != lpl) { goto L2; } /* I2 is the last neighbor of I1 unless the data structure */ /* is invalid. Bypass the search for a neighboring */ /* triangle if I2->I1 is a boundary arc. */ if ((i__2 = list[lp], abs(i__2)) != i2) { goto L12; } kn = 0; if (list[lp] < 0) { goto L6; } /* I2->I1 is not a boundary arc, and LP points to I2 as */ /* a neighbor of I1. */ L3: lp = lptr[lp]; i3 = (i__2 = list[lp], abs(i__2)); /* Find J such that LTRI(J,KN) = I3 (not used if KN > KT), */ /* and permute the vertex indexes of KN so that I1 is */ /* smallest. */ if (i1 < i2 && i1 < i3) { j = 3; } else if (i2 < i3) { j = 2; isv = i1; i1 = i2; i2 = i3; i3 = isv; } else { j = 1; isv = i1; i1 = i3; i3 = i2; i2 = isv; } /* Test for KN > KT (triangle index not yet assigned). */ if (i1 > n1) { goto L7; } /* Find KN, if it exists, by searching the triangle list in */ /* reverse order. */ for (kn = kt - 1; kn >= 1; --kn) { if (ltri[kn * ltri_dim1 + 1] == i1 && ltri[kn * ltri_dim1 + 2] == i2 && ltri[kn * ltri_dim1 + 3] == i3) { goto L5; } /* L4: */ } goto L7; /* Store KT as a neighbor of KN. */ L5: ltri[j + 3 + kn * ltri_dim1] = kt; /* Store KN as a neighbor of KT, and add a new arc KA. */ L6: ltri[i__ + 3 + kt * ltri_dim1] = kn; if (arcs) { ++ka; ltri[i__ + 6 + kt * ltri_dim1] = ka; if (kn != 0) { ltri[j + 6 + kn * ltri_dim1] = ka; } } L7: ; } /* Bottom of loop on triangles. */ L8: if (lp2 != lpln1) { goto L1; } /* L9: */ } /* No errors encountered. */ *nt = kt; *ier = 0; return 0; /* Invalid input parameter. */ L11: *nt = 0; *ier = 1; return 0; /* Invalid triangulation data structure: I1 is a neighbor of */ /* I2, but I2 is not a neighbor of I1. */ L12: *nt = 0; *ier = 2; return 0; } /* trlist_ */ /* Subroutine */ int trmesh_(int *n, double *x, double *y, double *z__, int *list, int *lptr, int *lend, int *lnew, int *near__, int *next, double *dist, int *ier) { /* System generated locals */ int i__1, i__2; /* Local variables */ static double d__; static int i__, j, k; static double d1, d2, d3; static int i0, lp, nn, lpl; static int nexti; /* *********************************************************** */ /* From STRIPACK */ /* Robert J. Renka */ /* Dept. of Computer Science */ /* Univ. of North Texas */ /* renka@cs.unt.edu */ /* 07/08/99 */ /* This subroutine creates a Delaunay triangulation of a */ /* set of N arbitrarily distributed points, referred to as */ /* nodes, on the surface of the unit sphere. The Delaunay */ /* triangulation is defined as a set of (spherical) triangles */ /* with the following five properties: */ /* 1) The triangle vertices are nodes. */ /* 2) No triangle contains a node other than its vertices. */ /* 3) The interiors of the triangles are pairwise disjoint. */ /* 4) The union of triangles is the convex hull of the set */ /* of nodes (the smallest convex set that contains */ /* the nodes). If the nodes are not contained in a */ /* single hemisphere, their convex hull is the en- */ /* tire sphere and there are no boundary nodes. */ /* Otherwise, there are at least three boundary nodes. */ /* 5) The interior of the circumcircle of each triangle */ /* contains no node. */ /* The first four properties define a triangulation, and the */ /* last property results in a triangulation which is as close */ /* as possible to equiangular in a certain sense and which is */ /* uniquely defined unless four or more nodes lie in a common */ /* plane. This property makes the triangulation well-suited */ /* for solving closest-point problems and for triangle-based */ /* interpolation. */ /* Provided the nodes are randomly ordered, the algorithm */ /* has expected time complexity O(N*log(N)) for most nodal */ /* distributions. Note, however, that the complexity may be */ /* as high as O(N**2) if, for example, the nodes are ordered */ /* on increasing latitude. */ /* Spherical coordinates (latitude and longitude) may be */ /* converted to Cartesian coordinates by Subroutine TRANS. */ /* The following is a list of the software package modules */ /* which a user may wish to call directly: */ /* ADDNOD - Updates the triangulation by appending a new */ /* node. */ /* AREAS - Returns the area of a spherical triangle. */ /* BNODES - Returns an array containing the indexes of the */ /* boundary nodes (if any) in counterclockwise */ /* order. Counts of boundary nodes, triangles, */ /* and arcs are also returned. */ /* CIRCUM - Returns the circumcenter of a spherical trian- */ /* gle. */ /* CRLIST - Returns the set of triangle circumcenters */ /* (Voronoi vertices) and circumradii associated */ /* with a triangulation. */ /* DELARC - Deletes a boundary arc from a triangulation. */ /* DELNOD - Updates the triangulation with a nodal deletion. */ /* EDGE - Forces an arbitrary pair of nodes to be connec- */ /* ted by an arc in the triangulation. */ /* GETNP - Determines the ordered sequence of L closest */ /* nodes to a given node, along with the associ- */ /* ated distances. */ /* INSIDE - Locates a point relative to a polygon on the */ /* surface of the sphere. */ /* INTRSC - Returns the point of intersection between a */ /* pair of great circle arcs. */ /* JRAND - Generates a uniformly distributed pseudo-random */ /* int. */ /* LEFT - Locates a point relative to a great circle. */ /* NEARND - Returns the index of the nearest node to an */ /* arbitrary point, along with its squared */ /* distance. */ /* SCOORD - Converts a point from Cartesian coordinates to */ /* spherical coordinates. */ /* STORE - Forces a value to be stored in main memory so */ /* that the precision of floating point numbers */ /* in memory locations rather than registers is */ /* computed. */ /* TRANS - Transforms spherical coordinates into Cartesian */ /* coordinates on the unit sphere for input to */ /* Subroutine TRMESH. */ /* TRLIST - Converts the triangulation data structure to a */ /* triangle list more suitable for use in a fin- */ /* ite element code. */ /* TRLPRT - Prints the triangle list created by Subroutine */ /* TRLIST. */ /* TRMESH - Creates a Delaunay triangulation of a set of */ /* nodes. */ /* TRPLOT - Creates a level-2 Encapsulated Postscript (EPS) */ /* file containing a triangulation plot. */ /* TRPRNT - Prints the triangulation data structure and, */ /* optionally, the nodal coordinates. */ /* VRPLOT - Creates a level-2 Encapsulated Postscript (EPS) */ /* file containing a Voronoi diagram plot. */ /* On input: */ /* N = Number of nodes in the triangulation. N .GE. 3. */ /* X,Y,Z = Arrays of length N containing the Cartesian */ /* coordinates of distinct nodes. (X(K),Y(K), */ /* Z(K)) is referred to as node K, and K is re- */ /* ferred to as a nodal index. It is required */ /* that X(K)**2 + Y(K)**2 + Z(K)**2 = 1 for all */ /* K. The first three nodes must not be col- */ /* linear (lie on a common great circle). */ /* The above parameters are not altered by this routine. */ /* LIST,LPTR = Arrays of length at least 6N-12. */ /* LEND = Array of length at least N. */ /* NEAR,NEXT,DIST = Work space arrays of length at */ /* least N. The space is used to */ /* efficiently determine the nearest */ /* triangulation node to each un- */ /* processed node for use by ADDNOD. */ /* On output: */ /* LIST = Set of nodal indexes which, along with LPTR, */ /* LEND, and LNEW, define the triangulation as a */ /* set of N adjacency lists -- counterclockwise- */ /* ordered sequences of neighboring nodes such */ /* that the first and last neighbors of a bound- */ /* ary node are boundary nodes (the first neigh- */ /* bor of an interior node is arbitrary). In */ /* order to distinguish between interior and */ /* boundary nodes, the last neighbor of each */ /* boundary node is represented by the negative */ /* of its index. */ /* LPTR = Set of pointers (LIST indexes) in one-to-one */ /* correspondence with the elements of LIST. */ /* LIST(LPTR(I)) indexes the node which follows */ /* LIST(I) in cyclical counterclockwise order */ /* (the first neighbor follows the last neigh- */ /* bor). */ /* LEND = Set of pointers to adjacency lists. LEND(K) */ /* points to the last neighbor of node K for */ /* K = 1,...,N. Thus, LIST(LEND(K)) < 0 if and */ /* only if K is a boundary node. */ /* LNEW = Pointer to the first empty location in LIST */ /* and LPTR (list length plus one). LIST, LPTR, */ /* LEND, and LNEW are not altered if IER < 0, */ /* and are incomplete if IER > 0. */ /* NEAR,NEXT,DIST = Garbage. */ /* IER = Error indicator: */ /* IER = 0 if no errors were encountered. */ /* IER = -1 if N < 3 on input. */ /* IER = -2 if the first three nodes are */ /* collinear. */ /* IER = L if nodes L and M coincide for some */ /* M > L. The data structure represents */ /* a triangulation of nodes 1 to M-1 in */ /* this case. */ /* Modules required by TRMESH: ADDNOD, BDYADD, COVSPH, */ /* INSERT, INTADD, JRAND, */ /* LEFT, LSTPTR, STORE, SWAP, */ /* SWPTST, TRFIND */ /* Intrinsic function called by TRMESH: ABS */ /* *********************************************************** */ /* Local parameters: */ /* D = (Negative cosine of) distance from node K to */ /* node I */ /* D1,D2,D3 = Distances from node K to nodes 1, 2, and 3, */ /* respectively */ /* I,J = Nodal indexes */ /* I0 = Index of the node preceding I in a sequence of */ /* unprocessed nodes: I = NEXT(I0) */ /* K = Index of node to be added and DO-loop index: */ /* K > 3 */ /* LP = LIST index (pointer) of a neighbor of K */ /* LPL = Pointer to the last neighbor of K */ /* NEXTI = NEXT(I) */ /* NN = Local copy of N */ /* Parameter adjustments */ --dist; --next; --near__; --lend; --z__; --y; --x; --list; --lptr; /* Function Body */ nn = *n; if (nn < 3) { *ier = -1; return 0; } /* Store the first triangle in the linked list. */ if (! left_(&x[1], &y[1], &z__[1], &x[2], &y[2], &z__[2], &x[3], &y[3], & z__[3])) { /* The first triangle is (3,2,1) = (2,1,3) = (1,3,2). */ list[1] = 3; lptr[1] = 2; list[2] = -2; lptr[2] = 1; lend[1] = 2; list[3] = 1; lptr[3] = 4; list[4] = -3; lptr[4] = 3; lend[2] = 4; list[5] = 2; lptr[5] = 6; list[6] = -1; lptr[6] = 5; lend[3] = 6; } else if (! left_(&x[2], &y[2], &z__[2], &x[1], &y[1], &z__[1], &x[3], & y[3], &z__[3])) { /* The first triangle is (1,2,3): 3 Strictly Left 1->2, */ /* i.e., node 3 lies in the left hemisphere defined by */ /* arc 1->2. */ list[1] = 2; lptr[1] = 2; list[2] = -3; lptr[2] = 1; lend[1] = 2; list[3] = 3; lptr[3] = 4; list[4] = -1; lptr[4] = 3; lend[2] = 4; list[5] = 1; lptr[5] = 6; list[6] = -2; lptr[6] = 5; lend[3] = 6; } else { /* The first three nodes are collinear. */ *ier = -2; return 0; } /* Initialize LNEW and test for N = 3. */ *lnew = 7; if (nn == 3) { *ier = 0; return 0; } /* A nearest-node data structure (NEAR, NEXT, and DIST) is */ /* used to obtain an expected-time (N*log(N)) incremental */ /* algorithm by enabling constant search time for locating */ /* each new node in the triangulation. */ /* For each unprocessed node K, NEAR(K) is the index of the */ /* triangulation node closest to K (used as the starting */ /* point for the search in Subroutine TRFIND) and DIST(K) */ /* is an increasing function of the arc length (angular */ /* distance) between nodes K and NEAR(K): -Cos(a) for arc */ /* length a. */ /* Since it is necessary to efficiently find the subset of */ /* unprocessed nodes associated with each triangulation */ /* node J (those that have J as their NEAR entries), the */ /* subsets are stored in NEAR and NEXT as follows: for */ /* each node J in the triangulation, I = NEAR(J) is the */ /* first unprocessed node in J's set (with I = 0 if the */ /* set is empty), L = NEXT(I) (if I > 0) is the second, */ /* NEXT(L) (if L > 0) is the third, etc. The nodes in each */ /* set are initially ordered by increasing indexes (which */ /* maximizes efficiency) but that ordering is not main- */ /* tained as the data structure is updated. */ /* Initialize the data structure for the single triangle. */ near__[1] = 0; near__[2] = 0; near__[3] = 0; for (k = nn; k >= 4; --k) { d1 = -(x[k] * x[1] + y[k] * y[1] + z__[k] * z__[1]); d2 = -(x[k] * x[2] + y[k] * y[2] + z__[k] * z__[2]); d3 = -(x[k] * x[3] + y[k] * y[3] + z__[k] * z__[3]); if (d1 <= d2 && d1 <= d3) { near__[k] = 1; dist[k] = d1; next[k] = near__[1]; near__[1] = k; } else if (d2 <= d1 && d2 <= d3) { near__[k] = 2; dist[k] = d2; next[k] = near__[2]; near__[2] = k; } else { near__[k] = 3; dist[k] = d3; next[k] = near__[3]; near__[3] = k; } /* L1: */ } /* Add the remaining nodes */ i__1 = nn; for (k = 4; k <= i__1; ++k) { addnod_(&near__[k], &k, &x[1], &y[1], &z__[1], &list[1], &lptr[1], & lend[1], lnew, ier); if (*ier != 0) { return 0; } /* Remove K from the set of unprocessed nodes associated */ /* with NEAR(K). */ i__ = near__[k]; if (near__[i__] == k) { near__[i__] = next[k]; } else { i__ = near__[i__]; L2: i0 = i__; i__ = next[i0]; if (i__ != k) { goto L2; } next[i0] = next[k]; } near__[k] = 0; /* Loop on neighbors J of node K. */ lpl = lend[k]; lp = lpl; L3: lp = lptr[lp]; j = (i__2 = list[lp], abs(i__2)); /* Loop on elements I in the sequence of unprocessed nodes */ /* associated with J: K is a candidate for replacing J */ /* as the nearest triangulation node to I. The next value */ /* of I in the sequence, NEXT(I), must be saved before I */ /* is moved because it is altered by adding I to K's set. */ i__ = near__[j]; L4: if (i__ == 0) { goto L5; } nexti = next[i__]; /* Test for the distance from I to K less than the distance */ /* from I to J. */ d__ = -(x[i__] * x[k] + y[i__] * y[k] + z__[i__] * z__[k]); if (d__ < dist[i__]) { /* Replace J by K as the nearest triangulation node to I: */ /* update NEAR(I) and DIST(I), and remove I from J's set */ /* of unprocessed nodes and add it to K's set. */ near__[i__] = k; dist[i__] = d__; if (i__ == near__[j]) { near__[j] = nexti; } else { next[i0] = nexti; } next[i__] = near__[k]; near__[k] = i__; } else { i0 = i__; } /* Bottom of loop on I. */ i__ = nexti; goto L4; /* Bottom of loop on neighbors J. */ L5: if (lp != lpl) { goto L3; } /* L6: */ } return 0; } /* trmesh_ */ nfft-3.3.2/3rdparty/cstripack/cstripack.h000066400000000000000000000106571300072027400203470ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef NFFT3_H #define NFFT3_H /* #include */ int addnod_(int *nst, int *k, double *x, double *y, double *z__, int *list, int *lptr, int *lend, int *lnew, int *ier); double areas_(double *v1, double *v2, double *v3); int bdyadd_(int *kk, int *i1, int *i2, int *list, int *lptr, int *lend, int *lnew); int bnodes_(int *n, int *list, int *lptr, int *lend, int *nodes, int *nb, int *na, int *nt); int circum_(double *v1, double *v2, double *v3, double *c__, int *ier); int covsph_(int *kk, int *n0, int *list, int *lptr, int *lend, int *lnew); int crlist_(int *n, int *ncol, double *x, double *y, double *z__, int *list, int *lend, int *lptr, int *lnew, int *ltri, int *listc, int *nb, double *xc, double *yc, double *zc, double *rc, int *ier); int delarc_(int *n, int *io1, int *io2, int * list, int *lptr, int *lend, int *lnew, int *ier); int delnb_(int *n0, int *nb, int *n, int *list, int *lptr, int *lend, int *lnew, int *lph); int delnod_(int *k, int *n, double *x, double *y, double *z__, int *list, int *lptr, int *lend, int *lnew, int *lwk, int *iwk, int *ier); int edge_(int *in1, int *in2, double *x, double *y, double *z__, int *lwk, int *iwk, int *list, int *lptr, int *lend, int *ier); int getnp_(double *x, double *y, double *z__, int *list, int *lptr, int *lend, int *l, int *npts, double *df, int *ier); int insert_(int *k, int *lp, int *list, int *lptr, int *lnew); int inside_(double *p, int *lv, double *xv, double *yv, double *zv, int * nv, int *listv, int *ier); int intadd_(int *kk, int *i1, int *i2, int *i3, int *list, int *lptr, int *lend, int *lnew); int intrsc_(double *p1, double *p2, double *cn, double *p, int *ier); int jrand_(int *n, int *ix, int *iy, int *iz); int left_(double *x1, double *y1, double *z1, double *x2, double *y2, double *z2, double *x0, double *y0, double *z0); int lstptr_(int *lpl, int *nb, int *list, int *lptr); int nbcnt_(int *lpl, int *lptr); int nearnd_(double *p, int *ist, int *n, double *x, double *y, double *z__, int *list, int *lptr, int *lend, double *al); int optim_(double *x, double *y, double *z__, int *na, int *list, int *lptr, int *lend, int *nit, int *iwk, int *ier); int scoord_(double *px, double *py, double *pz, double *plat, double *plon, double *pnrm); double store_(double *x); int swap_(int *in1, int *in2, int *io1, int * io2, int *list, int *lptr, int *lend, int *lp21); int swptst_(int *n1, int *n2, int *n3, int *n4, double *x, double *y, double *z__); int trans_(int *n, double *rlat, double *rlon, double *x, double *y, double *z__); int trfind_(int *nst, double *p, int *n, double *x, double *y, double *z__, int *list, int *lptr, int *lend, double *b1, double *b2, double *b3, int *i1, int *i2, int *i3); int trlist_(int *n, int *list, int *lptr, int *lend, int *nrow, int *nt, int *ltri, int *ier); int trlprt_(int *n, double *x, double *y, double *z__, int *iflag, int *nrow, int *nt, int *ltri, int *lout); int trmesh_(int *n, double *x, double *y, double *z__, int *list, int *lptr, int *lend, int *lnew, int *near__, int *next, double *dist, int *ier); int trplot_(int *lun, double *pltsiz, double *elat, double *elon, double *a, int *n, double *x, double *y, double *z__, int *list, int *lptr, int *lend, char *title, int *numbr, int *ier, short title_len); int trprnt_(int *n, double *x, double *y, double *z__, int *iflag, int *list, int *lptr, int *lend, int *lout); int vrplot_(int *lun, double *pltsiz, double *elat, double *elon, double *a, int *n, double *x, double *y, double *z__, int *nt, int *listc, int *lptr, int *lend, double *xc, double *yc, double *zc, char *title, int *numbr, int *ier, short title_len); #endif nfft-3.3.2/AUTHORS000066400000000000000000000030751300072027400135240ustar00rootroot00000000000000The NFFT3 package was developed and is maintained by Prof. Dr. Daniel Potts TU Chemnitz, Fakultaet fuer Mathematik Reichenhainer Str. 39 09107 Chemnitz, GERMANY Dr. Jens Keiner - fast polynomial transform (/kernel/fpt) - nfft on the sphere (/kernel/nfsft) - fast summation on the sphere (/applications/fastsumS2) - autotools, doxygen and friends - Matlab mex interface for nfsft (/matlab/nfsft) Prof. Dr. Stefan Kunis - nfft (/kernel/nfft) - inverse transforms (kernel/solver) - nfft on the hyperbolic cross (/kernel/nsfft) - fast Gauss transform (/applications/fastgauss) - Matlab mex interface for nfft (/matlab/nfft) Further contributions, in particular applications, are due to Dr. Markus Fenn - nfft on the hyperbolic cross (/kernel/nsfft) - polar fft (/applications/polarFFT) - discrete Radon transform and ridgelet transform (/applications/radon) - fast summation (/applications/fastsum) Steffen Klatt - nonequispaced cosine transform (/kernel/nfct) - nonequispaced sine transform (/kernel/nfst) Dr. Tobias Knopp - transforms in magnetic resonance imaging (/kernel/mri) - nonequispaced in time and frequency fft (/kernel/nnfft) - reconstruction in magnetic resonance imaging (/applications/mri) Dr. Antje Vollrath - transforms on the rotation group SO(3) (/kernel/nfsoft) Toni Volkmer - OpenMP parallelization of nfft (/kernel/nfft) - OpenMP parallelization of nfsft (/kernel/nfsft) - OpenMP parallelization of fast summation (/applications/fastsum) nfft-3.3.2/CONVENTIONS000066400000000000000000000016071300072027400142030ustar00rootroot00000000000000Code conventions used internally by NFFT3 (not in API): Common names: R : real type, (typically fftw_real) E : real type for local variables (possibly extra precision) C : complex type A : assert CK : check X(...) : used for mangling of external names (see below) Y(...) : used for mangling of external names (see below) FFTW(...) : used for mangling of FFTW API names NAME MANGLING: use Y(foo) for external names instead of nfft_foo. Y(foo) expands to nfftf_foo, nfftl_foo, or nfft_foo, depending on the precision. X(foo) also expands to the corresponding prefix, but is local to each module. I.e. X(foo) will expand to nfct_foo in the NFCT module, but Y(foo) will always be nfft_foo. FFTW(foo) expands to fftw_foo. Names that are not exported do not need to be mangled. nfft-3.3.2/COPYING000066400000000000000000000431221300072027400135040ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. nfft-3.3.2/ChangeLog000066400000000000000000000123601300072027400142230ustar00rootroot00000000000000This file contains the version history for NFFT 3.x.x. Changes in version 3.3.2: Bugfixes - #20 `make check` crashes on windows. - #24 Testsuite failures on selected architectures with 3.3.1. Enhancements - #25 Add support for GNU Octave via MEX interface. - #27 Enable query of versioning information. Changes in version 3.3.1: Bugfixes - #2 NFFT/NFST/NFCT transforms fail when using certain window functions. - #11 NFSFT module crashes due to pointer type incompatibility. - #14 applications\fastsum\fastsum_matlab produces wrong results in Windows. - #15 Fixes for Matlab applications/examples in Windows. - #16 X(bsplines)(n, x) can be inaccurate when x is close to zero. - #17 MATLAB r2015b/r2016a don't ship symlink libmfftw3.so to libmfftw3.so.3. - #18 Define format string for ptrdiff_t in platform-dependent macro. Enhancements - #3 Allow to select scope of unit tests via configure. - #1 Extend Travis CI configuration. Changes in version 3.3.0: - Added unit tests for some parts of the library. They are invoked via make check, but only if the CUnit framework was found on the build host. Changes in version 3.2.4 - Fixed an issue when linker flags were not set correctly. Changes in version 3.2.3 - Added a workaround for an internal compiler error occuring with gcc 4.7.1 in kernel/mri - Added a workaround for a compilation error in the MATLAB mex interface for gcc 4.7.1 when compiling with C99 support (-std=gnu99) Changes in version 3.2.2: - Fixed several problems introduced in version 3.2.1 - Fixed an issue when the configure script would not run correctly when using the option --with-fftw3. Changes in version 3.2.1: - Added missing files of new nfft MATLAB (class) interface to release. Changes in version 3.2.0: - Added support for OpenMP. To activate, use the configure script with the --enable-openmp option. - Added ticks.h from FFTW to leverage CPU cycle counters. If cycle counters are available, the configure script will try to determine the number of ticks per second. If successful, example programs measure times in seconds. Otherwise, example programs will output raw cycle counter differences in arbitrary units. If cycle counters are not available, results of time measurements are undefined. - Renamed functions of direct (non-fast) algorithms to _direct, e.g. the function name for the direct computation of the non-equispaced Fourier transform is nfft_trafo_direct(nfft_plan) instead of ndft_trafo(nfft_plan). Changes in version 3.1.4: - Added pkg-config file (thanks Gert Wollny) - Headers include/nfft3util.h, applications/fastsum/fastsum.h, and applications/fastsum/kernels.h can now be included by C++ compilers. - Fixed an error that occured when trying to create symbolic links to Matlab mex files during installation. - All programs from the application and examples subdirectories are no longer installed. The same holds for the Matlab code from the matlab subdirectory. Changes in version 3.1.3: - Fixed some issues that can cause C++ compilers to fail. Thanks to Romain Bossart. - Fixed an error that caused linking against FFTW while checking compiler characteristics in the configure script. This only affected installations where FFTW had been installed in a custom location. - Doxygen generated documentation is now only deleted if the target maintainer-clean is used. The documentation is no longer deleted if the user invokes the usual clean target. Changes in version 3.1.2: - Fixed a bug in fpt_precompute() that caused excessive stabilization and incorrect results. - Fixed three bugs in the nfft: window function defines are moved to the internal header infft.h, a larger lookup table is used for PRE_LIN_PSI, and nfft_adjoint for d=2,3 and PRE_FULL_PSI writes its output correctly. Changes in version 3.1.1: - Added a workaround for an internal compiler error occuring with gcc 4.3.2. Changes in version 3.1.0: - The FPT example program, that is, examples/fpt/simple_test has been modified to not require the NFCT module anymore. This solves the problem that NFFT won't compile when the FPT module has been switched on while the NFCT module is swithced off. Changes in version 3.1.0: - A module, called nfsoft, for fast Fourier transforms on the rotation group SO(3) has been added. - It is now possible to configure the build process so that only specific modules are compiled and installed. Invoke the configure script with option "--help" for details. - The handling of how to link against the fftw3 library has been improved. The new configure script options "--with-fftw3", "--with-fftw-includedir", and "--with-fftw-libdir" allow to specify where fftw3 has been installed. - Improved compliance with GNU standards. - The experimental Matlab interface has been improved and is now officially a part of NFFT3. To compile the Matlab modules, invoke the configure script with the option --with-matlab=. Also, an interface to the plain NFFT has been added. Changes in version 3.0.2: - Fixed a bug in the fpt module that lead to wrong output. nfft-3.3.2/Makefile.am000066400000000000000000000053631300072027400145120ustar00rootroot00000000000000LIBTOOL_DEPS = @LIBTOOL_DEPS@ libtool: $(LIBTOOL_DEPS) $(SHELL) ./config.status --recheck # Subdirectories DIST_SUBDIRS=3rdparty include kernel . tests examples applications matlab support doxygen if HAVE_EXAMPLES EXAMPLE_DIRS=examples else EXAMPLE_DIRS= endif if HAVE_APPLICATIONS APPLICATION_DIRS=applications else APPLICATION_DIRS= endif if HAVE_MATLAB MATLAB_DIRS=matlab LIBNFFT3_MATLAB_LA=libnfft3@PREC_SUFFIX@_matlab.la else MATLAB_DIRS= LIBNFFT3_MATLAB_LA= endif if HAVE_THREADS LIBNFFT3_THREADS_LA = libnfft3@PREC_SUFFIX@_threads.la else LIBNFFT3_THREADS_LA = endif SUBDIRS= 3rdparty include kernel . tests $(EXAMPLE_DIRS) $(APPLICATION_DIRS) $(MATLAB_DIRS) lib_LTLIBRARIES = libnfft3@PREC_SUFFIX@.la $(LIBNFFT3_THREADS_LA) noinst_LTLIBRARIES = $(LIBNFFT3_MATLAB_LA) libnfft3@PREC_SUFFIX@_la_SOURCES = libnfft3@PREC_SUFFIX@_la_LIBADD = 3rdparty/lib3rdparty.la kernel/libkernel.la @fftw3_LIBS@ -lm libnfft3@PREC_SUFFIX@_la_LDFLAGS = -no-undefined -version-info @SHARED_VERSION_INFO@ @fftw3_LDFLAGS@ if HAVE_THREADS libnfft3@PREC_SUFFIX@_threads_la_SOURCES = libnfft3@PREC_SUFFIX@_threads_la_LIBADD = 3rdparty/lib3rdparty.la kernel/libkernel_threads.la @fftw3_threads_LIBS@ -lm libnfft3@PREC_SUFFIX@_threads_la_LDFLAGS = -no-undefined -version-info @SHARED_VERSION_INFO@ @fftw3_LDFLAGS@ if HAVE_OPENMP libnfft3@PREC_SUFFIX@_threads_la_CFLAGS = $(OPENMP_CFLAGS) endif endif if HAVE_MATLAB libnfft3@PREC_SUFFIX@_matlab_la_SOURCES = if HAVE_MATLAB_THREADS libnfft3@PREC_SUFFIX@_matlab_la_LIBADD = 3rdparty/lib3rdparty.la kernel/libkernel_threads.la @matlab_fftw3_LIBS@ -lm else libnfft3@PREC_SUFFIX@_matlab_la_LIBADD = 3rdparty/lib3rdparty.la kernel/libkernel.la @matlab_fftw3_LIBS@ -lm endif libnfft3@PREC_SUFFIX@_matlab_la_LDFLAGS = @matlab_fftw3_LDFLAGS@ endif EXTRA_DIST = bootstrap.sh doxygen.dox nfft3.pc.in doc if HAVE_NON_DOUBLE_PRECISION nfft3@PREC_SUFFIX@.pc: nfft3.pc cp -f nfft3.pc nfft3@PREC_SUFFIX@.pc endif pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = nfft3@PREC_SUFFIX@.pc install-data-hook: if test -f "$(abs_top_builddir)/doc/html/index.html"; then \ $(MKDIR_P) $(DESTDIR)$(docdir); \ cp -Rf $(abs_top_builddir)/doc/html $(DESTDIR)$(docdir)/; \ elif test -f "$(abs_top_srcdir)/doc/html/index.html"; then \ $(MKDIR_P) $(DESTDIR)$(docdir); \ cp -Rf $(abs_top_srcdir)/doc/html $(DESTDIR)$(docdir)/; \ fi uninstall-hook: chmod -Rf u+rwX $(DESTDIR)$(docdir) rm -Rf $(DESTDIR)$(docdir) clean-local: rm -Rf $(abs_top_builddir)/doc/html dist-hook: doc rm -f @DX_DOCDIR@/@PACKAGE@.tag cp -R $(abs_top_builddir)/doc $(distdir)/ rm -Rf `find $(distdir) -name .svn -type d` include aminclude.am doc: doxygen-doc # Flags to be passed to aclocal. ACLOCAL_AMFLAGS = -I m4 AM_DISTCHECK_CONFIGURE_FLAGS = --enable-allnfft-3.3.2/NEWS000066400000000000000000000000001300072027400131340ustar00rootroot00000000000000nfft-3.3.2/README000077700000000000000000000000001300072027400146012README.mdustar00rootroot00000000000000nfft-3.3.2/README.md000066400000000000000000000124231300072027400137300ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/NFFT/nfft.svg?branch=develop)](https://travis-ci.org/NFFT/nfft) NFFT - Nonequispaced FFT ========================= Overview -------- NFFT is a software library, written in C, for computing non-equispaced fast Fourier transforms and related variations. It implements the following transforms: 1. Non-equispaced fast Fourier transform (NFFT) - forward transform *(NFFT)*, i.e. frequency to time/space domain - adjoint transform *(adjoint NFFT)*, i.e. time/space to frequency domain 2. Generalisations - to arbitrary nodes in time *and* frequency domain *(NNFFT)* - to real-valued data, i.e. (co)sine transforms, *(NFCT, NFST)* - to the sphere S^2 *(NFSFT)* - to the rotation group *(NFSOFT)* - to the hyperbolic cross *(NSFFT)* 3. Generalised inverse transformations based on iterative methods, e.g. CGNR/CGNE Some examples for application of these transforms are provided: 1. Medical imaging - magnetic resonance imaging - computerised tomography 2. Summation schemes - fast Gauss transform (FGT) - singular kernels - zonal kernels 3. polar FFT, discrete Radon transform, ridgelet transform Detailed API documentation in HTML format can be found in `doc/api/html/index.html`, if you are working from a release tarball. When working from a source repository, the documentation can be generated with Doxygen. ``` make doc ``` Building -------- When working from a source repository, your need to run libtoolize and autoreconf first. A bash script to do this is provided. ``` ./bootstrap.sh ``` The rest of the build process is standard. ``` ./configure (add options as necessary) make make install ``` Optionally, unit tests may be run. ``` make check ``` Citing ------ The most current general paper, the one that we recommend if you wish to cite NFFT, is *Keiner, J., Kunis, S., and Potts, D. ''Using NFFT 3 - a software library for various nonequispaced fast Fourier transforms'' ACM Trans. Math. Software,36, Article 19, 1-30, 2009*. Feedback -------- Your comments are welcome! This is the third version of the library and may not be as robust or well documented as it should be. Please keep track of bugs or missing/confusing instructions and report them to [Daniel Potts](mailto:potts@mathematik.tu-chemnitz.de). The postal address is ``` Prof. Dr. Daniel Potts TU Chemnitz, Fakultaet fuer Mathematik Reichenhainer Str. 39 09107 Chemnitz GERMANY ``` Alternatively, you might contact [Stefan Kunis](mailto:stefan.kunis@math.uos.de) or [Jens Keiner](mailto:jens@nfft.org). If you find NFFT useful, we would be delighted to hear about what application you are using NFFT for! Legal Information & Credits --------------------------- Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts This software was written by Jens Keiner, Stefan Kunis and Daniel Potts. It was developed at the Mathematical Institute, University of Luebeck, and at the Faculty of Mathematics, Chemnitz University of Technology. NFFT3 is free software. You can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. If not stated otherwise, this applies to all files contained in this package and its sub-directories. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Directory structure ------------------- File/Folder | Purpose ------------------:| ------------------------------------------------------ 3rdparty (dir) | Third-party source code aclocal.m4 | Macros for configure script applications (dir) | Application programs (see 4) above) AUTHORS | Information about the authors of NFFT bootstrap.sh | Bootstrap shell script that call Autoconf and friends ChangeLog | A short version history config.guess | Used by configure script config.sub | Used by configure script configure | Configure script (created by calling ./bootstrap.sh) configure.in | Autoconf configure script template CONVENTIONS | Internal coding conventions COPYING | Information about redistributing NFFT depcomp | Used by configure script doc (dir) | User and developer documentation examples (dir) | Simple examples for using NFFT routines include (dir) | Header files INSTALL | Installation instructions install-sh | Used by configure script kernel (dir) | Source code for core library routines ltmain.sh | Used by configure script Makefile.am | Automake Makefile template Makefile.in | Makefile template generated from Makefile.am, processed by configure script matlab (dir) | Matlab MEX interfaces for nfft, nfsft, nfsoft, nfft missing | Used by configure script NEWS | New and noteworthy README | This file tests (dir) | CUnit tests TODO | Work to be done nfft-3.3.2/aminclude.am000066400000000000000000000065451300072027400147410ustar00rootroot00000000000000## --------------------------------- ## ## Format-independent Doxygen rules. ## ## --------------------------------- ## if DX_COND_doc ## ------------------------------- ## ## Rules specific for HTML output. ## ## ------------------------------- ## if DX_COND_html DX_CLEAN_HTML = @DX_DOCDIR@/html endif DX_COND_html ## ------------------------------ ## ## Rules specific for CHM output. ## ## ------------------------------ ## if DX_COND_chm DX_CLEAN_CHM = @DX_DOCDIR@/chm if DX_COND_chi DX_CLEAN_CHI = @DX_DOCDIR@/@PACKAGE@.chi endif DX_COND_chi endif DX_COND_chm ## ------------------------------ ## ## Rules specific for MAN output. ## ## ------------------------------ ## if DX_COND_man DX_CLEAN_MAN = @DX_DOCDIR@/man endif DX_COND_man ## ------------------------------ ## ## Rules specific for RTF output. ## ## ------------------------------ ## if DX_COND_rtf DX_CLEAN_RTF = @DX_DOCDIR@/rtf endif DX_COND_rtf ## ------------------------------ ## ## Rules specific for XML output. ## ## ------------------------------ ## if DX_COND_xml DX_CLEAN_XML = @DX_DOCDIR@/xml endif DX_COND_xml ## ----------------------------- ## ## Rules specific for PS output. ## ## ----------------------------- ## if DX_COND_ps DX_CLEAN_PS = @DX_DOCDIR@/@PACKAGE@.ps DX_PS_GOAL = doxygen-ps doxygen-ps: @DX_DOCDIR@/@PACKAGE@.ps @DX_DOCDIR@/@PACKAGE@.ps: @DX_DOCDIR@/@PACKAGE@.tag cd @DX_DOCDIR@/latex; \ rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \ $(DX_LATEX) refman.tex; \ $(MAKEINDEX_PATH) refman.idx; \ $(DX_LATEX) refman.tex; \ countdown=5; \ while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \ refman.log > /dev/null 2>&1 \ && test $$countdown -gt 0; do \ $(DX_LATEX) refman.tex; \ countdown=`expr $$countdown - 1`; \ done; \ $(DX_DVIPS) -o ../@PACKAGE@.ps refman.dvi endif DX_COND_ps ## ------------------------------ ## ## Rules specific for PDF output. ## ## ------------------------------ ## if DX_COND_pdf DX_CLEAN_PDF = @DX_DOCDIR@/@PACKAGE@.pdf DX_PDF_GOAL = doxygen-pdf doxygen-pdf: @DX_DOCDIR@/@PACKAGE@.pdf @DX_DOCDIR@/@PACKAGE@.pdf: @DX_DOCDIR@/@PACKAGE@.tag cd @DX_DOCDIR@/latex; \ rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \ $(DX_PDFLATEX) refman.tex; \ $(DX_MAKEINDEX) refman.idx; \ $(DX_PDFLATEX) refman.tex; \ countdown=5; \ while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \ refman.log > /dev/null 2>&1 \ && test $$countdown -gt 0; do \ $(DX_PDFLATEX) refman.tex; \ countdown=`expr $$countdown - 1`; \ done; \ mv refman.pdf ../@PACKAGE@.pdf endif DX_COND_pdf ## ------------------------------------------------- ## ## Rules specific for LaTeX (shared for PS and PDF). ## ## ------------------------------------------------- ## if DX_COND_latex DX_CLEAN_LATEX = @DX_DOCDIR@/latex endif DX_COND_latex .PHONY: doxygen-run doxygen-doc $(DX_PS_GOAL) $(DX_PDF_GOAL) .INTERMEDIATE: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL) doxygen-run: @DX_DOCDIR@/@PACKAGE@.tag doxygen-doc: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL) @DX_DOCDIR@/@PACKAGE@.tag: $(DX_CONFIG) $(pkginclude_HEADERS) $(DX_ENV) $(DX_DOXYGEN) $(DX_CONFIG) echo Timestamp >$@ DX_CLEANFILES = \ @DX_DOCDIR@/@PACKAGE@.tag \ -r \ $(DX_CLEAN_HTML) \ $(DX_CLEAN_CHM) \ $(DX_CLEAN_CHI) \ $(DX_CLEAN_MAN) \ $(DX_CLEAN_RTF) \ $(DX_CLEAN_XML) \ $(DX_CLEAN_PS) \ $(DX_CLEAN_PDF) \ $(DX_CLEAN_LATEX) endif DX_COND_doc nfft-3.3.2/applications/000077500000000000000000000000001300072027400151355ustar00rootroot00000000000000nfft-3.3.2/applications/Makefile.am000066400000000000000000000006471300072027400172000ustar00rootroot00000000000000if HAVE_NFSFT DIR_FASTSUMS2=fastsumS2 DIR_QUADRATURES2=quadratureS2 DIR_ITERS2=iterS2 else DIR_FASTSUMS2= DIR_QUADRATURES2= DIR_ITERS2= endif if HAVE_MRI DIR_MRI=mri else DIR_MRI= endif DIST_SUBDIRS = fastgauss fastsum fastsumS2 mri polarFFT \ quadratureS2 radon iterS2 SUBDIRS= fastgauss fastsum $(DIR_FASTSUMS2) $(DIR_MRI) polarFFT \ $(DIR_QUADRATURES2) radon $(DIR_ITERS2) EXTRA_DIST = doxygen.c nfft-3.3.2/applications/doxygen.c000066400000000000000000000015141300072027400167570ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \defgroup applications Applications */ nfft-3.3.2/applications/fastgauss/000077500000000000000000000000001300072027400171355ustar00rootroot00000000000000nfft-3.3.2/applications/fastgauss/Makefile.am000066400000000000000000000003561300072027400211750ustar00rootroot00000000000000AM_CPPFLAGS = -I$(top_srcdir)/include noinst_PROGRAMS = fastgauss fastgauss_SOURCES = fastgauss.c fastgauss_LDADD = $(top_builddir)/libnfft3@PREC_SUFFIX@.la @fftw3_LDFLAGS@ @fftw3_LIBS@ EXTRA_DIST = levelplots.m show_results.m README nfft-3.3.2/applications/fastgauss/README000066400000000000000000000012711300072027400200160ustar00rootroot00000000000000Examples to the fast Gauss transform with complex parameters Author Stefan Kunis List of files and purpose README this file fastgauss.c univariate Gauss transform and tests levelplots.m visualisation with MATLAB of error estimates show_results.m visualisation with MATLAB of tested accuracy, relies on output_error.m and output_error_p.m produced by fastgauss.c References Stefan Kunis, Daniel Potts, and Gabriele Steidl Fast Gauss transforms with complex parameters using NFFTs. J. Numer. Math., to appear. 2006 Preprint available online http://www.tu-chemnitz.de/~potts/paper/fastgauss.pdf nfft-3.3.2/applications/fastgauss/fastgauss.c.in000066400000000000000000000370361300072027400217170ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \defgroup applications_fastgauss Fast Gauss transfrom with complex parameter * \ingroup applications * \{ */ #include #include #include #include #define @NFFT_PRECISION_MACRO@ #include "nfft3mp.h" /** * If this flag is set, the whole matrix is precomputed and stored for the * discrete Gauss transfrom. * * \see fgt_init_node_dependent * \see fgt_init * \author Stefan Kunis */ #define DGT_PRE_CEXP (1U<< 0) /** * If this flag is set, the fast Gauss transform uses the discrete instead of * the fast Fourier transform. * * \see fgt_init * \see nfft_trafo_direct * \see nfft_trafo * \author Stefan Kunis */ #define FGT_NDFT (1U<< 1) /** * If this flag is set, the discrete Fourier coefficients of the uniformly * sampled Gaussian are used instead of the sampled continuous Fourier * transform. * * \see fgt_init * \author Stefan Kunis */ #define FGT_APPROX_B (1U<< 2) /** Structure for the Gauss transform */ typedef struct { int N; /**< number of source nodes */ int M; /**< number of target nodes */ NFFT_C *alpha; /**< source coefficients */ NFFT_C *f; /**< target evaluations */ unsigned flags; /**< flags for precomputation and approximation type */ NFFT_C sigma; /**< parameter of the Gaussian */ NFFT_R *x; /**< source nodes in \f$[-1/4,1/4]\f$*/ NFFT_R *y; /**< target nodes in \f$[-1/4,1/4]\f$*/ NFFT_C *pre_cexp; /**< precomputed values for dgt */ int n; /**< expansion degree */ NFFT_R p; /**< period, at least 1 */ NFFT_C *b; /**< expansion coefficients */ NFFT(plan) *nplan1; /**< source nfft plan */ NFFT(plan) *nplan2; /**< target nfft plan */ } fgt_plan; /** * Executes the discrete Gauss transform. * * \arg ths The pointer to a fgt plan * * \author Stefan Kunis */ static void dgt_trafo(fgt_plan *ths) { NFFT_INT j, k, l; for (j = 0; j < ths->M; j++) ths->f[j] = NFFT_K(0.0); if (ths->flags & DGT_PRE_CEXP) for (j = 0, l = 0; j < ths->M; j++) for (k = 0; k < ths->N; k++, l++) ths->f[j] += ths->alpha[k] * ths->pre_cexp[l]; else for (j = 0; j < ths->M; j++) for (k = 0; k < ths->N; k++) ths->f[j] += ths->alpha[k] * NFFT_M(cexp)( -ths->sigma * (ths->y[j] - ths->x[k]) * (ths->y[j] - ths->x[k])); } /** * Executes the fast Gauss transform. * * \arg ths The pointer to a fgt plan * * \author Stefan Kunis */ static void fgt_trafo(fgt_plan *ths) { NFFT_INT l; if (ths->flags & FGT_NDFT) { NFFT(adjoint_direct)(ths->nplan1); for (l = 0; l < ths->n; l++) ths->nplan1->f_hat[l] *= ths->b[l]; NFFT(trafo_direct)(ths->nplan2); } else { NFFT(adjoint)(ths->nplan1); for (l = 0; l < ths->n; l++) ths->nplan1->f_hat[l] *= ths->b[l]; NFFT(trafo)(ths->nplan2); } } /** * Initialisation of a transform plan, guru. * * \arg ths The pointer to a fpt plan * \arg N The number of source nodes * \arg M The number of target nodes * \arg sigma The parameter of the Gaussian * \arg n The polynomial expansion degree * \arg p the periodisation length, at least 1 * \arg m The spatial cut-off of the nfft * \arg flags FGT flags to use * * \author Stefan Kunis */ static void fgt_init_guru(fgt_plan *ths, int N, int M, NFFT_C sigma, int n, NFFT_R p, int m, unsigned flags) { int j, n_fftw; FFTW(plan) fplan; ths->M = M; ths->N = N; ths->sigma = sigma; ths->flags = flags; ths->x = (NFFT_R*) NFFT(malloc)((size_t)(ths->N) * sizeof(NFFT_R)); ths->y = (NFFT_R*) NFFT(malloc)((size_t)(ths->M) * sizeof(NFFT_R)); ths->alpha = (NFFT_C*) NFFT(malloc)((size_t)(ths->N) * sizeof(NFFT_C)); ths->f = (NFFT_C*) NFFT(malloc)((size_t)(ths->M) * sizeof(NFFT_C)); ths->n = n; ths->p = p; ths->b = (NFFT_C*) NFFT(malloc)((size_t)(ths->n) * sizeof(NFFT_C)); ths->nplan1 = (NFFT(plan)*) NFFT(malloc)(sizeof(NFFT(plan))); ths->nplan2 = (NFFT(plan)*) NFFT(malloc)(sizeof(NFFT(plan))); n_fftw = (int)NFFT(next_power_of_2)(2 * ths->n); { NFFT(init_guru)(ths->nplan1, 1, &(ths->n), ths->N, &n_fftw, m, PRE_PHI_HUT | PRE_PSI | MALLOC_X | MALLOC_F_HAT | FFTW_INIT, FFTW_MEASURE); NFFT(init_guru)(ths->nplan2, 1, &(ths->n), ths->M, &n_fftw, m, PRE_PHI_HUT | PRE_PSI | MALLOC_X | FFTW_INIT, FFTW_MEASURE); } ths->nplan1->f = ths->alpha; ths->nplan2->f_hat = ths->nplan1->f_hat; ths->nplan2->f = ths->f; if (ths->flags & FGT_APPROX_B) { fplan = FFTW(plan_dft_1d)(ths->n, ths->b, ths->b, FFTW_FORWARD, FFTW_MEASURE); for (j = 0; j < ths->n; j++) ths->b[j] = NFFT_M(cexp)( -ths->p * ths->p * ths->sigma * ((NFFT_R)(j) - (NFFT_R)(ths->n) / NFFT_K(2.0)) * ((NFFT_R)(j) - (NFFT_R)(ths->n) / NFFT_K(2.0)) / ((NFFT_R) (ths->n * ths->n))) / ((NFFT_R)(ths->n)); NFFT(fftshift_complex_int)(ths->b, 1, &ths->n); FFTW(execute)(fplan); NFFT(fftshift_complex_int)(ths->b, 1, &ths->n); FFTW(destroy_plan)(fplan); } else { for (j = 0; j < ths->n; j++) ths->b[j] = NFFT_K(1.0) / ths->p * NFFT_M(csqrt)(NFFT_KPI / ths->sigma) * NFFT_M(cexp)( -NFFT_KPI * NFFT_KPI * ((NFFT_R)(j) - (NFFT_R)(ths->n) / NFFT_K(2.0)) * ((NFFT_R)(j) - (NFFT_R)(ths->n) / NFFT_K(2.0)) / (ths->p * ths->p * ths->sigma)); } } /** * Initialisation of a transform plan, simple. * * \arg ths The pointer to a fpt plan * \arg N The number of source nodes * \arg M The number of target nodes * \arg sigma The parameter of the Gaussian * \arg eps The target accuracy * * \author Stefan Kunis */ static void fgt_init(fgt_plan *ths, int N, int M, NFFT_C sigma, NFFT_R eps) { NFFT_R p; int n; p = NFFT_K(0.5) + NFFT_M(sqrt)(-NFFT_M(log)(eps) / NFFT_M(creal)(sigma)); if (p < NFFT_K(1.0)) p = NFFT_K(1.0); n = (int)(2 * (NFFT_M(lrint)(NFFT_M(ceil)(p * NFFT_M(cabs)(sigma) / NFFT_KPI * NFFT_M(sqrt)(-NFFT_M(log)(eps) / NFFT_M(creal)(sigma)))))); fgt_init_guru(ths, N, M, sigma, n, p, 7, N * M <= ((NFFT_INT) (1U << 20)) ? DGT_PRE_CEXP : 0); } /** * Initialisation of a transform plan, depends on source and target nodes. * * \arg ths The pointer to a fpt plan * \author Stefan Kunis */ static void fgt_init_node_dependent(fgt_plan *ths) { int j, k, l; if (ths->flags & DGT_PRE_CEXP) { ths->pre_cexp = (NFFT_C*) NFFT(malloc)((size_t)(ths->M * ths->N) * sizeof(NFFT_C)); for (j = 0, l = 0; j < ths->M; j++) for (k = 0; k < ths->N; k++, l++) ths->pre_cexp[l] = NFFT_M(cexp)( -ths->sigma * (ths->y[j] - ths->x[k]) * (ths->y[j] - ths->x[k])); } for (j = 0; j < ths->nplan1->M_total; j++) ths->nplan1->x[j] = ths->x[j] / ths->p; for (j = 0; j < ths->nplan2->M_total; j++) ths->nplan2->x[j] = ths->y[j] / ths->p; if (ths->nplan1->flags & PRE_PSI) NFFT(precompute_psi)(ths->nplan1); if (ths->nplan2->flags & PRE_PSI) NFFT(precompute_psi)(ths->nplan2); } /** * Destroys the transform plan. * * \arg ths The pointer to the fgt plan * \author Stefan Kunis */ static void fgt_finalize(fgt_plan *ths) { NFFT(finalize)(ths->nplan2); NFFT(finalize)(ths->nplan1); NFFT(free)(ths->nplan2); NFFT(free)(ths->nplan1); NFFT(free)(ths->b); NFFT(free)(ths->f); NFFT(free)(ths->y); NFFT(free)(ths->alpha); NFFT(free)(ths->x); } /** * Random initialisation of a fgt plan. * * \arg ths The pointer to the fgt plan * \author Stefan Kunis */ static void fgt_test_init_rand(fgt_plan *ths) { NFFT_INT j, k; for (k = 0; k < ths->N; k++) ths->x[k] = NFFT(drand48)() / NFFT_K(2.0) - NFFT_K(1.0) / NFFT_K(4.0); for (j = 0; j < ths->M; j++) ths->y[j] = NFFT(drand48)() / NFFT_K(2.0) - NFFT_K(1.0) / NFFT_K(4.0); for (k = 0; k < ths->N; k++) ths->alpha[k] = NFFT(drand48)() - NFFT_K(1.0) / NFFT_K(2.0) + _Complex_I * (NFFT(drand48)() - NFFT_K(1.0) / NFFT_K(2.0)); } /** * Compares execution times for the fast and discrete Gauss transform. * * \arg ths The pointer to the fgt plan * \arg dgt If this parameter is set \ref dgt_trafo is called as well * * \author Stefan Kunis */ static NFFT_R fgt_test_measure_time(fgt_plan *ths, unsigned dgt) { int r; NFFT_R t0, t1, time_diff; NFFT_R t_out; NFFT_R tau = NFFT_K(0.01); t_out = NFFT_K(0.0); r = 0; while (t_out < tau) { r++; t0 = NFFT(clock_gettime_seconds)(); if (dgt) dgt_trafo(ths); else fgt_trafo(ths); t1 = NFFT(clock_gettime_seconds)(); time_diff = t1 - t0; t_out += time_diff; } t_out /= (NFFT_R)(r); return t_out; } /** * Simple example that computes fast and discrete Gauss transforms. * * \arg ths The pointer to the fgt plan * \arg sigma The parameter of the Gaussian * \arg eps The target accuracy * * \author Stefan Kunis */ static void fgt_test_simple(int N, int M, NFFT_C sigma, NFFT_R eps) { fgt_plan my_plan; NFFT_C *swap_dgt; fgt_init(&my_plan, N, M, sigma, eps); swap_dgt = (NFFT_C*) NFFT(malloc)((size_t)(my_plan.M) * sizeof(NFFT_C)); fgt_test_init_rand(&my_plan); fgt_init_node_dependent(&my_plan); NFFT_CSWAP(swap_dgt, my_plan.f); dgt_trafo(&my_plan); NFFT(vpr_complex)(my_plan.f, my_plan.M, "discrete gauss transform"); NFFT_CSWAP(swap_dgt, my_plan.f); fgt_trafo(&my_plan); NFFT(vpr_complex)(my_plan.f, my_plan.M, "fast gauss transform"); printf("\n relative error: %1.3" NFFT__FES__ "\n", NFFT(error_l_infty_1_complex)(swap_dgt, my_plan.f, my_plan.M, my_plan.alpha, my_plan.N)); NFFT(free)(swap_dgt); fgt_finalize(&my_plan); } /** * Compares accuracy and execution time of the fast Gauss transform with * increasing expansion degree. * Similar to the test in F. Andersson and G. Beylkin. * The fast Gauss transform with complex parameters. * J. Comput. Physics 203 (2005) 274-286 * * \author Stefan Kunis */ static void fgt_test_andersson(void) { fgt_plan my_plan; NFFT_C *swap_dgt; int N; NFFT_C sigma = NFFT_K(4.0) * (NFFT_K(138.0) + _Complex_I * NFFT_K(100.0)); int n = 128; int N_dgt_pre_exp = (int) (1U << 11); int N_dgt = (int) (1U << 19); printf("n=%d, sigma=%1.3" NFFT__FES__ "+i%1.3" NFFT__FES__ "\n", n, NFFT_M(creal)(sigma), NFFT_M(cimag)(sigma)); for (N = ((NFFT_INT) (1U << 6)); N < ((NFFT_INT) (1U << 22)); N = N << 1) { printf("$%d$\t & ", N); fgt_init_guru(&my_plan, N, N, sigma, n, 1, 7, N < N_dgt_pre_exp ? DGT_PRE_CEXP : 0); swap_dgt = (NFFT_C*) NFFT(malloc)((size_t)(my_plan.M) * sizeof(NFFT_C)); fgt_test_init_rand(&my_plan); fgt_init_node_dependent(&my_plan); if (N < N_dgt) { NFFT_CSWAP(swap_dgt, my_plan.f); if (N < N_dgt_pre_exp) my_plan.flags ^= DGT_PRE_CEXP; printf("$%1.1" NFFT__FES__ "$\t & ", fgt_test_measure_time(&my_plan, 1)); if (N < N_dgt_pre_exp) my_plan.flags ^= DGT_PRE_CEXP; NFFT_CSWAP(swap_dgt, my_plan.f); } else printf("\t\t & "); if (N < N_dgt_pre_exp) printf("$%1.1" NFFT__FES__ "$\t & ", fgt_test_measure_time(&my_plan, 1)); else printf("\t\t & "); my_plan.flags ^= FGT_NDFT; printf("$%1.1" NFFT__FES__ "$\t & ", fgt_test_measure_time(&my_plan, 0)); my_plan.flags ^= FGT_NDFT; printf("$%1.1" NFFT__FES__ "$\t & ", fgt_test_measure_time(&my_plan, 0)); printf("$%1.1" NFFT__FES__ "$\t \\\\ \n", NFFT(error_l_infty_1_complex)(swap_dgt, my_plan.f, my_plan.M, my_plan.alpha, my_plan.N)); fflush(stdout); NFFT(free)(swap_dgt); fgt_finalize(&my_plan); FFTW(cleanup)(); } } /** * Compares accuracy of the fast Gauss transform with increasing expansion * degree. * * \author Stefan Kunis */ static void fgt_test_error(void) { fgt_plan my_plan; NFFT_C *swap_dgt; int n, mi; NFFT_C sigma = NFFT_K(4.0) * (NFFT_K(138.0) + _Complex_I * NFFT_K(100.0)); int N = 1000; int M = 1000; int m[2] = { 7, 3 }; printf("N=%d;\tM=%d;\nsigma=%1.3" NFFT__FES__ "+i*%1.3" NFFT__FES__ ";\n", N, M, NFFT_M(creal)(sigma), NFFT_M(cimag)(sigma)); printf("error=[\n"); swap_dgt = (NFFT_C*) NFFT(malloc)((size_t)(M) * sizeof(NFFT_C)); for (n = 8; n <= 128; n += 4) { printf("%d\t", n); for (mi = 0; mi < 2; mi++) { fgt_init_guru(&my_plan, N, M, sigma, n, 1, m[mi], 0); fgt_test_init_rand(&my_plan); fgt_init_node_dependent(&my_plan); NFFT_CSWAP(swap_dgt, my_plan.f); dgt_trafo(&my_plan); NFFT_CSWAP(swap_dgt, my_plan.f); fgt_trafo(&my_plan); printf("%1.3" NFFT__FES__ "\t", NFFT(error_l_infty_1_complex)(swap_dgt, my_plan.f, my_plan.M, my_plan.alpha, my_plan.N)); fflush(stdout); fgt_finalize(&my_plan); FFTW(cleanup)(); } printf("\n"); } printf("];\n"); NFFT(free)(swap_dgt); } /** * Compares accuracy of the fast Gauss transform with increasing expansion * degree and different periodisation lengths. * * \author Stefan Kunis */ static void fgt_test_error_p(void) { fgt_plan my_plan; NFFT_C *swap_dgt; int n, pi; NFFT_C sigma = NFFT_K(20.0) + NFFT_K(40.0) * _Complex_I; int N = 1000; int M = 1000; NFFT_R p[3] = {NFFT_K(1.0), NFFT_K(1.5), NFFT_K(2.0)}; printf("N=%d;\tM=%d;\nsigma=%1.3" NFFT__FES__ "+i*%1.3" NFFT__FES__ ";\n", N, M, NFFT_M(creal)(sigma), NFFT_M(cimag)(sigma)); printf("error=[\n"); swap_dgt = (NFFT_C*) NFFT(malloc)((size_t)(M) * sizeof(NFFT_C)); for (n = 8; n <= 128; n += 4) { printf("%d\t", n); for (pi = 0; pi < 3; pi++) { fgt_init_guru(&my_plan, N, M, sigma, n, p[pi], 7, 0); fgt_test_init_rand(&my_plan); fgt_init_node_dependent(&my_plan); NFFT_CSWAP(swap_dgt, my_plan.f); dgt_trafo(&my_plan); NFFT_CSWAP(swap_dgt, my_plan.f); fgt_trafo(&my_plan); printf("%1.3" NFFT__FES__ "\t", NFFT(error_l_infty_1_complex)(swap_dgt, my_plan.f, my_plan.M, my_plan.alpha, my_plan.N)); fflush(stdout); fgt_finalize(&my_plan); FFTW(cleanup)(); } printf("\n"); } printf("];\n"); } /** * Different tests of the fast Gauss transform. * * \author Stefan Kunis */ int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "fastgauss type\n"); fprintf(stderr, " type\n"); fprintf(stderr, " 0 - Simple test.\n"); fprintf(stderr, " 1 - Compares accuracy and execution time.\n"); fprintf(stderr, " Pipe to output_andersson.tex\n"); fprintf(stderr, " 2 - Compares accuracy.\n"); fprintf(stderr, " Pipe to output_error.m\n"); fprintf(stderr, " 3 - Compares accuracy.\n"); fprintf(stderr, " Pipe to output_error_p.m\n"); return EXIT_FAILURE; } if (atoi(argv[1]) == 0) fgt_test_simple(10, 10, NFFT_K(5.0) + NFFT_K(3.0) * _Complex_I, NFFT_K(0.001)); if (atoi(argv[1]) == 1) fgt_test_andersson(); if (atoi(argv[1]) == 2) fgt_test_error(); if (atoi(argv[1]) == 3) fgt_test_error_p(); return EXIT_SUCCESS; } /* \} */ nfft-3.3.2/applications/fastgauss/levelplots.m000066400000000000000000000021651300072027400215100ustar00rootroot00000000000000% Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 % Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. clear; n=128; p=1; a = 1:1500; b = -1500:1500; [A,B] = meshgrid(a,b); S = A.^2 + B.^2; Z = exp(-pi^2*A*n^2./(4*p^2*S)); ZZ = 2*exp(-A*(2*p-1)^2/4).*(1+1./p*(2*p-1)*A) + sqrt(pi./sqrt(S))/p.*exp(-pi^2*A*n^2./(4*p^2*S)).*(1 + 2*S*p^2./(n*pi^2*A)); p =-20:2:2; v = 10.^p; figure(1); [C,h]=contour(A,B,ZZ,v); clabel(C,h); figure(2); [C,h]=contour(A,B,Z,v); clabel(C,h); nfft-3.3.2/applications/fastgauss/output_error.m000066400000000000000000000053461300072027400220740ustar00rootroot00000000000000% Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 % Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. N=1000; M=1000; delta=5.520e+02+i*4.000e+02; error=[ 8 1.459e-02 1.459e-02 1.459e-02 1.748e-02 1.748e-02 1.748e-02 12 9.688e-03 9.688e-03 9.688e-03 1.212e-02 1.212e-02 1.212e-02 16 5.186e-03 5.186e-03 5.186e-03 7.868e-03 7.868e-03 7.868e-03 20 5.493e-03 5.493e-03 5.493e-03 6.925e-03 6.925e-03 6.925e-03 24 2.641e-03 2.641e-03 2.641e-03 3.190e-03 3.190e-03 3.190e-03 28 7.300e-04 7.300e-04 7.300e-04 1.181e-03 1.181e-03 1.181e-03 32 3.378e-04 3.378e-04 3.378e-04 5.849e-04 5.849e-04 5.849e-04 36 1.425e-04 1.425e-04 1.426e-04 1.829e-04 1.829e-04 1.829e-04 40 6.382e-05 6.382e-05 6.381e-05 8.337e-05 8.337e-05 8.337e-05 44 1.630e-05 1.630e-05 1.630e-05 2.820e-05 2.820e-05 2.819e-05 48 6.291e-06 6.291e-06 6.293e-06 8.636e-06 8.636e-06 8.618e-06 52 2.105e-06 2.105e-06 2.110e-06 2.701e-06 2.701e-06 2.710e-06 56 6.697e-07 6.697e-07 6.758e-07 1.062e-06 1.062e-06 1.065e-06 60 2.041e-07 2.041e-07 2.170e-07 2.543e-07 2.543e-07 2.552e-07 64 2.205e-08 2.205e-08 5.198e-08 3.413e-08 3.413e-08 6.138e-08 68 3.523e-09 3.523e-09 3.502e-08 9.928e-09 9.928e-09 3.745e-08 72 1.056e-09 1.056e-09 5.175e-08 1.489e-09 1.489e-09 5.231e-08 76 1.781e-10 1.781e-10 2.979e-08 3.771e-10 3.771e-10 2.992e-08 80 3.189e-11 3.189e-11 3.221e-08 5.446e-11 5.446e-11 3.220e-08 84 2.943e-12 2.943e-12 3.287e-08 3.739e-12 3.739e-12 3.287e-08 88 7.051e-13 7.051e-13 3.262e-08 1.039e-12 1.039e-12 3.262e-08 92 8.021e-14 8.041e-14 3.834e-08 1.675e-13 1.676e-13 3.834e-08 96 6.945e-15 7.029e-15 4.199e-08 1.540e-14 1.532e-14 4.199e-08 100 4.382e-16 7.516e-16 3.566e-08 8.655e-16 1.063e-15 3.566e-08 104 7.821e-17 4.575e-16 3.811e-08 8.676e-17 4.271e-16 3.811e-08 108 7.166e-17 5.269e-16 4.142e-08 7.515e-17 5.257e-16 4.142e-08 112 3.767e-17 4.911e-16 2.658e-08 3.993e-17 4.923e-16 2.658e-08 116 3.286e-17 2.782e-16 3.143e-08 3.264e-17 2.790e-16 3.143e-08 120 4.229e-17 4.084e-16 3.057e-08 4.211e-17 4.076e-16 3.057e-08 124 5.182e-17 3.743e-16 3.312e-08 5.084e-17 3.716e-16 3.312e-08 128 4.748e-17 3.891e-16 3.163e-08 4.748e-17 3.882e-16 3.163e-08 ]; nfft-3.3.2/applications/fastgauss/output_error_p.m000066400000000000000000000035041300072027400224050ustar00rootroot00000000000000% Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 % Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. N=1000; M=1000; delta=2.000e+01+i*4.000e+01; error=[ 8 1.451e-03 4.437e-03 9.238e-03 12 2.694e-04 1.785e-03 6.038e-03 16 2.198e-05 6.606e-04 1.779e-03 20 6.005e-05 1.084e-04 8.691e-04 24 5.849e-05 2.308e-05 2.467e-04 28 4.324e-05 2.349e-06 5.028e-05 32 6.813e-05 6.029e-08 7.187e-06 36 7.196e-05 5.159e-09 2.697e-06 40 3.732e-05 7.599e-11 9.629e-08 44 3.987e-05 1.102e-11 2.765e-08 48 6.336e-05 1.013e-11 3.984e-09 52 3.398e-05 7.971e-12 2.666e-10 56 3.791e-05 4.946e-12 1.691e-11 60 4.210e-05 1.251e-11 6.452e-13 64 5.044e-05 1.025e-11 4.226e-14 68 2.582e-05 4.764e-12 2.546e-15 72 4.118e-05 8.966e-12 1.958e-16 76 4.142e-05 8.439e-12 1.198e-16 80 6.218e-05 1.454e-11 2.520e-16 84 7.961e-05 1.330e-11 9.814e-17 88 4.900e-05 1.787e-11 1.585e-16 92 5.378e-05 1.005e-11 2.645e-16 96 2.436e-05 5.746e-12 1.541e-16 100 4.269e-05 1.186e-11 1.027e-16 104 3.258e-05 8.346e-12 1.648e-16 108 4.094e-05 1.176e-11 3.433e-16 112 6.134e-05 1.921e-11 2.092e-16 116 8.709e-05 1.517e-11 1.741e-16 120 2.122e-05 6.791e-12 3.134e-16 124 5.029e-05 5.540e-12 5.232e-16 128 3.538e-05 7.571e-12 5.073e-16 ]; nfft-3.3.2/applications/fastgauss/show_results.m000066400000000000000000000037401300072027400220600ustar00rootroot00000000000000% Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 % Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. output_error a=real(delta); C=exp(-a*pi^2/abs(delta)^2); figure(1); h=semilogy( error(:,1), error(:,2),'k-',... error(:,1), error(:,3),'k--',... error(:,1), error(:,4),'k-.',... error(:,1), 2*exp(-a/4)*(1+1/a) + sqrt(pi/abs(delta)) * exp(-pi^2*a*error(:,1).^2/(4*abs(delta)^2)).*(1+abs(delta)^2./(error(:,1)*pi^2*a)),'k:'); set(h,'LineWidth',1.8); set(h,'Markersize',10); set(gca,'FontSize',25); axis([min(error(:,1)),max(error(:,1)),10^-18,1]); print gauss1.eps -deps figure(2); h=semilogy( error(:,1), error(:,5),'k-',... error(:,1), error(:,6),'k--',... error(:,1), error(:,7),'k-.',... error(:,1), 8*abs(delta)^2./(pi^2*a*error(:,1)).*exp(-a/4).*(1+1./error(:,1)) + sqrt(pi/abs(delta)) * exp(-pi^2*a*error(:,1).^2/(4*abs(delta)^2)).*(1+2*abs(delta)^2./(error(:,1)*pi^2*a)),'k:'); set(h,'LineWidth',1.8); set(h,'Markersize',10); set(gca,'FontSize',25); axis([min(error(:,1)),max(error(:,1)),10^-18,1]); print gauss2.eps -deps output_error_p figure(3); h=semilogy( error(:,1), error(:,2),'k-',... error(:,1), error(:,3),'k--',... error(:,1), error(:,4),'k-.'); set(h,'LineWidth',1.8); set(h,'Markersize',10); set(gca,'FontSize',25); axis([min(error(:,1)),max(error(:,1)),10^-18,1]); print gauss6.eps -deps nfft-3.3.2/applications/fastsum/000077500000000000000000000000001300072027400166175ustar00rootroot00000000000000nfft-3.3.2/applications/fastsum/Makefile.am000066400000000000000000000050721300072027400206570ustar00rootroot00000000000000AM_CPPFLAGS = -I$(top_srcdir)/include if HAVE_THREADS FASTSUM_TEST_THREADS=fastsum_test_threads LIBFASTSUM_THREADS=libfastsum_threads.la else FASTSUM_TEST_THREADS= LIBFASTSUM_THREADS= endif if HAVE_THREADS if HAVE_OPENMP FASTSUM_BENCHOMP_PROGS=fastsum_benchomp fastsum_benchomp_createdataset fastsum_benchomp_detail_single fastsum_benchomp_detail_threads else FASTSUM_BENCHOMP_PROGS= endif else FASTSUM_BENCHOMP_PROGS= endif noinst_LTLIBRARIES = libfastsum.la libkernels.la $(LIBFASTSUM_THREADS) noinst_PROGRAMS = fastsum_test fastsum_matlab $(FASTSUM_TEST_THREADS) $(FASTSUM_BENCHOMP_PROGS) libfastsum_la_SOURCES = fastsum.c fastsum.h kernels.h libfastsum_la_LIBADD = @fftw3_LIBS@ libfastsum_la_LDFLAGS = @fftw3_LDFLAGS@ libkernels_la_SOURCES = kernels.c if HAVE_THREADS libfastsum_threads_la_SOURCES = fastsum.c fastsum.h kernels.h libfastsum_threads_la_LIBADD = @fftw3_threads_LIBS@ libfastsum_threads_la_LDFLAGS = @fftw3_threads_LDFLAGS@ if HAVE_OPENMP libfastsum_threads_la_CFLAGS = $(OPENMP_CFLAGS) endif endif fastsum_test_SOURCES = fastsum_test.c fastsum_test_LDADD = libfastsum.la libkernels.la $(top_builddir)/libnfft3@PREC_SUFFIX@.la fastsum_matlab_SOURCES = fastsum_matlab.c fastsum_matlab_LDADD = libfastsum.la libkernels.la $(top_builddir)/libnfft3@PREC_SUFFIX@.la if HAVE_THREADS fastsum_test_threads_SOURCES = fastsum_test.c fastsum_test_threads_LDADD = libfastsum_threads.la libkernels.la $(top_builddir)/libnfft3@PREC_SUFFIX@_threads.la if HAVE_OPENMP fastsum_test_threads_CFLAGS = $(OPENMP_CFLAGS) endif endif if HAVE_THREADS if HAVE_OPENMP fastsum_benchomp_SOURCES = fastsum_benchomp.c fastsum_benchomp_LDADD = libfastsum_threads.la libkernels.la $(top_builddir)/libnfft3@PREC_SUFFIX@_threads.la @fftw3_LDFLAGS@ @fftw3_threads_LIBS@ fastsum_benchomp_CFLAGS = $(OPENMP_CFLAGS) fastsum_benchomp_createdataset_SOURCES = fastsum_benchomp_createdataset.c fastsum_benchomp_createdataset_LDADD = libfastsum.la libkernels.la $(top_builddir)/libnfft3@PREC_SUFFIX@.la @fftw3_LDFLAGS@ @fftw3_LIBS@ fastsum_benchomp_detail_single_SOURCES = fastsum_benchomp_detail.c fastsum_benchomp_detail_single_LDADD = libfastsum.la libkernels.la $(top_builddir)/libnfft3@PREC_SUFFIX@.la @fftw3_LDFLAGS@ @fftw3_LIBS@ fastsum_benchomp_detail_threads_SOURCES = fastsum_benchomp_detail.c fastsum_benchomp_detail_threads_LDADD = libfastsum_threads.la libkernels.la $(top_builddir)/libnfft3@PREC_SUFFIX@_threads.la @fftw3_LDFLAGS@ @fftw3_threads_LIBS@ fastsum_benchomp_detail_threads_CFLAGS = $(OPENMP_CFLAGS) endif endif EXTRA_DIST = fastsum.m fastsum_test.m README nfft-3.3.2/applications/fastsum/README000066400000000000000000000031201300072027400174730ustar00rootroot00000000000000fastsum - fast NFFT-based summation This library of C functions computes approximations of sums of the form N - f(y ) = > alpha K(y - x ) (j=1,...,M) j - k j k k=1 where x_k, y_j are arbitrary nodes in [-1/4+eps_B/2, 1/4-eps_B/2]^d, alpha_k are complex coefficients and K: R^d -> C is a kernel function which is C^oo except of the origin. Such kernels include log|x| and 1/|x|^b (b \in N) or the parameter dependent Hardy's multiquadric (x^2+c^2)^(1/2) and generalized multiquadrics (x^2+c^2)^(-b/2) (b \in N). It is based on the fast Fourier transform for nonequispaced nodes (NFFT) and therefore depends on the NFFT C-library. New kernels are easily incorporated by defining an appropriate C-function (see kernels.c for some examples). fastsum_test.c is an example for the usage of the library. The MATLAB script file fastsum_test.m calls the MATLAB function fastsum.m, which is a simple example for the usage in MATLAB. References: [1] D. Potts, and G. Steidl. Fast summation at nonequispaced knots by NFFTs. SIAM J. Sci. Comput., 24:2013-2037, 2003. [2] D. Potts, G. Steidl, and A. Nieslony. Fast convolution with radial kernels at nonequispaced knots. Numer. Math., 98:329-351, 2004. [3] M. Fenn, and G. Steidl. Fast NFFT-based summation of radial functions. Sampl. Theory Signal Image Process., 3:1-28, 2004. [4] M. Fenn, and D. Potts. Fast summation based on fast trigonometric transforms at non-equispaced nodes. Numer. Linear Algebra. Appl., 12:161-169, 2005. nfft-3.3.2/applications/fastsum/fastsum.c000066400000000000000000000730741300072027400204600ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /*! \file fastsum.c * \brief Fast NFFT-based summation algorithm. * * \author Markus Fenn * \date 2003-2006 */ #include "config.h" #include #include #ifdef HAVE_COMPLEX_H #include #endif #include "nfft3.h" #include "fastsum.h" #include "infft.h" // Required for test if (ths->k == one_over_x) #include "kernels.h" /** * \addtogroup applications_fastsum * \{ */ /** max */ static int max_i(int a, int b) { return a >= b ? a : b; } /** factorial */ static R fak(int n) { if (n <= 1) return K(1.0); else return (R)(n) * fak(n - 1); } /** binomial coefficient */ static R binom(int n, int m) { return fak(n) / fak(m) / fak(n - m); } /** basis polynomial for regularized kernel */ static R BasisPoly(int m, int r, R xx) { int k; R sum = K(0.0); for (k = 0; k <= m - r; k++) { sum += binom(m + k, k) * POW((xx + K(1.0)) / K(2.0), (R) k); } return sum * POW((xx + K(1.0)), (R) r) * POW(K(1.0) - xx, (R) (m + 1)) / (R)(1 << (m + 1)) / fak(r); /* 1<<(m+1) = 2^(m+1) */ } /** regularized kernel with K_I arbitrary and K_B smooth to zero */ C regkern(kernel k, R xx, int p, const R *param, R a, R b) { int r; C sum = K(0.0); if (xx < -K(0.5)) xx = -K(0.5); if (xx > K(0.5)) xx = K(0.5); if ((xx >= -K(0.5) + b && xx <= -a) || (xx >= a && xx <= K(0.5) - b)) { return k(xx, 0, param); } else if (xx < -K(0.5) + b) { sum = (k(-K(0.5), 0, param) + k(K(0.5), 0, param)) / K(2.0) * BasisPoly(p - 1, 0, K(2.0) * xx / b + (K(1.0) - b) / b); for (r = 0; r < p; r++) { sum += POW(-b / K(2.0), (R) r) * k(-K(0.5) + b, r, param) * BasisPoly(p - 1, r, -K(2.0) * xx / b + (b - K(1.0)) / b); } return sum; } else if ((xx > -a) && (xx < a)) { for (r = 0; r < p; r++) { sum += POW(a, (R) r) * (k(-a, r, param) * BasisPoly(p - 1, r, xx / a) + k(a, r, param) * BasisPoly(p - 1, r, -xx / a) * (r & 1 ? -1 : 1)); } return sum; } else if (xx > K(0.5) - b) { sum = (k(-K(0.5), 0, param) + k(K(0.5), 0, param)) / K(2.0) * BasisPoly(p - 1, 0, -K(2.0) * xx / b + (K(1.0) - b) / b); for (r = 0; r < p; r++) { sum += POW(b / K(2.0), (R) r) * k(K(0.5) - b, r, param) * BasisPoly(p - 1, r, K(2.0) * xx / b - (K(1.0) - b) / b); } return sum; } return k(xx, 0, param); } /** regularized kernel with K_I arbitrary and K_B periodized * (used in 1D) */ static C regkern1(kernel k, R xx, int p, const R *param, R a, R b) { int r; C sum = K(0.0); if (xx < -K(0.5)) xx = -K(0.5); if (xx > K(0.5)) xx = K(0.5); if ((xx >= -K(0.5) + b && xx <= -a) || (xx >= a && xx <= K(0.5) - b)) { return k(xx, 0, param); } else if ((xx > -a) && (xx < a)) { for (r = 0; r < p; r++) { sum += POW(a, (R) r) * (k(-a, r, param) * BasisPoly(p - 1, r, xx / a) + k(a, r, param) * BasisPoly(p - 1, r, -xx / a) * (r & 1 ? -1 : 1)); } return sum; } else if (xx < -K(0.5) + b) { for (r = 0; r < p; r++) { sum += POW(b, (R) r) * (k(K(0.5) - b, r, param) * BasisPoly(p - 1, r, (xx + K(0.5)) / b) + k(-K(0.5) + b, r, param) * BasisPoly(p - 1, r, -(xx + K(0.5)) / b) * (r & 1 ? -1 : 1)); } return sum; } else if (xx > K(0.5) - b) { for (r = 0; r < p; r++) { sum += POW(b, (R) r) * (k(K(0.5) - b, r, param) * BasisPoly(p - 1, r, (xx - K(0.5)) / b) + k(-K(0.5) + b, r, param) * BasisPoly(p - 1, r, -(xx - K(0.5)) / b) * (r & 1 ? -1 : 1)); } return sum; } return k(xx, 0, param); } /** regularized kernel for even kernels with K_I even and K_B mirrored */ //static C regkern2(kernel k, R xx, int p, const R *param, R a, R b) //{ // int r; // C sum = K(0.0); // // xx = FABS(xx); // // if (xx > K(0.5)) // { // for (r = 0; r < p; r++) // { // sum += POW(b, (R) r) * k(K(0.5) - b, r, param) // * (BasisPoly(p - 1, r, 0) + BasisPoly(p - 1, r, 0)); // } // return sum; // } // else if ((a <= xx) && (xx <= K(0.5) - b)) // { // return k(xx, 0, param); // } // else if (xx < a) // { // for (r = 0; r < p; r++) // { // sum += POW(-a, (R) r) * k(a, r, param) // * (BasisPoly(p - 1, r, xx / a) + BasisPoly(p - 1, r, -xx / a)); // } // return sum; // } // else if ((K(0.5) - b < xx) && (xx <= K(0.5))) // { // for (r = 0; r < p; r++) // { // sum += POW(b, (R) r) * k(K(0.5) - b, r, param) // * (BasisPoly(p - 1, r, (xx - K(0.5)) / b) // + BasisPoly(p - 1, r, -(xx - K(0.5)) / b)); // } // return sum; // } // return K(0.0); //} /** regularized kernel for even kernels with K_I even * and K_B mirrored smooth to K(1/2) (used in dD, d>1) */ static C regkern3(kernel k, R xx, int p, const R *param, R a, R b) { int r; C sum = K(0.0); xx = FABS(xx); if (xx >= K(0.5)) { /*return kern(typ,c,0,K(0.5));*/ xx = K(0.5); } /* else */ if ((a <= xx) && (xx <= K(0.5) - b)) { return k(xx, 0, param); } else if (xx < a) { for (r = 0; r < p; r++) { sum += POW(-a, (R) r) * k(a, r, param) * (BasisPoly(p - 1, r, xx / a) + BasisPoly(p - 1, r, -xx / a)); } /*sum=kern(typ,c,0,xx); */ return sum; } else if ((K(0.5) - b < xx) && (xx <= K(0.5))) { sum = k(K(0.5), 0, param) * BasisPoly(p - 1, 0, -K(2.0) * xx / b + (K(1.0) - b) / b); /* sum=regkern2(typ,c,p,a,b, K(0.5))*BasisPoly(p-1,0,-K(2.0)*xx/b+(K(1.0)-b)/b); */ for (r = 0; r < p; r++) { sum += POW(b / K(2.0), (R) r) * k(K(0.5) - b, r, param) * BasisPoly(p - 1, r, K(2.0) * xx / b - (K(1.0) - b) / b); } return sum; } return K(0.0); } /** linear spline interpolation in near field with even kernels */ //static C linintkern(const R x, const C *Add, const int Ad, const R a) //{ // R c, c1, c3; // int r; // C f1, f2; // // c = x * Ad / a; // r = (int)(LRINT(c)); // r = abs(r); // f1 = Add[r]; // f2 = Add[r + 1]; // c = FABS(c); // c1 = c - r; // c3 = c1 - K(1.0); // return (-f1 * c3 + f2 * c1); //} // //static C quadrintkern(const R x, const C *Add, const int Ad, const R a) //{ // R c, c1, c2, c3; // int r; // C f0, f1, f2; // // c = x * Ad / a; // r = (int)(LRINT(c)); // r = abs(r); // if (r == 0) // { // f0 = Add[r + 1]; // f1 = Add[r]; // f2 = Add[r + 1]; // } // else // { // f0 = Add[r - 1]; // f1 = Add[r]; // f2 = Add[r + 1]; // } // c = FABS(c); // c1 = c - r; // c2 = c1 + K(1.0); // c3 = c1 - K(1.0); // return (f0 * c1 * c3 / K(2.0) - f1 * c2 * c3 + f2 * c2 * c1 / K(2.0)); //} /** cubic spline interpolation in near field with even kernels */ C kubintkern(const R x, const C *Add, const int Ad, const R a) { R c, c1, c2, c3, c4; int r; C f0, f1, f2, f3; c = x * (R)(Ad) / a; r = (int)(LRINT(c)); r = abs(r); if (r == 0) { f0 = Add[r + 1]; f1 = Add[r]; f2 = Add[r + 1]; f3 = Add[r + 2]; } else { f0 = Add[r - 1]; f1 = Add[r]; f2 = Add[r + 1]; f3 = Add[r + 2]; } c = FABS(c); c1 = c - (R)(r); c2 = c1 + K(1.0); c3 = c1 - K(1.0); c4 = c1 - K(2.0); /* return(-f0*(c-r)*(c-r-K(1.0))*(c-r-K(2.0))/K(6.0)+f1*(c-r+K(1.0))*(c-r-K(1.0))*(c-r-K(2.0))/2- f2*(c-r+K(1.0))*(c-r)*(c-r-K(2.0))/2+f3*(c-r+K(1.0))*(c-r)*(c-r-K(1.0))/K(6.0)); */ return (-f0 * c1 * c3 * c4 / K(6.0) + f1 * c2 * c3 * c4 / K(2.0) - f2 * c2 * c1 * c4 / K(2.0) + f3 * c2 * c1 * c3 / K(6.0)); } /** cubic spline interpolation in near field with arbitrary kernels */ static C kubintkern1(const R x, const C *Add, const int Ad, const R a) { R c, c1, c2, c3, c4; int r; C f0, f1, f2, f3; Add += 2; c = (x + a) * (R)(Ad) / K(2.0) / a; r = (int)(LRINT(c)); r = abs(r); /*if (r==0) {f0=Add[r];f1=Add[r];f2=Add[r+1];f3=Add[r+2];} else */ { f0 = Add[r - 1]; f1 = Add[r]; f2 = Add[r + 1]; f3 = Add[r + 2]; } c = FABS(c); c1 = c - (R)(r); c2 = c1 + K(1.0); c3 = c1 - K(1.0); c4 = c1 - K(2.0); /* return(-f0*(c-r)*(c-r-K(1.0))*(c-r-K(2.0))/K(6.0)+f1*(c-r+K(1.0))*(c-r-K(1.0))*(c-r-K(2.0))/2- f2*(c-r+K(1.0))*(c-r)*(c-r-K(2.0))/2+f3*(c-r+K(1.0))*(c-r)*(c-r-K(1.0))/K(6.0)); */ return (-f0 * c1 * c3 * c4 / K(6.0) + f1 * c2 * c3 * c4 / K(2.0) - f2 * c2 * c1 * c4 / K(2.0) + f3 * c2 * c1 * c3 / K(6.0)); } /** quicksort algorithm for source knots and associated coefficients */ static void quicksort(int d, int t, R *x, C *alpha, int N) { int lpos = 0; int rpos = N - 1; /*R pivot=x[((N-1)/2)*d+t];*/ R pivot = x[(N / 2) * d + t]; int k; R temp1; C temp2; while (lpos <= rpos) { while (x[lpos * d + t] < pivot) lpos++; while (x[rpos * d + t] > pivot) rpos--; if (lpos <= rpos) { for (k = 0; k < d; k++) { temp1 = x[lpos * d + k]; x[lpos * d + k] = x[rpos * d + k]; x[rpos * d + k] = temp1; } temp2 = alpha[lpos]; alpha[lpos] = alpha[rpos]; alpha[rpos] = temp2; lpos++; rpos--; } } if (0 < rpos) quicksort(d, t, x, alpha, rpos + 1); if (lpos < N - 1) quicksort(d, t, x + lpos * d, alpha + lpos, N - lpos); } /** initialize box-based search data structures */ static void BuildBox(fastsum_plan *ths) { int t, l; int *box_index; R val[ths->d]; box_index = (int *) NFFT(malloc)((size_t)(ths->box_count) * sizeof(int)); for (t = 0; t < ths->box_count; t++) box_index[t] = 0; for (l = 0; l < ths->N_total; l++) { int ind = 0; for (t = 0; t < ths->d; t++) { val[t] = ths->x[ths->d * l + t] + K(0.25) - ths->eps_B / K(2.0); ind *= ths->box_count_per_dim; ind += (int) (val[t] / ths->eps_I); } box_index[ind]++; } ths->box_offset[0] = 0; for (t = 1; t <= ths->box_count; t++) { ths->box_offset[t] = ths->box_offset[t - 1] + box_index[t - 1]; box_index[t - 1] = ths->box_offset[t - 1]; } for (l = 0; l < ths->N_total; l++) { int ind = 0; for (t = 0; t < ths->d; t++) { val[t] = ths->x[ths->d * l + t] + K(0.25) - ths->eps_B / K(2.0); ind *= ths->box_count_per_dim; ind += (int) (val[t] / ths->eps_I); } ths->box_alpha[box_index[ind]] = ths->alpha[l]; for (t = 0; t < ths->d; t++) { ths->box_x[ths->d * box_index[ind] + t] = ths->x[ths->d * l + t]; } box_index[ind]++; } NFFT(free)(box_index); } /** inner computation function for box-based near field correction */ static inline C calc_SearchBox(int d, R *y, R *x, C *alpha, int start, int end_lt, const C *Add, const int Ad, int p, R a, const kernel k, const R *param, const unsigned flags) { C result = K(0.0); int m, l; R r; for (m = start; m < end_lt; m++) { if (d == 1) { r = y[0] - x[m]; } else { r = K(0.0); for (l = 0; l < d; l++) r += (y[l] - x[m * d + l]) * (y[l] - x[m * d + l]); r = SQRT(r); } if (FABS(r) < a) { result += alpha[m] * k(r, 0, param); /* alpha*(kern-regkern) */ if (d == 1) { if (flags & EXACT_NEARFIELD) result -= alpha[m] * regkern1(k, r, p, param, a, K(1.0) / K(16.0)); /* exact value (in 1D) */ else result -= alpha[m] * kubintkern1(r, Add, Ad, a); /* spline approximation */ } else { if (flags & EXACT_NEARFIELD) result -= alpha[m] * regkern(k, r, p, param, a, K(1.0) / K(16.0)); /* exact value (in dD) */ else #if defined(NF_KUB) result -= alpha[m] * kubintkern(r, Add, Ad, a); /* spline approximation */ #elif defined(NF_QUADR) result -= alpha[m]*quadrintkern(r,Add,Ad,a); /* spline approximation */ #elif defined(NF_LIN) result -= alpha[m]*linintkern(r,Add,Ad,a); /* spline approximation */ #else #error define interpolation method #endif } } } return result; } /** box-based near field correction */ static C SearchBox(R *y, fastsum_plan *ths) { C val = K(0.0); int t; int y_multiind[ths->d]; int multiindex[ths->d]; int y_ind; for (t = 0; t < ths->d; t++) { y_multiind[t] = (int)(LRINT((y[t] + K(0.25) - ths->eps_B / K(2.0)) / ths->eps_I)); } if (ths->d == 1) { for (y_ind = max_i(0, y_multiind[0] - 1); y_ind < ths->box_count_per_dim && y_ind <= y_multiind[0] + 1; y_ind++) { val += calc_SearchBox(ths->d, y, ths->box_x, ths->box_alpha, ths->box_offset[y_ind], ths->box_offset[y_ind + 1], ths->Add, ths->Ad, ths->p, ths->eps_I, ths->k, ths->kernel_param, ths->flags); } } else if (ths->d == 2) { for (multiindex[0] = max_i(0, y_multiind[0] - 1); multiindex[0] < ths->box_count_per_dim && multiindex[0] <= y_multiind[0] + 1; multiindex[0]++) for (multiindex[1] = max_i(0, y_multiind[1] - 1); multiindex[1] < ths->box_count_per_dim && multiindex[1] <= y_multiind[1] + 1; multiindex[1]++) { y_ind = (ths->box_count_per_dim * multiindex[0]) + multiindex[1]; val += calc_SearchBox(ths->d, y, ths->box_x, ths->box_alpha, ths->box_offset[y_ind], ths->box_offset[y_ind + 1], ths->Add, ths->Ad, ths->p, ths->eps_I, ths->k, ths->kernel_param, ths->flags); } } else if (ths->d == 3) { for (multiindex[0] = max_i(0, y_multiind[0] - 1); multiindex[0] < ths->box_count_per_dim && multiindex[0] <= y_multiind[0] + 1; multiindex[0]++) for (multiindex[1] = max_i(0, y_multiind[1] - 1); multiindex[1] < ths->box_count_per_dim && multiindex[1] <= y_multiind[1] + 1; multiindex[1]++) for (multiindex[2] = max_i(0, y_multiind[2] - 1); multiindex[2] < ths->box_count_per_dim && multiindex[2] <= y_multiind[2] + 1; multiindex[2]++) { y_ind = ((ths->box_count_per_dim * multiindex[0]) + multiindex[1]) * ths->box_count_per_dim + multiindex[2]; val += calc_SearchBox(ths->d, y, ths->box_x, ths->box_alpha, ths->box_offset[y_ind], ths->box_offset[y_ind + 1], ths->Add, ths->Ad, ths->p, ths->eps_I, ths->k, ths->kernel_param, ths->flags); } } else { exit(EXIT_FAILURE); } return val; } /** recursive sort of source knots dimension by dimension to get tree structure */ static void BuildTree(int d, int t, R *x, C *alpha, int N) { if (N > 1) { int m = N / 2; quicksort(d, t, x, alpha, N); BuildTree(d, (t + 1) % d, x, alpha, m); BuildTree(d, (t + 1) % d, x + (m + 1) * d, alpha + (m + 1), N - m - 1); } } /** fast search in tree of source knots for near field computation*/ static C SearchTree(const int d, const int t, const R *x, const C *alpha, const R *xmin, const R *xmax, const int N, const kernel k, const R *param, const int Ad, const C *Add, const int p, const unsigned flags) { if (N == 0) { return K(0.0); } else { int m = N / 2; R Min = xmin[t]; R Max = xmax[t]; R Median = x[m * d + t]; R a = FABS(Max - Min) / 2; int l; int E = 0; R r; if (Min > Median) return SearchTree(d, (t + 1) % d, x + (m + 1) * d, alpha + (m + 1), xmin, xmax, N - m - 1, k, param, Ad, Add, p, flags); else if (Max < Median) return SearchTree(d, (t + 1) % d, x, alpha, xmin, xmax, m, k, param, Ad, Add, p, flags); else { C result = K(0.0); E = 0; for (l = 0; l < d; l++) { if (x[m * d + l] > xmin[l] && x[m * d + l] < xmax[l]) E++; } if (E == d) { if (d == 1) { r = xmin[0] + a - x[m]; /* remember: xmin+a = y */ } else { r = K(0.0); for (l = 0; l < d; l++) r += (xmin[l] + a - x[m * d + l]) * (xmin[l] + a - x[m * d + l]); /* remember: xmin+a = y */ r = SQRT(r); } if (FABS(r) < a) { result += alpha[m] * k(r, 0, param); /* alpha*(kern-regkern) */ if (d == 1) { if (flags & EXACT_NEARFIELD) result -= alpha[m] * regkern1(k, r, p, param, a, K(1.0) / K(16.0)); /* exact value (in 1D) */ else result -= alpha[m] * kubintkern1(r, Add, Ad, a); /* spline approximation */ } else { if (flags & EXACT_NEARFIELD) result -= alpha[m] * regkern(k, r, p, param, a, K(1.0) / K(16.0)); /* exact value (in dD) */ else #if defined(NF_KUB) result -= alpha[m] * kubintkern(r, Add, Ad, a); /* spline approximation */ #elif defined(NF_QUADR) result -= alpha[m]*quadrintkern(r,Add,Ad,a); /* spline approximation */ #elif defined(NF_LIN) result -= alpha[m]*linintkern(r,Add,Ad,a); /* spline approximation */ #else #error define interpolation method #endif } } } result += SearchTree(d, (t + 1) % d, x + (m + 1) * d, alpha + (m + 1), xmin, xmax, N - m - 1, k, param, Ad, Add, p, flags) + SearchTree(d, (t + 1) % d, x, alpha, xmin, xmax, m, k, param, Ad, Add, p, flags); return result; } } } /** initialization of fastsum plan */ void fastsum_init_guru(fastsum_plan *ths, int d, int N_total, int M_total, kernel k, R *param, unsigned flags, int nn, int m, int p, R eps_I, R eps_B) { int t; int N[d], n[d]; int n_total; unsigned sort_flags_trafo = 0U; unsigned sort_flags_adjoint = 0U; #ifdef _OPENMP int nthreads = NFFT(get_num_threads)(); #endif if (d > 1) { sort_flags_trafo = NFFT_SORT_NODES; #ifdef _OPENMP sort_flags_adjoint = NFFT_SORT_NODES | NFFT_OMP_BLOCKWISE_ADJOINT; #else sort_flags_adjoint = NFFT_SORT_NODES; #endif } ths->d = d; ths->N_total = N_total; ths->M_total = M_total; ths->x = (R *) NFFT(malloc)((size_t)(d * N_total) * (sizeof(R))); ths->alpha = (C *) NFFT(malloc)((size_t)(N_total) * (sizeof(C))); ths->y = (R *) NFFT(malloc)((size_t)(d * M_total) * (sizeof(R))); ths->f = (C *) NFFT(malloc)((size_t)(M_total) * (sizeof(C))); ths->k = k; ths->kernel_param = param; ths->flags = flags; ths->p = p; ths->eps_I = eps_I; /* =(R)ths->p/(R)nn; *//** inner boundary */ ths->eps_B = eps_B; /* =K(1.0)/K(16.0); *//** outer boundary */ /** init spline for near field computation */ if (!(ths->flags & EXACT_NEARFIELD)) { if (ths->d == 1) { ths->Ad = 4 * (ths->p) * (ths->p); ths->Add = (C *) NFFT(malloc)((size_t)(ths->Ad + 5) * (sizeof(C))); } else { if (ths->k == one_over_x) { R delta = K(1e-8); switch (p) { case 2: delta = K(1e-3); break; case 3: delta = K(1e-4); break; case 4: delta = K(1e-5); break; case 5: delta = K(1e-6); break; case 6: delta = K(1e-6); break; case 7: delta = K(1e-7); break; default: delta = K(1e-8); } #if defined(NF_KUB) ths->Ad = max_i(10, (int)(LRINT(CEIL(K(1.4) / POW(delta, K(1.0) / K(4.0)))))); ths->Add = (C *) NFFT(malloc)((size_t)(ths->Ad + 3) * (sizeof(C))); #elif defined(NF_QUADR) ths->Ad = (int)(LRINT(CEIL(K(2.2)/POW(delta,K(1.0)/K(3.0))))); ths->Add = (C *)NFFT(malloc)((size_t)(ths->Ad+3)*(sizeof(C))); #elif defined(NF_LIN) ths->Ad = (int)(LRINT(CEIL(K(1.7)/pow(delta,K(1.0)/K(2.0))))); ths->Add = (C *)NFFT(malloc)((size_t)(ths->Ad+3)*(sizeof(C))); #else #error define NF_LIN or NF_QUADR or NF_KUB #endif } else { ths->Ad = 2 * (ths->p) * (ths->p); ths->Add = (C *) NFFT(malloc)((size_t)(ths->Ad + 3) * (sizeof(C))); } } } /** init d-dimensional NFFT plan */ ths->n = nn; for (t = 0; t < d; t++) { N[t] = nn; n[t] = 2 * nn; } NFFT(init_guru)(&(ths->mv1), d, N, N_total, n, m, sort_flags_adjoint | PRE_PHI_HUT | PRE_PSI | MALLOC_X | MALLOC_F_HAT | MALLOC_F | FFTW_INIT | FFT_OUT_OF_PLACE, FFTW_MEASURE | FFTW_DESTROY_INPUT); NFFT(init_guru)(&(ths->mv2), d, N, M_total, n, m, sort_flags_trafo | PRE_PHI_HUT | PRE_PSI | MALLOC_X | MALLOC_F_HAT | MALLOC_F | FFTW_INIT | FFT_OUT_OF_PLACE, FFTW_MEASURE | FFTW_DESTROY_INPUT); /** init d-dimensional FFTW plan */ n_total = 1; for (t = 0; t < d; t++) n_total *= nn; ths->b = (C*) NFFT(malloc)((size_t)(n_total) * sizeof(C)); #ifdef _OPENMP #pragma omp critical (nfft_omp_critical_fftw_plan) { FFTW(plan_with_nthreads)(nthreads); #endif ths->fft_plan = FFTW(plan_dft)(d, N, ths->b, ths->b, FFTW_FORWARD, FFTW_ESTIMATE); #ifdef _OPENMP } #endif if (ths->flags & NEARFIELD_BOXES) { ths->box_count_per_dim = (int)(LRINT(FLOOR((K(0.5) - ths->eps_B) / ths->eps_I))) + 1; ths->box_count = 1; for (t = 0; t < ths->d; t++) ths->box_count *= ths->box_count_per_dim; ths->box_offset = (int *) NFFT(malloc)((size_t)(ths->box_count + 1) * sizeof(int)); ths->box_alpha = (C *) NFFT(malloc)((size_t)(ths->N_total) * (sizeof(C))); ths->box_x = (R *) NFFT(malloc)((size_t)(ths->d * ths->N_total) * sizeof(R)); } } /** finalization of fastsum plan */ void fastsum_finalize(fastsum_plan *ths) { NFFT(free)(ths->x); NFFT(free)(ths->alpha); NFFT(free)(ths->y); NFFT(free)(ths->f); if (!(ths->flags & EXACT_NEARFIELD)) NFFT(free)(ths->Add); NFFT(finalize)(&(ths->mv1)); NFFT(finalize)(&(ths->mv2)); #ifdef _OPENMP #pragma omp critical (nfft_omp_critical_fftw_plan) { #endif FFTW(destroy_plan)(ths->fft_plan); #ifdef _OPENMP } #endif NFFT(free)(ths->b); if (ths->flags & NEARFIELD_BOXES) { NFFT(free)(ths->box_offset); NFFT(free)(ths->box_alpha); NFFT(free)(ths->box_x); } } /** direct computation of sums */ void fastsum_exact(fastsum_plan *ths) { int j, k; int t; R r; #ifdef _OPENMP #pragma omp parallel for default(shared) private(j,k,t,r) #endif for (j = 0; j < ths->M_total; j++) { ths->f[j] = K(0.0); for (k = 0; k < ths->N_total; k++) { if (ths->d == 1) r = ths->y[j] - ths->x[k]; else { r = K(0.0); for (t = 0; t < ths->d; t++) r += (ths->y[j * ths->d + t] - ths->x[k * ths->d + t]) * (ths->y[j * ths->d + t] - ths->x[k * ths->d + t]); r = SQRT(r); } ths->f[j] += ths->alpha[k] * ths->k(r, 0, ths->kernel_param); } } } /** precomputation for fastsum */ void fastsum_precompute(fastsum_plan *ths) { int j, k, t; int n_total; #ifdef MEASURE_TIME ticks t0, t1; #endif ths->MEASURE_TIME_t[0] = K(0.0); ths->MEASURE_TIME_t[1] = K(0.0); ths->MEASURE_TIME_t[2] = K(0.0); ths->MEASURE_TIME_t[3] = K(0.0); #ifdef MEASURE_TIME t0 = getticks(); #endif if (ths->flags & NEARFIELD_BOXES) { BuildBox(ths); } else { /** sort source knots */ BuildTree(ths->d, 0, ths->x, ths->alpha, ths->N_total); } #ifdef MEASURE_TIME t1 = getticks(); ths->MEASURE_TIME_t[3] += nfft_elapsed_seconds(t1,t0); #endif #ifdef MEASURE_TIME t0 = getticks(); #endif /** precompute spline values for near field*/ if (!(ths->flags & EXACT_NEARFIELD)) { if (ths->d == 1) #ifdef _OPENMP #pragma omp parallel for default(shared) private(k) #endif for (k = -ths->Ad / 2 - 2; k <= ths->Ad / 2 + 2; k++) ths->Add[k + ths->Ad / 2 + 2] = regkern1(ths->k, ths->eps_I * (R) k / (R)(ths->Ad) * K(2.0), ths->p, ths->kernel_param, ths->eps_I, ths->eps_B); else #ifdef _OPENMP #pragma omp parallel for default(shared) private(k) #endif for (k = 0; k <= ths->Ad + 2; k++) ths->Add[k] = regkern3(ths->k, ths->eps_I * (R) k / (R)(ths->Ad), ths->p, ths->kernel_param, ths->eps_I, ths->eps_B); } #ifdef MEASURE_TIME t1 = getticks(); ths->MEASURE_TIME_t[0] += NFFT(elapsed_seconds)(t1,t0); #endif #ifdef MEASURE_TIME t0 = getticks(); #endif /** init NFFT plan for transposed transform in first step*/ for (k = 0; k < ths->mv1.M_total; k++) for (t = 0; t < ths->mv1.d; t++) ths->mv1.x[ths->mv1.d * k + t] = -ths->x[ths->mv1.d * k + t]; /* note the factor -1 for transposed transform instead of adjoint*/ /** precompute psi, the entries of the matrix B */ if (ths->mv1.flags & PRE_LIN_PSI) NFFT(precompute_lin_psi)(&(ths->mv1)); if (ths->mv1.flags & PRE_PSI) NFFT(precompute_psi)(&(ths->mv1)); if (ths->mv1.flags & PRE_FULL_PSI) NFFT(precompute_full_psi)(&(ths->mv1)); #ifdef MEASURE_TIME t1 = getticks(); ths->MEASURE_TIME_t[1] += nfft_elapsed_seconds(t1,t0); #endif /** init Fourier coefficients */ for (k = 0; k < ths->mv1.M_total; k++) ths->mv1.f[k] = ths->alpha[k]; #ifdef MEASURE_TIME t0 = getticks(); #endif /** init NFFT plan for transform in third step*/ for (j = 0; j < ths->mv2.M_total; j++) for (t = 0; t < ths->mv2.d; t++) ths->mv2.x[ths->mv2.d * j + t] = -ths->y[ths->mv2.d * j + t]; /* note the factor -1 for conjugated transform instead of standard*/ /** precompute psi, the entries of the matrix B */ if (ths->mv2.flags & PRE_LIN_PSI) NFFT(precompute_lin_psi)(&(ths->mv2)); if (ths->mv2.flags & PRE_PSI) NFFT(precompute_psi)(&(ths->mv2)); if (ths->mv2.flags & PRE_FULL_PSI) NFFT(precompute_full_psi)(&(ths->mv2)); #ifdef MEASURE_TIME t1 = getticks(); ths->MEASURE_TIME_t[2] += NFFT(elapsed_seconds)(t1,t0); #endif #ifdef MEASURE_TIME t0 = getticks(); #endif /** precompute Fourier coefficients of regularised kernel*/ n_total = 1; for (t = 0; t < ths->d; t++) n_total *= ths->n; #ifdef _OPENMP #pragma omp parallel for default(shared) private(j,k,t) #endif for (j = 0; j < n_total; j++) { if (ths->d == 1) ths->b[j] = regkern1(ths->k, (R) j / (R)(ths->n) - K(0.5), ths->p, ths->kernel_param, ths->eps_I, ths->eps_B) / (R)(n_total); else { k = j; ths->b[j] = K(0.0); for (t = 0; t < ths->d; t++) { ths->b[j] += ((R) (k % (ths->n)) / (R)(ths->n) - K(0.5)) * ((R) (k % (ths->n)) / (R)(ths->n) - K(0.5)); k = k / (ths->n); } ths->b[j] = regkern3(ths->k, SQRT(CREAL(ths->b[j])), ths->p, ths->kernel_param, ths->eps_I, ths->eps_B) / (R)(n_total); } } NFFT(fftshift_complex)(ths->b, (int)(ths->mv1.d), ths->mv1.N); FFTW(execute)(ths->fft_plan); NFFT(fftshift_complex)(ths->b, (int)(ths->mv1.d), ths->mv1.N); #ifdef MEASURE_TIME t1 = getticks(); ths->MEASURE_TIME_t[0] += nfft_elapsed_seconds(t1,t0); #endif } /** fast NFFT-based summation */ void fastsum_trafo(fastsum_plan *ths) { int j, k, t; #ifdef MEASURE_TIME ticks t0, t1; #endif ths->MEASURE_TIME_t[4] = K(0.0); ths->MEASURE_TIME_t[5] = K(0.0); ths->MEASURE_TIME_t[6] = K(0.0); ths->MEASURE_TIME_t[7] = K(0.0); #ifdef MEASURE_TIME t0 = getticks(); #endif /** first step of algorithm */ NFFT(adjoint)(&(ths->mv1)); #ifdef MEASURE_TIME t1 = getticks(); ths->MEASURE_TIME_t[4] += NFFT(elapsed_seconds)(t1,t0); #endif #ifdef MEASURE_TIME t0 = getticks(); #endif /** second step of algorithm */ #ifdef _OPENMP #pragma omp parallel for default(shared) private(k) #endif for (k = 0; k < ths->mv2.N_total; k++) ths->mv2.f_hat[k] = ths->b[k] * ths->mv1.f_hat[k]; #ifdef MEASURE_TIME t1 = getticks(); ths->MEASURE_TIME_t[5] += nfft_elapsed_seconds(t1,t0); #endif #ifdef MEASURE_TIME t0 = getticks(); #endif /** third step of algorithm */ NFFT(trafo)(&(ths->mv2)); #ifdef MEASURE_TIME t1 = getticks(); ths->MEASURE_TIME_t[6] += nfft_elapsed_seconds(t1,t0); #endif #ifdef MEASURE_TIME t0 = getticks(); #endif /** add near field */ #ifdef _OPENMP #pragma omp parallel for default(shared) private(j,k,t) #endif for (j = 0; j < ths->M_total; j++) { R ymin[ths->d], ymax[ths->d]; /** limits for d-dimensional near field box */ if (ths->flags & NEARFIELD_BOXES) { ths->f[j] = ths->mv2.f[j] + SearchBox(ths->y + ths->d * j, ths); } else { for (t = 0; t < ths->d; t++) { ymin[t] = ths->y[ths->d * j + t] - ths->eps_I; ymax[t] = ths->y[ths->d * j + t] + ths->eps_I; } ths->f[j] = ths->mv2.f[j] + SearchTree(ths->d, 0, ths->x, ths->alpha, ymin, ymax, ths->N_total, ths->k, ths->kernel_param, ths->Ad, ths->Add, ths->p, ths->flags); } /* ths->f[j] = ths->mv2.f[j]; */ /* ths->f[j] = SearchTree(ths->d,0, ths->x, ths->alpha, ymin, ymax, ths->N_total, ths->k, ths->kernel_param, ths->Ad, ths->Add, ths->p, ths->flags); */ } #ifdef MEASURE_TIME t1 = getticks(); ths->MEASURE_TIME_t[7] += NFFT(elapsed_seconds)(t1,t0); #endif } /* \} */ /* fastsum.c */ nfft-3.3.2/applications/fastsum/fastsum.h000066400000000000000000000124011300072027400204500ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /*! \file fastsum.h * \brief Header file for the fast NFFT-based summation algorithm. * * reference: M. Fenn, G. Steidl, * Fast NFFT based summation of radial functions. * Sampl. Theory Signal Image Process., 3, 1-28, 2004. * * \author Markus Fenn * \date 2003-2006 */ /** * \defgroup applications_fastsum Fast summation * \ingroup applications * \{ */ #ifndef fastsum_h_inc #define fastsum_h_inc #include "config.h" /** Include header for C99 complex datatype. */ #ifdef HAVE_COMPLEX_H #include #endif /** Include header for utils from NFFT3 library. */ /** Include header for NFFT3 library. */ #include "nfft3.h" #include "infft.h" #undef X #define X(name) NFFT(name) #if !(defined(NF_LIN) || defined(NF_QUADR) || defined(NF_KUB)) #define NF_KUB #endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ typedef C (*kernel)(R , int , const R *); /** * Constant symbols */ #define EXACT_NEARFIELD (1U<< 0) #define NEARFIELD_BOXES (1U<< 1) /** plan for fast summation algorithm */ typedef struct fastsum_plan_ { /** api */ int d; /**< number of dimensions */ int N_total; /**< number of source knots */ int M_total; /**< number of target knots */ C *alpha; /**< source coefficients */ C *f; /**< target evaluations */ R *x; /**< source knots in d-ball with radius 1/4-eps_b/2 */ R *y; /**< target knots in d-ball with radius 1/4-eps_b/2 */ kernel k; /**< kernel function */ R *kernel_param; /**< parameters for kernel function */ unsigned flags; /**< flags precomp. and approx.type */ /** internal */ /** DS_PRE - direct summation */ C *pre_K; /**< precomputed K(x_j-y_l) */ /** FS__ - fast summation */ int n; /**< expansion degree */ C *b; /**< expansion coefficients */ int p; /**< degree of smoothness of regularization */ R eps_I; /**< inner boundary */ /* fixed to p/n so far */ R eps_B; /**< outer boundary */ /* fixed to 1/16 so far */ X(plan) mv1; /**< source nfft plan */ X(plan) mv2; /**< target nfft plan */ /** near field */ int Ad; /**< number of spline knots for nearfield computation of regularized kernel */ C *Add; /**< spline values */ /* things for computing *b - are they used only once?? */ FFTW(plan) fft_plan; int box_count; int box_count_per_dim; int *box_offset; R *box_x; C *box_alpha; R MEASURE_TIME_t[8]; /**< Measured time for each step if MEASURE_TIME is set */ } fastsum_plan; /** initialize fast summation plan * * \param ths The pointer to a fastsum plan. * \param d The dimension of the problem. * \param N_total The number of source knots x. * \param M_total The number of target knots y. * \param kernel The kernel function. * \param param The parameters for the kernel function. * \param flags Fastsum flags. * \param nn The expansion degree. * \param m The cut-off parameter for the NFFT. * \param p The degree of smoothness. * \param eps_I The inner boundary. * \param eps_B the outer boundary. * */ void fastsum_init_guru(fastsum_plan *ths, int d, int N_total, int M_total, kernel k, R *param, unsigned flags, int nn, int m, int p, R eps_I, R eps_B); /** finalize plan * * \param ths The pointer to a fastsum plan. */ void fastsum_finalize(fastsum_plan *ths); /** direct summation * * \param ths The pointer to a fastsum plan. */ void fastsum_exact(fastsum_plan *ths); /** sort source nodes, precompute Fourier coefficients, etc. * * \param ths The pointer to a fastsum plan. */ void fastsum_precompute(fastsum_plan *ths); /** fast NFFT-based summation algorithm * * \param ths The pointer to a fastsum plan. */ void fastsum_trafo(fastsum_plan *ths); /* \} */ C regkern(kernel k, R xx, int p, const R *param, R a, R b); /** cubic spline interpolation in near field with even kernels */ C kubintkern(const R x, const C *Add, const int Ad, const R a); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* fastsum.h */ nfft-3.3.2/applications/fastsum/fastsum.m000066400000000000000000000046211300072027400204620ustar00rootroot00000000000000% Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 % Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. function [f,f_direct]=fastsum(x,alpha,y,kernel,c,m,n,p,eps_I,eps_B) % f=fastsum(x,alpha,y,kernel,c,m,n,p) % % Computes the sums % % f(y_j) = sum_{k=1}^N alpha_k kernel(x_k-y_j) (j=1:M) % % by calling C-program with the fast NFFT-based algorithm. % % size(f) = [N,1] (complex) % size(x) = [N,d] % size(alpha) = [N,1] (complex) % size(y)=[M,d] % kernel = 'multiquadric', etc. (see options below) % c kernel parameter % m cut-off parameter for NFFT % n expansion degree % p smoothness % % Kernel functions: % 'gaussian' K(x) = EXP(-x^2/c^2) % 'multiquadric' K(x) = SQRT(x^2+c^2) % 'inverse_multiquadric' K(x) = 1/SQRT(x^2+c^2) % 'logarithm' K(x) = LOG |x| % 'thinplate_spline' K(x) = x^2 LOG |x| % 'one_over_square' K(x) = 1/x^2 % 'one_over_modulus' K(x) = 1/|x| % 'one_over_x' K(x) = 1/x % 'inverse_multiquadric3' K(x) = 1/SQRT(x^2+c^2)^3 % 'sinc_kernel' K(x) = SIN(cx)/x % 'cosc' K(x) = COS(cx)/x % 'cot' K(x) = cot(cx) % 'one_over_cube' K(x) = 1/x^3 % % Markus Fenn, 2006. [N,d]=size(x); [M,d]=size(y); %write input to file save -ascii -double x.dat x alpha2=[real(alpha) imag(alpha)]; save -ascii -double alpha.dat alpha2 save -ascii -double y.dat y %execute C-program for fast summation if ispc cmd='fastsum_matlab.exe'; else cmd='./fastsum_matlab'; end system(sprintf('%s %d %d %d %d %d %d %s %e %e %e',cmd,d,N,M,n,m,p,kernel,c,eps_I,eps_B)); %read result from file f2=load('f.dat'); f=f2(:,1)+i*f2(:,2); f2=load('f_direct.dat'); f_direct=f2(:,1)+i*f2(:,2); nfft-3.3.2/applications/fastsum/fastsum_benchomp.c000066400000000000000000000526231300072027400223300ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include "config.h" #include "nfft3.h" #include "infft.h" #define NREPEAT 5 #if defined(_WIN32) || defined(_WIN64) const char *CMD_CREATEDATASET = "fastsum_benchomp_createdataset.exe"; const char *CMD_DETAIL_SINGLE = "fastsum_benchomp_detail_single.exe"; const char *CMD_DETAIL_THREADS = "fastsum_benchomp_detail_threads.exe"; #else const char *CMD_CREATEDATASET = "./fastsum_benchomp_createdataset"; const char *CMD_DETAIL_SINGLE = "./fastsum_benchomp_detail_single"; const char *CMD_DETAIL_THREADS = "./fastsum_benchomp_detail_threads"; #endif static FILE* file_out_tex = NULL; int get_nthreads_array(int **arr) { int max_threads = NFFT(get_num_threads)(); int alloc_num = 2; int k; int ret_number = 0; int max_threads_pw2 = (max_threads / 2) * 2 == max_threads ? 1 : 0; if (max_threads <= 5) { *arr = (int*) NFFT(malloc)((size_t) (max_threads) * sizeof(int)); for (k = 0; k < max_threads; k++) *(*arr + k) = k + 1; return max_threads; } for (k = 1; k <= max_threads; k *= 2, alloc_num++) ; *arr = (int*) NFFT(malloc)((size_t)(alloc_num) * sizeof(int)); for (k = 1; k <= max_threads; k *= 2) { if (k != max_threads && 2 * k > max_threads && max_threads_pw2) { *(*arr + ret_number) = max_threads / 2; ret_number++; } *(*arr + ret_number) = k; ret_number++; if (k != max_threads && 2 * k > max_threads) { *(*arr + ret_number) = max_threads; ret_number++; break; } } return ret_number; } void check_result_value(const int val, const int ok, const char *msg) { if (val != ok) { fprintf(stderr, "ERROR %s: %d not %d\n", msg, val, ok); exit(EXIT_FAILURE); } } void run_test_create(int d, int L, int M) { char cmd[1025]; snprintf(cmd, 1024, "%s %d %d %d > fastsum_benchomp_test.data", CMD_CREATEDATASET, d, L, M); fprintf(stderr, "%s\n", cmd); check_result_value(system(cmd), 0, "createdataset"); } void run_test_init_output() { FILE *f = fopen("fastsum_benchomp_test.result", "w"); if (f != NULL) fclose(f); } typedef struct { int d; int L; int M; int n; int m; int p; char *kernel_name; R c; R eps_I; R eps_B; } s_param; typedef struct { R avg; R min; R max; } s_resval; typedef struct { int nthreads; s_resval resval[16]; } s_result; typedef struct { s_param param; s_result *results; int nresults; } s_testset; void run_test(s_resval *res, int nrepeat, int n, int m, int p, char *kernel_name, R c, R eps_I, R eps_B, int nthreads) { char cmd[1025]; int r, t; for (t = 0; t < 16; t++) { res[t].avg = K(0.0); res[t].min = K(1.0) / K(0.0); res[t].max = K(0.0); } if (nthreads < 2) snprintf(cmd, 1024, "%s %d %d %d %s " __FR__ " " __FR__ " " __FR__ " < fastsum_benchomp_test.data > fastsum_benchomp_test.out", CMD_DETAIL_SINGLE, n, m, p, kernel_name, c, eps_I, eps_B); else snprintf(cmd, 1024, "%s %d %d %d %s " __FR__ " " __FR__ " " __FR__ " %d < fastsum_benchomp_test.data > fastsum_benchomp_test.out", CMD_DETAIL_THREADS, n, m, p, kernel_name, c, eps_I, eps_B, nthreads); fprintf(stderr, "%s\n", cmd); check_result_value(system(cmd), 0, cmd); for (r = 0; r < nrepeat; r++) { int retval; R v[16]; FILE *f; check_result_value(system(cmd), 0, cmd); f = fopen("fastsum_benchomp_test.out", "r"); retval = fscanf(f, "" __FR__ " " __FR__ " " __FR__ " " __FR__ " " __FR__ " " __FR__ " " __FR__ " " __FR__ " " __FR__ " " __FR__ " " __FR__ " " __FR__ " " __FR__ " " __FR__ " " __FR__ " " __FR__ "", v, v + 1, v + 2, v + 3, v + 4, v + 5, v + 6, v + 7, v + 8, v + 9, v + 10, v + 11, v + 12, v + 13, v + 14, v + 15); check_result_value(retval, 16, "read fastsum_benchomp_test.out"); fclose(f); for (t = 0; t < 16; t++) { res[t].avg += v[t]; if (res[t].min > v[t]) res[t].min = v[t]; if (res[t].max < v[t]) res[t].max = v[t]; } } for (t = 0; t < 16; t++) res[t].avg /= (R)(nrepeat); fprintf(stderr, "%d %d: ", nthreads, nrepeat); for (t = 0; t < 16; t++) fprintf(stderr, "%.3" __FES__ " %.3" __FES__ " %.3" __FES__ " | ", res[t].avg, res[t].min, res[t].max); fprintf(stderr, "\n"); } const char *get_psi_string(int flags) { if (flags & PRE_PSI) return "prepsi"; else if (flags & PRE_ONE_PSI) return "unknownPSI"; return "nopsi"; } const char *get_sort_string(int flags) { if (flags & NFFT_OMP_BLOCKWISE_ADJOINT) return ""; if (flags & NFFT_SORT_NODES) return "sorted"; return "unsorted"; } const char *get_adjoint_omp_string(int flags) { if (flags & NFFT_OMP_BLOCKWISE_ADJOINT) return "blockwise"; return ""; } #define MASK_FSUM_D (1U<<0) #define MASK_FSUM_L (1U<<1) #define MASK_FSUM_M (1U<<2) #define MASK_FSUM_MULTIBW (1U<<3) #define MASK_FSUM_WINM (1U<<4) #define MASK_FSUM_P (1U<<5) #define MASK_FSUM_KERNEL (1U<<6) #define MASK_FSUM_EPSI (1U<<7) #define MASK_FSUM_EPSB (1U<<8) unsigned int fastsum_determine_different_parameters(s_testset *testsets, int ntestsets) { int t; unsigned int mask = 0; if (ntestsets < 2) return 0; for (t = 1; t < ntestsets; t++) { if (testsets[t - 1].param.d != testsets[t].param.d) mask |= MASK_FSUM_D; if (testsets[t - 1].param.L != testsets[t].param.L) mask |= MASK_FSUM_L; if (testsets[t - 1].param.M != testsets[t].param.M) mask |= MASK_FSUM_M; if (testsets[t - 1].param.n != testsets[t].param.n) mask |= MASK_FSUM_MULTIBW; if (testsets[t - 1].param.m != testsets[t].param.m) mask |= MASK_FSUM_WINM; if (testsets[t - 1].param.p != testsets[t].param.p) mask |= MASK_FSUM_P; if (strcmp(testsets[t - 1].param.kernel_name, testsets[t].param.kernel_name) != 0) mask |= MASK_FSUM_KERNEL; if (testsets[t - 1].param.eps_I != testsets[t].param.eps_I) mask |= MASK_FSUM_EPSI; if (testsets[t - 1].param.eps_B != testsets[t].param.eps_B) mask |= MASK_FSUM_EPSB; } return mask; } void strEscapeUnderscore(char *dst, char *src, int maxlen) { int i = 0; int len; int offset = 0; while (src[i] != '\0' && len + offset < maxlen - 1) { if (src[i] == '_') len = snprintf(dst + offset, maxlen - offset, "\\_{}"); else len = snprintf(dst + offset, maxlen - offset, "%c", src[i]); offset += len; i++; } } void fastsum_get_plot_title_minus_indep(char *outstr, int maxlen, char *hostname, s_param param, unsigned int diff_mask) { unsigned int mask = ~diff_mask; int offset = 0; int len; len = snprintf(outstr, maxlen, "%s", hostname); if (len < 0 || len + offset >= maxlen - 1) return; offset += len; if (mask & MASK_FSUM_D) { len = snprintf(outstr + offset, maxlen - offset, " %dd fastsum", param.d); if (len < 0 || len + offset >= maxlen - 1) return; offset += len; } if ((mask & (MASK_FSUM_L | MASK_FSUM_M)) && param.L == param.M) { len = snprintf(outstr + offset, maxlen - offset, " L=M=%d", param.L); if (len < 0 || len + offset >= maxlen - 1) return; offset += len; } else { if (mask & MASK_FSUM_L) { len = snprintf(outstr + offset, maxlen - offset, " L=%d", param.L); if (len < 0 || len + offset >= maxlen - 1) return; offset += len; } if (mask & MASK_FSUM_M) { len = snprintf(outstr + offset, maxlen - offset, " M=%d", param.M); if (len < 0 || len + offset >= maxlen - 1) return; offset += len; } } if (mask & MASK_FSUM_MULTIBW) { len = snprintf(outstr + offset, maxlen - offset, " n=%d", param.n); if (len < 0 || len + offset >= maxlen - 1) return; offset += len; } if (mask & MASK_FSUM_WINM) { len = snprintf(outstr + offset, maxlen - offset, " m=%d", param.m); if (len < 0 || len + offset >= maxlen - 1) return; offset += len; } if (mask & MASK_FSUM_P) { len = snprintf(outstr + offset, maxlen - offset, " p=%d", param.p); if (len < 0 || len + offset >= maxlen - 1) return; offset += len; } if (mask & MASK_FSUM_KERNEL) { char tmp[maxlen]; strEscapeUnderscore(tmp, param.kernel_name, maxlen); len = snprintf(outstr + offset, maxlen - offset, " %s", tmp); if (len < 0 || len + offset >= maxlen - 1) return; offset += len; } if ((mask & (MASK_FSUM_EPSI | MASK_FSUM_EPSB)) && param.eps_I == param.eps_B) { len = snprintf(outstr + offset, maxlen - offset, " $\\varepsilon_\\mathrm{I}$=$\\varepsilon_\\mathrm{B}$=%" __FGS__ "", param.eps_I); if (len < 0 || len + offset >= maxlen - 1) return; offset += len; } else { if (mask & MASK_FSUM_EPSI) { len = snprintf(outstr + offset, maxlen - offset, " $\\varepsilon_\\mathrm{I}$=%" __FGS__ "", param.eps_I); if (len < 0 || len + offset >= maxlen - 1) return; offset += len; } if (mask & MASK_FSUM_EPSB) { len = snprintf(outstr + offset, maxlen - offset, " $\\varepsilon_\\mathrm{B}$=%" __FGS__ "", param.eps_B); if (len < 0 || len + offset >= maxlen - 1) return; offset += len; } } } void nfft_adjoint_print_output_histo_DFBRT(FILE *out, s_testset testset) { int i, size = testset.nresults; char hostname[1025]; #ifdef HAVE_GETHOSTNAME if (gethostname(hostname, 1024) != 0) #endif strncpy(hostname, "unnamed", 1024); fprintf(out, "\\begin{tikzpicture}\n"); fprintf(out, "\\begin{axis}["); fprintf(out, "width=0.9\\textwidth, height=0.6\\textwidth, "); fprintf(out, "symbolic x coords={"); for (i = 0; i < size; i++) if (i > 0) fprintf(out, ",%d", testset.results[i].nthreads); else fprintf(out, "%d", testset.results[i].nthreads); fprintf(out, "}, x tick label style={ /pgf/number format/1000 sep=}, xlabel=Number of threads, ylabel=Time in s, xtick=data, legend style={legend columns=-1}, ybar, bar width=7pt, ymajorgrids=true, yminorgrids=true, minor y tick num=1, "); fprintf(out, " title={%s %dd $\\textrm{NFFT}^\\top$ N=%d $\\sigma$=2 M=%d m=%d prepsi sorted}", hostname, testset.param.d, testset.param.n, testset.param.M, testset.param.m); fprintf(out, " ]\n"); fprintf(out, "\\addplot coordinates {"); for (i = 0; i < size; i++) fprintf(out, "(%d, %.6" __FES__ ") ", testset.results[i].nthreads, testset.results[i].resval[10].avg); fprintf(out, "};\n"); fprintf(out, "\\addplot coordinates {"); for (i = 0; i < size; i++) fprintf(out, "(%d, %.6" __FES__ ") ", testset.results[i].nthreads, testset.results[i].resval[11].avg); fprintf(out, "};\n"); fprintf(out, "\\addplot coordinates {"); for (i = 0; i < size; i++) fprintf(out, "(%d, %.6" __FES__ ") ", testset.results[i].nthreads, testset.results[i].resval[12].avg); fprintf(out, "};\n"); fprintf(out, "\\addplot coordinates {"); for (i = 0; i < size; i++) fprintf(out, "(%d, %.6" __FES__ ") ", testset.results[i].nthreads, testset.results[i].resval[1].avg); fprintf(out, "};\n"); fprintf(out, "\\addplot coordinates {"); for (i = 0; i < size; i++) fprintf(out, "(%d, %.6" __FES__ ") ", testset.results[i].nthreads, testset.results[i].resval[4].avg + testset.results[i].resval[1].avg); fprintf(out, "};\n"); fprintf(out, "\\legend{D,$\\textrm{F}^\\top$,$\\textrm{B}^\\top$,prepsi,total}\n"); fprintf(out, "\\end{axis}\n"); fprintf(out, "\\end{tikzpicture}\n"); fprintf(out, "\n\n"); fflush(out); } void nfft_trafo_print_output_histo_DFBRT(FILE *out, s_testset testset) { int i, size = testset.nresults; char hostname[1025]; #ifdef HAVE_GETHOSTNAME if (gethostname(hostname, 1024) != 0) #endif strncpy(hostname, "unnamed", 1024); fprintf(out, "\\begin{tikzpicture}\n"); fprintf(out, "\\begin{axis}["); fprintf(out, "width=0.9\\textwidth, height=0.6\\textwidth, "); fprintf(out, "symbolic x coords={"); for (i = 0; i < size; i++) if (i > 0) fprintf(out, ",%d", testset.results[i].nthreads); else fprintf(out, "%d", testset.results[i].nthreads); fprintf(out, "}, x tick label style={ /pgf/number format/1000 sep=}, xlabel=Number of threads, ylabel=Time in s, xtick=data, legend style={legend columns=-1}, ybar, bar width=7pt, ymajorgrids=true, yminorgrids=true, minor y tick num=1, "); fprintf(out, " title={%s %dd $\\textrm{NFFT}$ N=%d $\\sigma$=2 M=%d m=%d prepsi sorted}", hostname, testset.param.d, testset.param.n, testset.param.M, testset.param.m); fprintf(out, " ]\n"); fprintf(out, "\\addplot coordinates {"); for (i = 0; i < size; i++) fprintf(out, "(%d, %.6" __FES__ ") ", testset.results[i].nthreads, testset.results[i].resval[13].avg); fprintf(out, "};\n"); fprintf(out, "\\addplot coordinates {"); for (i = 0; i < size; i++) fprintf(out, "(%d, %.6" __FES__ ") ", testset.results[i].nthreads, testset.results[i].resval[14].avg); fprintf(out, "};\n"); fprintf(out, "\\addplot coordinates {"); for (i = 0; i < size; i++) fprintf(out, "(%d, %.6" __FES__ ") ", testset.results[i].nthreads, testset.results[i].resval[15].avg); fprintf(out, "};\n"); fprintf(out, "\\addplot coordinates {"); for (i = 0; i < size; i++) fprintf(out, "(%d, %.6" __FES__ ") ", testset.results[i].nthreads, testset.results[i].resval[2].avg); fprintf(out, "};\n"); fprintf(out, "\\addplot coordinates {"); for (i = 0; i < size; i++) fprintf(out, "(%d, %.6" __FES__ ") ", testset.results[i].nthreads, testset.results[i].resval[6].avg + testset.results[i].resval[2].avg); fprintf(out, "};\n"); fprintf(out, "\\legend{D,F,B,prepsi,total}\n"); fprintf(out, "\\end{axis}\n"); fprintf(out, "\\end{tikzpicture}\n"); fprintf(out, "\n\n"); fflush(out); } void fastsum_print_output_histo_PreRfNfT(FILE *out, s_testset testset) { int i, size = testset.nresults; char hostname[1025]; char plottitle[1025]; #ifdef HAVE_GETHOSTNAME if (gethostname(hostname, 1024) != 0) #endif strncpy(hostname, "unnamed", 1024); fastsum_get_plot_title_minus_indep(plottitle, 1024, hostname, testset.param, 0); fprintf(out, "\\begin{tikzpicture}\n"); fprintf(out, "\\begin{axis}["); fprintf(out, "width=0.9\\textwidth, height=0.6\\textwidth, "); fprintf(out, "symbolic x coords={"); for (i = 0; i < size; i++) if (i > 0) fprintf(out, ",%d", testset.results[i].nthreads); else fprintf(out, "%d", testset.results[i].nthreads); fprintf(out, "}, x tick label style={ /pgf/number format/1000 sep=}, xlabel=Number of threads, ylabel=Time in s, xtick=data, legend style={legend columns=1}, ybar, bar width=7pt, ymajorgrids=true, yminorgrids=true, minor y tick num=1, "); fprintf(out, " title={%s}", plottitle); fprintf(out, " ]\n"); fprintf(out, "\\addplot coordinates {"); for (i = 0; i < size; i++) fprintf(out, "(%d, %.6" __FES__ ") ", testset.results[i].nthreads, testset.results[i].resval[1].avg + testset.results[i].resval[2].avg); fprintf(out, "};\n"); fprintf(out, "\\addplot coordinates {"); for (i = 0; i < size; i++) fprintf(out, "(%d, %.6" __FES__ ") ", testset.results[i].nthreads, testset.results[i].resval[3].avg); fprintf(out, "};\n"); fprintf(out, "\\addplot coordinates {"); for (i = 0; i < size; i++) fprintf(out, "(%d, %.6" __FES__ ") ", testset.results[i].nthreads, testset.results[i].resval[4].avg + testset.results[i].resval[5].avg + testset.results[i].resval[6].avg); fprintf(out, "};\n"); fprintf(out, "\\addplot coordinates {"); for (i = 0; i < size; i++) fprintf(out, "(%d, %.6" __FES__ ") ", testset.results[i].nthreads, testset.results[i].resval[7].avg); fprintf(out, "};\n"); fprintf(out, "\\addplot coordinates {"); for (i = 0; i < size; i++) fprintf(out, "(%d, %.6" __FES__ ") ", testset.results[i].nthreads, testset.results[i].resval[9].avg - testset.results[i].resval[0].avg); fprintf(out, "};\n"); fprintf(out, "\\legend{prepsi (step 1b),init nearfield (step 1c),far field (steps 2a-c),nearfield (step 2d),total $-$ step 1a}\n"); fprintf(out, "\\end{axis}\n"); fprintf(out, "\\end{tikzpicture}\n"); fprintf(out, "\n\n"); fflush(out); } void fastsum_print_output_speedup_total_minus_indep(FILE *out, s_testset *testsets, int ntestsets) { int i, t; char hostname[1025]; char plottitle[1025]; unsigned int diff_mask = fastsum_determine_different_parameters(testsets, ntestsets); #ifdef HAVE_GETHOSTNAME if (gethostname(hostname, 1024) != 0) #endif strncpy(hostname, "unnamed", 1024); fastsum_get_plot_title_minus_indep(plottitle, 1024, hostname, testsets[0].param, diff_mask | MASK_FSUM_WINM); fprintf(out, "\\begin{tikzpicture}\n"); fprintf(out, "\\begin{axis}["); fprintf(out, "width=0.9\\textwidth, height=0.6\\textwidth, x tick label style={ /pgf/number format/1000 sep=}, xlabel=Number of threads, ylabel=Speedup, xtick=data, legend style={ legend pos = north west, legend columns=1}, ymajorgrids=true, yminorgrids=true, minor y tick num=4, "); fprintf(out, " title={%s}", plottitle); fprintf(out, " ]\n"); for (t = 0; t < ntestsets; t++) { s_testset testset = testsets[t]; R tref = K(0.0); for (i = 0; i < testset.nresults; i++) if (testset.results[i].nthreads == 1) tref = testset.results[i].resval[9].avg - testset.results[i].resval[0].avg; fprintf(out, "\\addplot coordinates {"); for (i = 0; i < testset.nresults; i++) fprintf(out, "(%d, %.6" __FES__ ") ", testset.results[i].nthreads, tref / (testset.results[i].resval[9].avg - testset.results[i].resval[0].avg)); fprintf(out, "};\n"); for (i = 0; i < testset.nresults; i++) { fprintf(stderr, "%d:%.3" __FIS__ " ", testset.results[i].nthreads, tref / (testset.results[i].resval[9].avg - testset.results[i].resval[0].avg)); } fprintf(stderr, "\n\n"); } fprintf(out, "\\legend{{"); for (t = 0; t < ntestsets; t++) { char title[256]; if (t > 0) fprintf(out, "},{"); fastsum_get_plot_title_minus_indep(title, 255, "", testsets[t].param, ~(diff_mask | MASK_FSUM_WINM)); fprintf(out, "%s", title); } fprintf(out, "}}\n"); fprintf(out, "\\end{axis}\n"); fprintf(out, "\\end{tikzpicture}\n"); fprintf(out, "\n\n"); fflush(out); } void run_testset(s_testset *testset, int d, int L, int M, int n, int m, int p, char *kernel_name, R c, R eps_I, R eps_B, int *nthreads_array, int n_threads_array_size) { int i; testset->param.d = d; testset->param.L = L; testset->param.M = M; testset->param.n = n; testset->param.m = m; testset->param.p = p; testset->param.kernel_name = kernel_name; testset->param.c = c; testset->param.eps_I = eps_I; testset->param.eps_B = eps_B; testset->results = (s_result*) NFFT(malloc)( (size_t)(n_threads_array_size) * sizeof(s_result)); testset->nresults = n_threads_array_size; run_test_create(testset->param.d, testset->param.L, testset->param.M); for (i = 0; i < n_threads_array_size; i++) { testset->results[i].nthreads = nthreads_array[i]; run_test(testset->results[i].resval, NREPEAT, testset->param.n, testset->param.m, testset->param.p, testset->param.kernel_name, testset->param.c, testset->param.eps_I, testset->param.eps_B, testset->results[i].nthreads); } } void test1(int *nthreads_array, int n_threads_array_size) { s_testset testsets[1]; #if defined MEASURE_TIME && defined MEASURE_TIME_FFTW run_testset(&testsets[0], 3, 100000, 100000, 128, 4, 7, "one_over_x", K(0.0), K(0.03125), K(0.03125), nthreads_array, n_threads_array_size); fastsum_print_output_speedup_total_minus_indep(file_out_tex, testsets, 1); fastsum_print_output_histo_PreRfNfT(file_out_tex, testsets[0]); nfft_adjoint_print_output_histo_DFBRT(file_out_tex, testsets[0]); nfft_trafo_print_output_histo_DFBRT(file_out_tex, testsets[0]); #endif } int main(int argc, char** argv) { int *nthreads_array; int n_threads_array_size = get_nthreads_array(&nthreads_array); int k; #if !(defined MEASURE_TIME && defined MEASURE_TIME_FFTW) fprintf(stderr, "WARNING: Detailed time measurements are not activated.\n"); fprintf(stderr, "Please re-run the configure script with options\n"); fprintf(stderr, "--enable-measure-time --enable-measure-time-fftw --enable-openmp\n"); fprintf(stderr, "and run \"make clean all\"\n\n"); #endif for (k = 0; k < n_threads_array_size; k++) fprintf(stderr, "%d ", nthreads_array[k]); fprintf(stderr, "\n"); file_out_tex = fopen("fastsum_benchomp_results_plots.tex", "w"); test1(nthreads_array, n_threads_array_size); fclose(file_out_tex); return EXIT_SUCCESS; } nfft-3.3.2/applications/fastsum/fastsum_benchomp_createdataset.c000066400000000000000000000052611300072027400252150ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include "config.h" #include "nfft3.h" #include "infft.h" void fastsum_benchomp_createdataset(unsigned int d, int L, int M) { int t, j, k; R *x; R *y; C *alpha; x = (R*) NFFT(malloc)((size_t)(d * L) * sizeof(R)); y = (R*) NFFT(malloc)((size_t)(d * L) * sizeof(R)); alpha = (C*) NFFT(malloc)((size_t)(L) * sizeof(C)); /** init source knots in a d-ball with radius 1 */ k = 0; while (k < L) { R r_max = K(1.0); R r2 = K(0.0); for (j = 0; j < d; j++) x[k * d + j] = K(2.0) * r_max * NFFT(drand48)() - r_max; for (j = 0; j < d; j++) r2 += x[k * d + j] * x[k * d + j]; if (r2 >= r_max * r_max) continue; k++; } NFFT(vrand_unit_complex)(alpha, L); /** init target knots in a d-ball with radius 1 */ k = 0; while (k < M) { R r_max = K(1.0); R r2 = K(0.0); for (j = 0; j < d; j++) y[k * d + j] = K(2.0) * r_max * NFFT(drand48)() - r_max; for (j = 0; j < d; j++) r2 += y[k * d + j] * y[k * d + j]; if (r2 >= r_max * r_max) continue; k++; } printf("%d %d %d\n", d, L, M); for (j = 0; j < L; j++) { for (t = 0; t < d; t++) printf("%.16" __FES__ " ", x[d * j + t]); printf("\n"); } for (j = 0; j < L; j++) printf("%.16" __FES__ " %.16" __FES__ "\n", CREAL(alpha[j]), CIMAG(alpha[j])); for (j = 0; j < M; j++) { for (t = 0; t < d; t++) printf("%.16" __FES__ " ", y[d * j + t]); printf("\n"); } NFFT(free)(x); NFFT(free)(y); NFFT(free)(alpha); } int main(int argc, char **argv) { int d; int L; int M; if (argc < 4) { fprintf(stderr, "usage: d L M\n"); return -1; } d = atoi(argv[1]); L = atoi(argv[2]); M = atoi(argv[3]); fprintf(stderr, "d=%d, L=%d, M=%d\n", d, L, M); fastsum_benchomp_createdataset(d, L, M); return 0; } nfft-3.3.2/applications/fastsum/fastsum_benchomp_detail.c000066400000000000000000000141221300072027400236420ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include "nfft3.h" #include "infft.h" #include "fastsum.h" #include "kernels.h" #ifdef _OPENMP #include #endif int bench_openmp(FILE *infile, int n, int m, int p, C (*kernel)(R, int, const R *), R c, R eps_I, R eps_B) { fastsum_plan my_fastsum_plan; int d, L, M; int t, j; R re, im; R r_max = K(0.25) - my_fastsum_plan.eps_B / K(2.0); ticks t0, t1; R tt_total; fscanf(infile, "%d %d %d", &d, &L, &M); #ifdef _OPENMP FFTW(import_wisdom_from_filename)("fastsum_benchomp_detail_threads.plan"); #else FFTW(import_wisdom_from_filename)("fastsum_benchomp_detail_single.plan"); #endif fastsum_init_guru(&my_fastsum_plan, d, L, M, kernel, &c, NEARFIELD_BOXES, n, m, p, eps_I, eps_B); #ifdef _OPENMP FFTW(export_wisdom_to_filename)("fastsum_benchomp_detail_threads.plan"); #else FFTW(export_wisdom_to_filename)("fastsum_benchomp_detail_single.plan"); #endif for (j = 0; j < L; j++) { for (t = 0; t < d; t++) { R v; fscanf(infile, __FR__, &v); my_fastsum_plan.x[d * j + t] = v * r_max; } } for (j = 0; j < L; j++) { fscanf(infile, __FR__ " " __FR__, &re, &im); my_fastsum_plan.alpha[j] = re + II * im; } for (j = 0; j < M; j++) { for (t = 0; t < d; t++) { R v; fscanf(infile, __FR__, &v); my_fastsum_plan.y[d * j + t] = v * r_max; } } /** precomputation */ t0 = getticks(); fastsum_precompute(&my_fastsum_plan); /** fast computation */ fastsum_trafo(&my_fastsum_plan); t1 = getticks(); tt_total = NFFT(elapsed_seconds)(t1, t0); #ifndef MEASURE_TIME my_fastsum_plan.MEASURE_TIME_t[0] = K(0.0); my_fastsum_plan.MEASURE_TIME_t[1] = K(0.0); my_fastsum_plan.MEASURE_TIME_t[2] = K(0.0); my_fastsum_plan.MEASURE_TIME_t[3] = K(0.0); my_fastsum_plan.MEASURE_TIME_t[4] = K(0.0); my_fastsum_plan.MEASURE_TIME_t[5] = K(0.0); my_fastsum_plan.MEASURE_TIME_t[6] = K(0.0); my_fastsum_plan.MEASURE_TIME_t[7] = K(0.0); my_fastsum_plan.mv1.MEASURE_TIME_t[0] = K(0.0); my_fastsum_plan.mv1.MEASURE_TIME_t[2] = K(0.0); my_fastsum_plan.mv2.MEASURE_TIME_t[0] = K(0.0); my_fastsum_plan.mv2.MEASURE_TIME_t[2] = K(0.0); #endif #ifndef MEASURE_TIME_FFTW my_fastsum_plan.mv1.MEASURE_TIME_t[1] = K(0.0); my_fastsum_plan.mv2.MEASURE_TIME_t[1] = K(0.0); #endif printf( "%.6" __FES__ " %.6" __FES__ " %.6" __FES__ " %6" __FES__ " %.6" __FES__ " %.6" __FES__ " %.6" __FES__ " %.6" __FES__ " %.6" __FES__ " %6" __FES__ " %.6" __FES__ " %.6" __FES__ " %6" __FES__ " %.6" __FES__ " %.6" __FES__ " %6" __FES__ "\n", my_fastsum_plan.MEASURE_TIME_t[0], my_fastsum_plan.MEASURE_TIME_t[1], my_fastsum_plan.MEASURE_TIME_t[2], my_fastsum_plan.MEASURE_TIME_t[3], my_fastsum_plan.MEASURE_TIME_t[4], my_fastsum_plan.MEASURE_TIME_t[5], my_fastsum_plan.MEASURE_TIME_t[6], my_fastsum_plan.MEASURE_TIME_t[7], tt_total - my_fastsum_plan.MEASURE_TIME_t[0] - my_fastsum_plan.MEASURE_TIME_t[1] - my_fastsum_plan.MEASURE_TIME_t[2] - my_fastsum_plan.MEASURE_TIME_t[3] - my_fastsum_plan.MEASURE_TIME_t[4] - my_fastsum_plan.MEASURE_TIME_t[5] - my_fastsum_plan.MEASURE_TIME_t[6] - my_fastsum_plan.MEASURE_TIME_t[7], tt_total, my_fastsum_plan.mv1.MEASURE_TIME_t[0], my_fastsum_plan.mv1.MEASURE_TIME_t[1], my_fastsum_plan.mv1.MEASURE_TIME_t[2], my_fastsum_plan.mv2.MEASURE_TIME_t[0], my_fastsum_plan.mv2.MEASURE_TIME_t[1], my_fastsum_plan.mv2.MEASURE_TIME_t[2]); fastsum_finalize(&my_fastsum_plan); return 0; } int main(int argc, char **argv) { int n; /**< expansion degree */ int m; /**< cut-off parameter */ int p; /**< degree of smoothness */ char *s; /**< name of kernel */ C (*kernel)(R, int, const R *); /**< kernel function */ R c; /**< parameter for kernel */ R eps_I; /**< inner boundary */ R eps_B; /**< outer boundary */ #ifdef _OPENMP int nthreads; if (argc != 9) return EXIT_FAILURE; nthreads = atoi(argv[8]); FFTW(init_threads)(); omp_set_num_threads(nthreads); #else if (argc != 8) return EXIT_FAILURE; #endif n = atoi(argv[1]); m = atoi(argv[2]); p = atoi(argv[3]); s = argv[4]; c = atof(argv[5]); eps_I = (R)(atof(argv[6])); eps_B = (R)(atof(argv[7])); if (strcmp(s, "gaussian") == 0) kernel = gaussian; else if (strcmp(s, "multiquadric") == 0) kernel = multiquadric; else if (strcmp(s, "inverse_multiquadric") == 0) kernel = inverse_multiquadric; else if (strcmp(s, "logarithm") == 0) kernel = logarithm; else if (strcmp(s, "thinplate_spline") == 0) kernel = thinplate_spline; else if (strcmp(s, "one_over_square") == 0) kernel = one_over_square; else if (strcmp(s, "one_over_modulus") == 0) kernel = one_over_modulus; else if (strcmp(s, "one_over_x") == 0) kernel = one_over_x; else if (strcmp(s, "inverse_multiquadric3") == 0) kernel = inverse_multiquadric3; else if (strcmp(s, "sinc_kernel") == 0) kernel = sinc_kernel; else if (strcmp(s, "cosc") == 0) kernel = cosc; else if (strcmp(s, "cot") == 0) kernel = kcot; else { s = "multiquadric"; kernel = multiquadric; } bench_openmp(stdin, n, m, p, kernel, c, eps_I, eps_B); return EXIT_SUCCESS; } nfft-3.3.2/applications/fastsum/fastsum_matlab.c000066400000000000000000000154021300072027400217670ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /*! \file fastsum_matlab.c * \brief Simple test program for the fast NFFT-based summation algorithm, called by fastsum.m. * * \author Markus Fenn * \date 2006 */ #include "config.h" #include #include #include #include #ifdef HAVE_COMPLEX_H #include #endif #include "fastsum.h" #include "kernels.h" #include "infft.h" /** * \defgroup applications_fastsum_matlab fastsum_matlab * \ingroup applications_fastsum * \{ */ int main(int argc, char **argv) { int j, k, t; /**< indices */ int d; /**< number of dimensions */ int N; /**< number of source nodes */ int M; /**< number of target nodes */ int n; /**< expansion degree */ int m; /**< cut-off parameter */ int p; /**< degree of smoothness */ const char *s; /**< name of kernel */ C (*kernel)(R, int, const R *); /**< kernel function */ R c; /**< parameter for kernel */ fastsum_plan my_fastsum_plan; /**< plan for fast summation */ C *direct; /**< array for direct computation */ ticks t0, t1; /**< for time measurement */ R time; /**< for time measurement */ R error = K(0.0); /**< for error computation */ R eps_I; /**< inner boundary */ R eps_B; /**< outer boundary */ FILE *fid1, *fid2; R temp; if (argc != 11) { printf("\nfastsum_test d N M n m p kernel c\n\n"); printf(" d dimension \n"); printf(" N number of source nodes \n"); printf(" M number of target nodes \n"); printf(" n expansion degree \n"); printf(" m cut-off parameter \n"); printf(" p degree of smoothness \n"); printf(" kernel kernel function (e.g., gaussian)\n"); printf(" c kernel parameter \n"); printf(" eps_I inner boundary \n"); printf(" eps_B outer boundary \n\n"); exit(-1); } else { d = atoi(argv[1]); N = atoi(argv[2]); c = K(1.0) / POW((R)(N), K(1.0) / ((R)(d))); M = atoi(argv[3]); n = atoi(argv[4]); m = atoi(argv[5]); p = atoi(argv[6]); s = argv[7]; c = (R)(atof(argv[8])); eps_I = (R)(atof(argv[9])); eps_B = (R)(atof(argv[10])); if (strcmp(s, "gaussian") == 0) kernel = gaussian; else if (strcmp(s, "multiquadric") == 0) kernel = multiquadric; else if (strcmp(s, "inverse_multiquadric") == 0) kernel = inverse_multiquadric; else if (strcmp(s, "logarithm") == 0) kernel = logarithm; else if (strcmp(s, "thinplate_spline") == 0) kernel = thinplate_spline; else if (strcmp(s, "one_over_square") == 0) kernel = one_over_square; else if (strcmp(s, "one_over_modulus") == 0) kernel = one_over_modulus; else if (strcmp(s, "one_over_x") == 0) kernel = one_over_x; else if (strcmp(s, "inverse_multiquadric3") == 0) kernel = inverse_multiquadric3; else if (strcmp(s, "sinc_kernel") == 0) kernel = sinc_kernel; else if (strcmp(s, "cosc") == 0) kernel = cosc; else if (strcmp(s, "cot") == 0) kernel = kcot; else { s = "multiquadric"; kernel = multiquadric; } } printf( "d=%d, N=%d, M=%d, n=%d, m=%d, p=%d, kernel=%s, c=%" __FGS__ ", eps_I=%" __FGS__ ", eps_B=%" __FGS__ " \n", d, N, M, n, m, p, s, c, eps_I, eps_B); /** init two dimensional fastsum plan */ fastsum_init_guru(&my_fastsum_plan, d, N, M, kernel, &c, 0, n, m, p, eps_I, eps_B); /*fastsum_init_guru(&my_fastsum_plan, d, N, M, kernel, &c, EXACT_NEARFIELD, n, m, p);*/ /** load source knots and coefficients */ fid1 = fopen("x.dat", "r"); fid2 = fopen("alpha.dat", "r"); for (k = 0; k < N; k++) { for (t = 0; t < d; t++) { fscanf(fid1, __FR__, &my_fastsum_plan.x[k * d + t]); } fscanf(fid2, __FR__, &temp); my_fastsum_plan.alpha[k] = temp; fscanf(fid2, __FR__, &temp); my_fastsum_plan.alpha[k] += temp * II; } fclose(fid1); fclose(fid2); /** load target knots */ fid1 = fopen("y.dat", "r"); for (j = 0; j < M; j++) { for (t = 0; t < d; t++) { fscanf(fid1, __FR__, &my_fastsum_plan.y[j * d + t]); } } fclose(fid1); /** direct computation */ printf("direct computation: "); fflush(NULL); t0 = getticks(); fastsum_exact(&my_fastsum_plan); t1 = getticks(); time = NFFT(elapsed_seconds)(t1, t0); printf(__FI__ "sec\n", time); /** copy result */ direct = (C *) NFFT(malloc)((size_t)(my_fastsum_plan.M_total) * (sizeof(C))); for (j = 0; j < my_fastsum_plan.M_total; j++) direct[j] = my_fastsum_plan.f[j]; /** precomputation */ printf("pre-computation: "); fflush(NULL); t0 = getticks(); fastsum_precompute(&my_fastsum_plan); t1 = getticks(); time = NFFT(elapsed_seconds)(t1, t0); printf(__FI__ "sec\n", time); /** fast computation */ printf("fast computation: "); fflush(NULL); t0 = getticks(); fastsum_trafo(&my_fastsum_plan); t1 = getticks(); time = NFFT(elapsed_seconds)(t1, t0); printf(__FI__ "sec\n", time); /** compute max error */ error = K(0.0); for (j = 0; j < my_fastsum_plan.M_total; j++) { if (CABS(direct[j] - my_fastsum_plan.f[j]) / CABS(direct[j]) > error) error = CABS(direct[j] - my_fastsum_plan.f[j]) / CABS(direct[j]); } printf("max relative error: " __FE__ "\n", error); /** write result to file */ fid1 = fopen("f.dat", "w+"); fid2 = fopen("f_direct.dat", "w+"); if (fid1 == NULL) { printf("Fehler!\n"); exit(EXIT_FAILURE); } for (j = 0; j < M; j++) { temp = CREAL(my_fastsum_plan.f[j]); fprintf(fid1, " % .16" __FES__ "", temp); temp = CIMAG(my_fastsum_plan.f[j]); fprintf(fid1, " % .16" __FES__ "\n", temp); temp = CREAL(direct[j]); fprintf(fid2, " % .16" __FES__ "", temp); temp = CIMAG(direct[j]); fprintf(fid2, " % .16" __FES__ "\n", temp); } fclose(fid1); fclose(fid2); /** finalise the plan */ fastsum_finalize(&my_fastsum_plan); return EXIT_SUCCESS; } /* \} */ nfft-3.3.2/applications/fastsum/fastsum_test.c000066400000000000000000000177251300072027400215200ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /*! \file fastsum_test.c * \brief Simple test program for the fast NFFT-based summation algorithm. * * \author Markus Fenn * \date 2006 */ #include "config.h" #include #include #include #include #ifdef HAVE_COMPLEX_H #include #endif #ifdef _OPENMP #include #endif #include "fastsum.h" #include "kernels.h" #include "infft.h" /** * \defgroup applications_fastsum_test fastsum_test * \ingroup applications_fastsum * \{ */ int main(int argc, char **argv) { int j, k; /**< indices */ int d; /**< number of dimensions */ int N; /**< number of source nodes */ int M; /**< number of target nodes */ int n; /**< expansion degree */ int m; /**< cut-off parameter */ int p; /**< degree of smoothness */ const char *s; /**< name of kernel */ C (*kernel)(R, int, const R *); /**< kernel function */ R c; /**< parameter for kernel */ fastsum_plan my_fastsum_plan; /**< plan for fast summation */ C *direct; /**< array for direct computation */ ticks t0, t1; /**< for time measurement */ R time; /**< for time measurement */ R error = K(0.0); /**< for error computation */ R eps_I; /**< inner boundary */ R eps_B; /**< outer boundary */ if (argc != 11) { printf("\nfastsum_test d N M n m p kernel c eps_I eps_B\n\n"); printf(" d dimension \n"); printf(" N number of source nodes \n"); printf(" M number of target nodes \n"); printf(" n expansion degree \n"); printf(" m cut-off parameter \n"); printf(" p degree of smoothness \n"); printf(" kernel kernel function (e.g., gaussian)\n"); printf(" c kernel parameter \n"); printf(" eps_I inner boundary \n"); printf(" eps_B outer boundary \n\n"); exit(EXIT_FAILURE); } else { d = atoi(argv[1]); N = atoi(argv[2]); c = K(1.0) / POW((R)(N), K(1.0) / ((R)(d))); M = atoi(argv[3]); n = atoi(argv[4]); m = atoi(argv[5]); p = atoi(argv[6]); s = argv[7]; c = (R)(atof(argv[8])); eps_I = (R)(atof(argv[9])); eps_B = (R)(atof(argv[10])); if (strcmp(s, "gaussian") == 0) kernel = gaussian; else if (strcmp(s, "multiquadric") == 0) kernel = multiquadric; else if (strcmp(s, "inverse_multiquadric") == 0) kernel = inverse_multiquadric; else if (strcmp(s, "logarithm") == 0) kernel = logarithm; else if (strcmp(s, "thinplate_spline") == 0) kernel = thinplate_spline; else if (strcmp(s, "one_over_square") == 0) kernel = one_over_square; else if (strcmp(s, "one_over_modulus") == 0) kernel = one_over_modulus; else if (strcmp(s, "one_over_x") == 0) kernel = one_over_x; else if (strcmp(s, "inverse_multiquadric3") == 0) kernel = inverse_multiquadric3; else if (strcmp(s, "sinc_kernel") == 0) kernel = sinc_kernel; else if (strcmp(s, "cosc") == 0) kernel = cosc; else if (strcmp(s, "cot") == 0) kernel = kcot; else { s = "multiquadric"; kernel = multiquadric; } } printf( "d=%d, N=%d, M=%d, n=%d, m=%d, p=%d, kernel=%s, c=%" __FGS__ ", eps_I=%" __FGS__ ", eps_B=%" __FGS__ " \n", d, N, M, n, m, p, s, c, eps_I, eps_B); #ifdef NF_KUB printf("nearfield correction using piecewise cubic Lagrange interpolation\n"); #elif defined(NF_QUADR) printf("nearfield correction using piecewise quadratic Lagrange interpolation\n"); #elif defined(NF_LIN) printf("nearfield correction using piecewise linear Lagrange interpolation\n"); #endif #ifdef _OPENMP #pragma omp parallel { #pragma omp single { printf("nthreads=%d\n", omp_get_max_threads()); } } FFTW(init_threads)(); #endif /** init d-dimensional fastsum plan */ fastsum_init_guru(&my_fastsum_plan, d, N, M, kernel, &c, 0, n, m, p, eps_I, eps_B); //fastsum_init_guru(&my_fastsum_plan, d, N, M, kernel, &c, NEARFIELD_BOXES, n, m, p, eps_I, eps_B); if (my_fastsum_plan.flags & NEARFIELD_BOXES) printf( "determination of nearfield candidates based on partitioning into boxes\n"); else printf("determination of nearfield candidates based on search tree\n"); /** init source knots in a d-ball with radius 0.25-eps_b/2 */ k = 0; while (k < N) { R r_max = K(0.25) - my_fastsum_plan.eps_B / K(2.0); R r2 = K(0.0); for (j = 0; j < d; j++) my_fastsum_plan.x[k * d + j] = K(2.0) * r_max * NFFT(drand48)() - r_max; for (j = 0; j < d; j++) r2 += my_fastsum_plan.x[k * d + j] * my_fastsum_plan.x[k * d + j]; if (r2 >= r_max * r_max) continue; k++; } for (k = 0; k < N; k++) { /* R r=(0.25-my_fastsum_plan.eps_B/2.0)*pow((R)rand()/(R)RAND_MAX,1.0/d); my_fastsum_plan.x[k*d+0] = r; for (j=1; j= r_max * r_max) continue; k++; } /* for (k=0; k error) error = CABS(direct[j] - my_fastsum_plan.f[j]) / CABS(direct[j]); } printf("max relative error: %" __FES__ "\n", error); /** finalise the plan */ fastsum_finalize(&my_fastsum_plan); return EXIT_SUCCESS; } /* \} */ nfft-3.3.2/applications/fastsum/fastsum_test.dSYM/000077500000000000000000000000001300072027400221535ustar00rootroot00000000000000nfft-3.3.2/applications/fastsum/fastsum_test.dSYM/Contents/000077500000000000000000000000001300072027400237505ustar00rootroot00000000000000nfft-3.3.2/applications/fastsum/fastsum_test.dSYM/Contents/Info.plist000066400000000000000000000012011300072027400257120ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleIdentifier com.apple.xcode.dsym.fastsum_test CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType dSYM CFBundleSignature ???? CFBundleShortVersionString 1.0 CFBundleVersion 1 nfft-3.3.2/applications/fastsum/fastsum_test.dSYM/Contents/Resources/000077500000000000000000000000001300072027400257225ustar00rootroot00000000000000nfft-3.3.2/applications/fastsum/fastsum_test.dSYM/Contents/Resources/DWARF/000077500000000000000000000000001300072027400265655ustar00rootroot00000000000000nfft-3.3.2/applications/fastsum/fastsum_test.dSYM/Contents/Resources/DWARF/fastsum_test000066400000000000000000002224501300072027400312360ustar00rootroot00000000000000Ïúíþ È4 ú2 8œíxUü3t„@½H__PAGEZEROx__TEXT __text__TEXT@ â€__stubs__TEXT"Æ€__stub_helper__TEXTèZ€__const__TEXTPÈ__cstring__TEXTá__unwind_info__TEXTüÈ__eh_frame__TEXTÈ8ˆ__DATA __nl_symbol_ptr__DATA !__got__DATA #__la_symbol_ptr__DATA( &__common__DATA0!H__LINKEDIT0`ý__DWARF0(õ __debug_abbrev__DWARF00__debug_aranges__DWARF0’0 02__debug_info__DWARF`›s`;__debug_line__DWARFs 9s®__debug_loc__DWARF€Gn€ç__debug_pubnames__DWARFîLf îì__debug_pubtypes__DWARFTXóTø__debug_str__DWARFG^•Gþ__apple_names__DWARFÜoÜ__apple_types__DWARFì}ôì__apple_namespac__DWARFà„$à$__apple_objc__DWARF…$% ! À/ð9À=) >3F=PMHÀTT^adq°h|Pkƒ kˆ`Óœ@è­ÀÀÑàKä0†õ@Р ÀÀà "€ &1(:)Nà*UÐ-a07mà[y€€…à‰¦€‹ÆP³Ý´â ´ù ÛÐå0æGðïg0ò~ðò•pû´ðû× öÀÿ@à €Ð)®/1>ð/P(c°2w0J†ðk |¦°“½ ¿Ãà"ϰ…Ú@ àÀuîàýÐûA! ¸3PÞI°ÑaÒrð#Ð׊ @!š°õ©ÀPÔÍ` åÀ Ð%Ø 8!.°:À"I#Xp#g xp!ˆpÔ•°  @×® 0!ÁÐÔØÖó 'A[0 qP÷•Àü¹ÐõÈÀÕ@äå°õ`n`Ø2ÀJ@cð{“ ª0ÃÐÛó  Ðöpö=ðõW0Ïf Žx0Œ‰P‘•Ðžðœ«Љ_BasisPoly_max_i_BuildBox_BuildTree_regkern1_regkern3_SearchBox_SearchTree_kubintkern1_calc_SearchBox_quicksort_binom_fak_evaluate_chebyshev_nfft_trafo_1d_B_nfft_adjoint_1d_B_nfft_trafo_2d_B_nfft_adjoint_2d_B_nfft_trafo_3d_B_nfft_adjoint_3d_B_D_A_B_A_B_T_D_T_sort_uo_init_help_intprod_precompute_phi_hut_sort0_D_serial_T_B_serial_T_B_serial_A_D_serial_A_nfft_adjoint_B_compute_full_psi_nfft_adjoint_3d_compute_serial_nfft_3d_init_fg_exp_l_uo2_nfft_trafo_3d_compute_nfft_adjoint_2d_compute_serial_nfft_2d_init_fg_exp_l_nfft_trafo_2d_compute_nfft_adjoint_1d_compute_serial_nfft_1d_init_fg_exp_l_nfft_trafo_1d_compute_sort_node_indices_radix_count_sort_node_indices_radix_rearrange_sort_node_indices_sort_bubble_elapsed_P1_Q1_P2_Q2_m2K___mh_execute_header_cosc_fastsum_exact_fastsum_finalize_fastsum_init_guru_fastsum_precompute_fastsum_trafo_gaussian_inverse_multiquadric_inverse_multiquadric3_kcot_kubintkern_logarithm_main_multiquadric_nfftl_adjoint_nfftl_adjoint_1d_nfftl_adjoint_2d_nfftl_adjoint_3d_nfftl_adjoint_direct_nfftl_assertion_failed_nfftl_bessel_i0_nfftl_check_nfftl_die_nfftl_die_hook_nfftl_drand48_nfftl_elapsed_seconds_nfftl_exp2i_nfftl_fftshift_complex_nfftl_fftshift_complex_int_nfftl_finalize_nfftl_free_nfftl_free_hook_nfftl_init_nfftl_init_1d_nfftl_init_2d_nfftl_init_3d_nfftl_init_guru_nfftl_init_lin_nfftl_log2i_nfftl_m2K_nfftl_malloc_nfftl_malloc_hook_nfftl_next_power_of_2_nfftl_next_power_of_2_exp_nfftl_precompute_fg_psi_nfftl_precompute_full_psi_nfftl_precompute_lin_psi_nfftl_precompute_one_psi_nfftl_precompute_psi_nfftl_sort_node_indices_radix_lsdf_nfftl_sort_node_indices_radix_msdf_nfftl_srand48_nfftl_trafo_nfftl_trafo_1d_nfftl_trafo_2d_nfftl_trafo_3d_nfftl_trafo_direct_nfftl_upd_axpby_complex_nfftl_upd_axpby_double_nfftl_upd_axpwy_complex_nfftl_upd_axpwy_double_nfftl_upd_axpy_complex_nfftl_upd_axpy_double_nfftl_upd_xpawy_complex_nfftl_upd_xpawy_double_nfftl_upd_xpay_complex_nfftl_upd_xpay_double_nfftl_vrand_real_nfftl_vrand_shifted_unit_double_nfftl_vrand_unit_complex_one_over_cube_one_over_modulus_one_over_square_one_over_x_regkern_sinc_kernel_thinplate_spline%.: ; ' I? 2 @ : ; I 4: ; I  $> I&I I' I I: ;  : ; I: ; 8 2  : ; I: ;' I!I/ $ > < .: ;' I? 2 @ : ;I 4: ;I .: ;' ? 2 @ 4: ;I.: ;' I2 @ .: ; ' I2 @ .: ;' 2 @ !I.: ; ' ? 2 @ 4I: ; !4I: ;  "4I? : ;  #.: ; ' 2 @ $4: ; I%.: ; ' I? 2 @ &4I: ;  '!I/,@ † \›ÐÇ !5à"§(À/,ð/1«°26ð9ÇÀ=Ü >QF*0JPMnÀTF ^èd¤°h™PkC kHì7ðk Àu¥ |Ô°…ÐЉ)0Œ: ŽpP‘%°“ ðœé®P ¿Y0ÏL,»°ÑP<AÒZ`Óå\^!PÔpÔQÐÔ+Ö6L #@ׂÐ×4ØL\ƒ$`ØêPÞã@äô@è„Ðû$§° ÀK#AÉ àK}"`nÅ0†e2 ¸š@Ðz1ÀÖ ÀàÖÀà ø a€ ¢0 Ñõ˜°U  Gp!OÀ">#hp#rð#ÜÐ%¹(c)Ôà*ëÐ- .à[$€€] à‰•€‹Ë'P³½´„ ´ú& Û, Ð彿’ 0ò½ðòºle°õÐõðõtpö[ÐötlÀfP÷pûyðûÏÀüR a<èj/ÀFܾk… a… a¦Àl0™Ðn@¯ðn` TÀ ê,^r° r— @O@ ª6Ú@ ÆV¯6Ú‘`´6á‘X¹8Ú‘T»8Ú‘P½9Ú‘L¿:Ú‘HÁ;Ú‘DÃ<Ú‘@Å=Ú‘¼Ç>Ú‘¸É?ò‘°Ë@ü‘¨ÒA)‘ÔBE‘ xäCû‘˜xëD}‘xîD}‘ˆxñE)‘ðwöF)‘àwüG)‘ÐwH)‘Àw,ª)‘°w«)‘ w ¯Ï)‘wÐ)‘€wæë÷ë  ) Ú ; "R 4$Q&@) P2| ?pJ ½ÚN# MÚP# UÚQ# ]ûS# cûT# eV#  gW#( »Y#0 iZ#8 v\#@ |ûa#H ÃÚd#P ‚ûe#X ÇÚg#` ü)h#p )i#€ „k# ˆl#  ŒÚo#° ûp#¸ “Ps#À œÚu#È ¦Úv#Ì ¸lw#Ð Ãx#Ø Éûy#à Óq{#ð) üË@â "ï M÷Â# U÷Â# úÂ# cÂ# %Â#  %Â#( ½÷Â#0 ¿3Â#8 8Â#@ Ã3Â#H ÷Â#P Å÷Â#X ‚8Â#` "÷Â#h vÂ#p $Â#t e8Â#x Ó=Â#€ /PÂ#° =PÂ#¸ KgÂ#À U8Â#È Y3Â#Ð e3Â#Ø qÂ#à sÂ#è yÂ#ð |Â#ø 8Â#€ 3Â#ˆ •6 š"¤"­e* 2÷44I\»eaÆ8Ú)I ˆÓ¤ “Ù☠ùUOÐV½Ð—!V»V ‘X VŽ ‘@ÇV! ‘¼V0‘°VŽ ‘ ‚VŽ ‘X! ‘ŒY½‘à~ ÈR C½à"‡(VeC5‘PC:‘HŒCD‘DC5‘°ÒEŽ ‘ 'EŽ ‘*EŽ ‘€-EŽ ‘ð~0EŽ ‘à~F! ‘Ü~3G½‘°~6G½‘~9G½‘ð}<G½‘Ð}?¸(¡/VQ¸I‘`½¸! ‘\M¸! ‘XU¸! ‘T»¹ ‘H¹ ‘@v¹‘¼U¹! ‘¸Å¹! ‘´Ç¹! ‘°ü¹Ž ‘ ¹Ž ‘X»! ‘Œ½! ‘ü~Z¾‘ø~k¿‘ô~ü{7*V,P*V,P*L,²*L,²*L,Æ*,~îŽ ‘à~„Qð/ö0VQQI‘x•r1«2VQrI‘x¹t! ‘t»t! ‘pXu! ‘lvŽ ‘P£°2æ9VQI‘x¹’! ‘t»’! ‘pX’! ‘l“! ‘h¶$0JGMVQ$I‘`¹&! ‘\»&! ‘XX&! ‘TK%M%KMÄ[†:Éb½ÀT^V½bD‘¬XbD‘¨eb0‘ ]b:‘˜Ôc0‘Ùc0‘ˆ¿cD‘„»c‘‘ø~c0‘ð~ŒdD‘ì~d:‘à~ÇdD‘Ü~vd–‘Ø~0Uî]LUî]Ål! ‘Ô~ÞmŽ ‘À~ânŽ ‘°~æoŽ ‘ ~pŽ ‘~íq! ‘Œ~ïr! ‘ˆ~sŽ ‘ð}ÕUî]·Vî]xWî]ñ}½‘Ð}øe½^øcVee5‘Pe:‘HŒeD‘De5‘°ÒgŽ ‘ 'gŽ ‘*gŽ ‘€-gŽ ‘ð~0gŽ ‘à~h! ‘Ü~3i½‘°~6i½‘~9i½‘ð}<i½‘Ð}½PM¾TVg ‘¨QI‘ ½‘€X! ‘ü~! ‘ì~{t#ݽd¤hV½Ý! ‘¼gÝ ‘°eÝ ‘¨]Ý‘ 2Ý! ‘œ8Þ! ‘˜Þ:‘ŒÞD‘ŒÇÞ! ‘ˆÞŽ ‘ð~»Þ‘‘è~ß0‘à~vß–‘Ü~ñὑ°~Åã! ‘¬~íã! ‘¨~äŽ ‘~?ë½F*JV»ë ‘X ëŽ ‘@Çë! ‘¼ë0‘°ëŽ ‘ ‚ëŽ ‘í! ‘Œî½‘à~H‹½ >ñEV»‹ ‘X ‹Ž ‘@Ç‹! ‘¼‹0‘°‹Ž ‘ ‚‹Ž ‘! ‘Œ޽‘à~QTÀ=œ>V½T! ‘|XT! ‘xeT ‘p]T‘h¿T! ‘dÚ=–>ì=–>ÅX! ‘`[‚°hIkV½‚! ‘|X‚! ‘xe‚ ‘p]‚‘h¿‚! ‘de„! ‘`j…! ‘\o‡Ž ‘@»‰! ‘¼uŠŽ ‘ {‹½‘€ªð9·=VQªI‘pX¬! ‘lí¬! ‘hŠ­j‘`®†®z:];‘:M;”¶! ‘T<†=<v=”É! ‘P˜3! À/ì/V3! ‘|‚3! ‘xžHŽ  !Õ"VÅH! ‘|H! ‘x HŽ ‘`»J! ‘\KŽ ‘@ ™ $Q&¨9Ž  kèkVÃ9! ‘l¬BŽ Pk“kVÃB! ‘|ÅB! ‘x Ë@ ½ Ž ! 05Ž ?½! N Y2| ?pJ ½! N# M! P# U! Q# ]S# cT# e V#  g W#( » Y#0 i Z#8 v\#@ |a#H Ã! d#P ‚e#X Ç! g#` üŽ h#p Ž i#€ „k# ˆl#  Œ! o#° p#¸ “Ns#À œ! u#È ¦! v#Ì ¸jw#Ð Ã x#Ø Éy#à Óo{#𽎠â ï MõÂ# UõÂ# úÂ# cÂ# #Â#  #Â#( ½õÂ#0 ¿1Â#8 6Â#@ Ã1Â#H õÂ#P ÅõÂ#X ‚6Â#` "õÂ#h vÂ#p $Â#t e6Â#x Ó;Â#€ /NÂ#° =NÂ#¸ KeÂ#À U6Â#È Y1Â#Ð e1Â#Ø qÂ#à sÂ#è yÂ#ð |Â#ø 6Â#€ 1Â#ˆ •6 š"¤È­e( 0õ™ ™ GZ»e_Æ6! Ž G! GŽ G € ²¦ Oðk¼(ðk€uVe(`‘PÅ(r‘L(y‘@Ò*`‘°É+`‘  šR ÏBÀue|VeB`‘PÅBr‘LBy‘@ÒD`‘°ÉE`‘ Ü\ |t…Ve\`‘PÅ\r‘L\y‘@Ò^`‘°É_`‘ ñv°…€‰Vev`‘PÅvr‘Lvy‘@Éx`‘°û—Љù‹Ve—`‘PÅ—r‘L—y‘@É™`‘° ³0ŒjŽVe³`‘Pųr‘L³y‘@ɵ`‘°Ï Ž‘VeÏ`‘PÅÏr‘LÏy‘@ÉÑ`‘°-ëP‘u“Veë`‘PÅër‘Lëy‘@Éí`‘°8°“±œVe`‘PÅr‘Ly‘@Ò `‘°É `‘ N!ðœÙ­Ve!`‘PÅ!r‘L!y‘@Ò#`‘°É$`‘ Z<®`¿Ve<`‘PÅ<r‘L<y‘@Ò>`‘°É?`‘ _@`‘d\ ¿ùÎVe\`‘PÅ\r‘L\y‘@Ò^`‘°É_`‘ ix0Ï|ÑVex`‘PÅxr‘Lxy‘@Éz`‘° k$Q&~`‚ wÍ €°ÑÒ°ÑÒVÉm‘xé~‘tîm‘hrw ó€Ò ÿ3 8 C… Nš"¤ 3 3 3 !‘§ €´ ¢ ­$Q&!‘š à!åŠ ´ !åz @&¢ÒZÓVe&¢‘`jÒNÓ†Ò×Òg4‘P×ÒNÓg:‘@+¢`ÓEÔVÃ3‘xÒ‘pe‘`¢‘P‚¢‘@X¢‘°¹8‘¨ª >A€PÔDUPÔiÔV£‘x `… kš"¤PUpÔÁÔVÅ£‘xíU‘p\U‘h_+UÐÔûÕV¿+£‘pÃ-U‘hu-U‘`w-U‘X|.U‘PLÖ6×V¿L£‘x L¨‘pXL¨‘hÃNU‘`uNU‘XwNU‘P|OU‘HUUs ª˜€@×"³< 0! GÅZL X Y dà oç\÷" Œ 8! —Zœ X"2º @! ÅAZÊ Ò×ÜYX@×Â×VÃY‘pÇX‘hf/Ø\ØVÇ/X‘xq<ÐרVÉ<Ò‘x@ {w‚`ØÔ“`ØJÞVQ“=‘pú•á?‘hc•á?‘`ÊØ'ÞãØ"Ú¹œ‘XãØÚýØ Ú碑PýØÚÙòÙë¥ñ?‘@"Ú'Þ¹­‘˜"Ú'Þ<ÚÞë³ñ?‘€X´‘ø~ñ´‘ð~ç´‘è~ôÑPÞ3äVQÑ=‘púÓá?‘hcÓá?‘`¹ÞäÒÞà¹ç‘XÒÞ àìÞùßçê‘PìÞôßßáßëíñ?‘@àä¹ö‘˜çö‘àä+àýãëñ?‘ð~X‘è~ñ‘à~ ± @ä4èVQ± ü?‘x¿³ @‘p ³ @‘hó @‘`´ á?‘X´ á?‘Póä+è&º á?‘H-º á?‘@4» @‘¸?» @‘°Xå èxå]æ»Ê ‘¨]æ è»Ù ‘ Jï ÐûôÿVQï ü?‘xÃñ ‘p¿ñ ‘h&ò á?‘`-ò á?‘Xò á?‘Pò á?‘H4ó @‘@?ó @‘¸Ëüæÿîü þ» ‘° þæÿ» ‘¨[Æ °¶VQÆ ü?‘xjÈ ‘pmÈ ‘hpÈ ‘`sÈ ‘XvÈ ‘PÿÈ ‘HsÉ á?‘@úÉ á?‘¸yÊ @‘°…Ê @‘¨‘Ê @‘ Ê @‘˜©Ë ñ?‘€®Ë ñ?‘ð~³Ë ñ?‘à~¸Ë ñ?‘Ð~½Ì á?‘È~ÅÌ á?‘À~ÍÌ á?‘¸~ÕÌ á?‘°~ÝÌ á?‘¨~åÌ á?‘ ~íÌ á?‘˜~õÌ á?‘~ý$AÙKVQ$ü?‘xj&‘pm&‘hp&‘`s&‘Xv&‘Pÿ&‘Hs'á?‘@ú'á?‘¸y(@‘°…(@‘¨‘(@‘ (@‘˜©)ñ?‘€®)ñ?‘ð~³)ñ?‘à~¸)ñ?‘Ð~½*á?‘È~Å*á?‘À~Í*á?‘¸~Õ*á?‘°~Ý*á?‘¨~å*á?‘ ~í*á?‘˜~õ*á?‘~ ý`n%†VQýü?‘xjÿ‘pmÿ‘h ÿ‘`pÿ‘Xsÿ‘P ÿ‘Hvÿ‘@ÿÿ‘¸ ÿ‘°sá?‘¨úá?‘ y@‘˜…@‘‘@‘ˆ@‘€# @‘ø~/ @‘ð~©ñ?‘à~®ñ?‘Ð~³ñ?‘À~¸ñ?‘°~; ñ?‘ ~@ ñ?‘~E á?‘ˆ~N á?‘€~W á?‘ø}` á?‘ð}i á?‘è}r á?‘à}{ á?‘Ø}„ á?‘Ð} á?‘È}– á?‘À}Ÿ á?‘¸}¨ á?‘°}± á?‘¨}º á?‘ }à á?‘˜}Ì á?‘}Õ € ¸:ÐVQ€ü?‘xj‚‘pm‚‘h ‚‘`p‚‘Xs‚‘P ‚‘Hv‚‘@ÿ‚‘¸ ‚‘°sƒá?‘¨úƒá?‘ y„@‘˜…„@‘‘„@‘ˆ„@‘€# „@‘ø~/ „@‘ð~©…ñ?‘à~®…ñ?‘Ð~³…ñ?‘À~¸…ñ?‘°~; …ñ?‘ ~@ …ñ?‘~E †á?‘ˆ~N †á?‘€~W †á?‘ø}` †á?‘ð}i †á?‘è}r †á?‘à}{ †á?‘Ø}„ †á?‘Ð} ‡á?‘È}– ‡á?‘À}Ÿ ‡á?‘¸}¨ ‡á?‘°}± ‡á?‘¨}º ‡á?‘ }à ‡á?‘˜}Ì ‡á?‘}æ ýÀ–VQýü?‘xò #à¶VQ#ü?‘x b VQbü?‘xXd‘p¹e‘h fñ?‘P r VQrü?‘xXt‘p6 u‘h8 u‘`(ÿ Bì ¹{‘X: 0 VQü?‘xX‘pí‘hO ‘‘`6 ’‘X8 ’‘PH øb 幘‘HR ÖVQÖü?‘pXÝ‘hñÝ‘`¹Þ‘Xl ß‘Pp ã‘@v 葸y è‘°€ ¨VQü?‘x™ t°VQtü?‘x½t*@‘t¿t1@‘hUt*@‘dXv‘X¤  g!VQü?‘x½*@‘t¿1@‘hU*@‘dÃ1@‘XÅ*@‘Tvž«?‘P$ž«?‘LX ‘@´ ·p!¿"VQ·ü?‘x½·*@‘t¿·1@‘hU·*@‘d÷1@‘XÅ·*@‘T"·*@‘Pv¸«?‘L$¸«?‘HXº‘@à ÑÀ"þ"VQÑü?‘xÿÑ*@‘tUÑ*@‘p¿Ó6@‘lÑ Ú#h#VQÚü?‘hÿÚ*@‘d Ú*@‘`UÚ*@‘\¿ÜB@‘pß ãp#â#VQãü?‘`ÿã*@‘\ ã*@‘Xí ã*@‘TUã*@‘P¿åN@‘lð íeð#Ì%VQíü?‘p¹ï‘hjoü  Ð%‰(VQ ü?‘xX ‘p  VQü?‘xX‘pp ‘h  "*@‘d(ªAª³ª ]1@‘X# L)Ô*VQLü?‘pXO‘`6 N_@ç9 1(ó(VA 1Z@‘x1@‘p½1@‘hX3‘`Ç3‘X … )š"¤E F€ " VQF=‘x¹F@‘pH F%@‘hK F%@‘`N G@‘XV I@‘@ÒJ‘¸#Y y q VQy=‘x#^ Mà*Ë-V½M@‘pÃMZ@‘hÅM@‘`d N@‘Xp Nj@‘Px N%@‘HuP‘¸¹P‘°} P‘¨‚ P‘ ˆ Q%@‘˜’ R‘$˜ P_@ œ nàûVQnü?‘x  kÐ-07VQkü?‘Xúká?‘Pská?‘HXk‘¸ñk‘°çk‘¨« ùÀÛVQùü?‘x¯ ±07Ù[VQ±ü?‘Hp ±‘@X±‘°ñ±‘¨¹±‘ l ±‘˜v ±‘c±á?‘ˆq±á?‘€º ±á?‘ø~½ ±‘ð~ ±‘è~È ±ñ?‘Ð~Ð ±ñ?‘À~Ø ±ñ?‘°~â ±ñ?‘ ~ç ±ñ?‘~ì ±ñ?‘€~ñ ±ñ?‘ð}ö ±‘è}û ±‘à} ±o@Z “ÀÛVQ“ü?‘x à[}€VQü?‘Hp ‘@X‘°ñ‘¨¹‘ l ‘˜v ‘cá?‘ˆqá?‘€º á?‘ø~½ ‘ð~ ‘è~È ñ?‘Ð~Ð ñ?‘À~Ø ñ?‘°~â ñ?‘ ~ç ñ?‘~ì ñ?‘€~ñ ñ?‘ð}ö ‘è}û ‘à} o@”  »VQü?‘x  €€݉VQ ü?‘Xú á?‘Ps á?‘HX ‘¸ñ ‘°ç ‘¨' ø@кVQøü?‘H»ú‘@pû@‘¸sü@‘° ý@‘¨Áþ@‘ Åÿ@‘˜qá?‘„Ñ›ÓÑ›Óіӳуӹ‘ˆ›ÓJÙ´ÓJÙmÔ4ÙƒÔ!Ù¹3‘ð~í4‘è~9 5ñ?‘Ð~B 6ñ?‘À~K 7ñ?‘°~T 2@ÎJÙ?écÙ?é(Ú&é>Úé6 q‘˜~8 q‘~íq‘ˆ~¹r‘€~9 tñ?‘à}B tñ?‘Ð}K tñ?‘À}?é ôXé ô"£@‘¸}û ¤@‘°}Žéô¤éòó6 ±‘¨}8 ±‘ }í±‘˜}ö ²‘}_ ³ñ?‘€}ñ ³ñ?‘ð|¹´‘è|ô’)ô6 䑨|8 ä‘Ð|íä‘È|¹æ‘¸|T å@d |P³ ´V |@‘xÅ|@‘p‚|@‘`í~‘Xz ñ?‘@„ ñ?‘°Ž ñ?‘ ˜ ñ?‘¥ 4€‹K³Vº 4 @‘Pq4á?‘HÄ 5j@‘@Ð 5j@‘¸Ü 5j@‘°è 5j@‘¨ì 6j@‘ ð 6j@‘˜p6@‘s6@‘ˆ 6@‘€Å7@‘ø~ô 9‘ð~÷ 9‘è~ú 9‘à~ý 9‘Ø~ 9‘Ð~ 9‘È~ 9‘À~ 9‘¸~ 9‘°~ :á?‘¨~ ;j@‘ ~ ;j@‘˜~ ;j@‘~$ P´”´V6 P%@‘x8 P%@‘peP@‘`ÃP@‘XÅP@‘PÒR‘H( )à‰u‹Vq)á?‘pY)Z@‘hU*j@‘`c* @‘XÁ*@‘P½*@‘HÃ*Z@‘@Å+@‘¸v+@‘´+Z@‘¨»-‘ p .‘˜ŠhŠX6‘hŠr‹~Š_‹íš‘ˆ¹›‘€H +0†•¸VQ+ü?‘Hp-@‘@s.@‘¸ /@‘°Á0@‘¨Å1@‘ q3 @‘˜»5‘¬†AˆņAˆp 9@‘ˆý†<ˆ‡)ˆí?‘€¹@‘ø~AˆpŠZˆpŠZˆkŠpˆXйO‘ð~pŠ,‰Š,E‹[‹¹b‘à~íc‘Ø~9 eñ?‘À~B fñ?‘°~K gñ?‘ ~,! E!  ‘  ‘õŸ¹™‘ˆ~6 š‘€~8 š‘ø}íš‘ð}9 œñ?‘Ð}B œñ?‘À}K œñ?‘°}! åª: åª"Ç@‘¨}û Ç@‘ }p àª† ͪ6 Б˜}8 Б}íБˆ}_ Ññ?‘ð|ñ Ññ?‘à|ö Ò‘Ø|¹Ô‘È|T Ó@Bîªm¸«Z¸6 ý‘¸|8 ý‘°|íý‘¨|¹þ‘ |T ü@|X Ž ´šÛVº Žá?‘`qŽ @‘XÄ Žj@‘PÐ j@‘HÜ j@‘@è j@‘¸ì j@‘°ð j@‘¨p@‘ s@‘˜ @‘Å@‘ˆô ’‘€÷ ’‘ø~ú ’‘ð~ý ’‘è~ ’‘à~ ’‘Ø~ ’‘Ð~ ’‘È~ ’‘À~ “ @‘¸~ ”j@‘°~ ”j@‘¨~ ”j@‘ ~n å àK]nVQå ü?‘Ppç @‘Hsè @‘@Áé @‘¸Åê @‘°që á?‘¨»ì ‘ MÄN+MÄN+M¿NAM¬N¹ ‘˜ÄN¼RÝN¼R]O¦RsO“R¹ ‘€í ‘ø~9  ñ?‘à~B ! ñ?‘Ð~K " ñ?‘À~T  @¶¼RŠ]ÕRŠ]aSq]wS^]6 Q ‘¨~8 Q ‘ ~íQ ‘˜~9 R ñ?‘€~B R ñ?‘ð}K R ñ?‘à}¹T ‘Ð}T S @ðŠ] e£] e"x @‘È}û y @‘À}Ù]eï]ód6 † ‘¸}8 † ‘°}í† ‘¨}ö ‡ ‘ }_ ˆ ñ?‘}ñ ˆ ñ?‘€}¹‰ ‘ø|e7n*e$n6 ± ‘è|8 ± ‘à|í± ‘Ø|¹³ ‘È|T ² @*€ + ÐåæV + @‘xÅ+ @‘p‚+ @‘`í- ‘Xz . ñ?‘@„ . ñ?‘°Ž . ñ?‘ ˜ . ñ?‘–   ÛÌåVº  @‘hq á?‘`Ä  j@‘XÐ  j@‘Pè  j@‘Hì  j@‘@p @‘¸s @‘°Å @‘¨ô  ‘ ÷  ‘˜ú  ‘ý  ‘ˆ  ‘€  ‘ø~  á?‘ð~  j@‘è~  j@‘à~µ e À AVQe ü?‘Pqg @‘Hph @‘@si @‘¸Áj @‘°Åk @‘¨»m ‘ *¦C¦p q @‘˜h¡~Žíw ‘¹x ‘ˆ¦X!¿X!¿S!Õ@!¹‡ ‘€X!q%q!q%ô!X% "E%¹› ‘è~íœ ‘à~9  ñ?‘Ð~B ž ñ?‘À~K Ÿ ñ?‘°~T š @dq%?0Š%?0&&0,&06 Æ ‘˜~8 Æ ‘~íÆ ‘ˆ~9 Ç ñ?‘ð}B Ç ñ?‘à}K Ç ñ?‘Ð}¹É ‘À}T È @ž?0¹7X0¹7"é @‘¸}û é @‘°}Ž0´7¤0¡76 ò ‘¨}8 ò ‘ }íò ‘˜}_ ó ñ?‘€}ñ ó ñ?‘ð|ö ô ‘è|¹ö ‘Ø|T õ @ØÂ7å@Ø7Ò@6  ‘È|8  ‘À|í ‘¸|¹ ‘°|T  @Å = æðïVº = á?‘xq= @‘pÄ = j@‘hÐ > j@‘`è > j@‘Xì > j@‘Pp> @‘Hs? @‘@Å? @‘¸ô A ‘°÷ A ‘¨ú A ‘ ý A ‘˜ A ‘ A ‘ˆ B @‘€ C j@‘ø~ C j@‘ð~Û ó§VQóü?‘hÃõ@‘`Áõ@‘XÅõ@‘P»ö‘Hq÷á?‘@*5*5%K¹ ‘¸*BCBŒ,¢¹) ‘ í* ‘˜9 + ñ?‘€B , ñ?‘ð~K - ñ?‘à~T ( @LBâ [â °É Æ¶ 6 Q ‘È~8 Q ‘À~íQ ‘¸~9 S ñ?‘ ~B S ñ?‘~K S ñ?‘€~¹T ‘ø}T R @†â Ò û Ò "m @‘ð}û n @‘è}1 Í G º 6 { ‘à}8 { ‘Ø}í{ ‘Ð}ö | ‘È}_ } ñ?‘°}ñ } ñ?‘ }¹~ ‘˜}Û ‡ñ t6   ‘ˆ}8   ‘€}í  ‘ø|¹¢ ‘è|T ¡ @Àí 0òíòV @‘xÅ@‘p‚@‘`ç @‘Xí‘Pz ñ?‘@„ ñ?‘°Ž ñ?‘ ˜ ñ?‘0ðï"òVº 0 @‘xq0á?‘pT 1j@‘hV 1j@‘`Ã1@‘XÅ1@‘P6 3‘H8 3‘@í3‘¸ 4á?‘°"5j@‘¨'¯@èÄûVQ¯ü?‘pñ@‘hÁ±@‘`ű@‘X7±@‘Pq² @‘H¥èüé¾èüé»¶‘@¾è÷éÔèäéí¼‘¸¹½‘°üé ëê ë»Ç‘¨êë+êòê¹Í‘  ë5í#ë5í»Ö‘˜eëí{ë í¹à‘ˆ9 á@‘ð~B á@‘à~K âñ?‘Ð~íä‘À~5íçòNíçò»ö‘°~ íÎò¼íµò¹‘ ~6 ‘˜~8 ‘~푈~9 ñ?‘ð}B ñ?‘à}K ñ?‘Ð}çò¡ûóÞö"@‘À}û @‘¸}»‘°}6óÙöRóÀö6 %‘¨}8 %‘ }í%‘˜}_ &ñ?‘€}ñ &ñ?‘ð|ö '‘è|¹)‘Ø|T (@úÞö¡û»<‘Ð|çö¡û÷ˆû6 F‘À|8 F‘¸|íF‘°|¹G‘¨|T E@4<ðòªõVº á?‘xq @‘pT j@‘hV j@‘`Ã@‘XÅ@‘P6 ‘H8 ‘@푸  @‘°"j@‘¨„=‰= ”=ï Mi?Â# Ui?Â# út?Â# ct?Â# Œ?Â#  Œ?Â#( ½i?Â#0 ¿š?Â#8 Ÿ?Â#@ Ú?Â#H i?Â#P Åi?Â#X ‚Ÿ?Â#` "i?Â#h v«?Â#p $«?Â#t eŸ?Â#x Ó²?Â#€ /Å?Â#° =Å?Â#¸ KÜ?Â#À UŸ?Â#È Yš?Â#Ð eš?Â#Ø qt?Â#à st?Â#è yt?Â#ð |t?Â#ø Ÿ?Â#€ š?Â#ˆ •6y?…?­e ‘? ™?i?¤?&â¤?¾?Ñ?»eÖ?ÆŸ?æ? …?R ¤?$Q‰=ñ?@æ?ñ?ñ?¾?*@*@¾?*@¾?*@¾?@¾?@ñ?¾?¾?«?´ Rš1€°õ%YF°õËõV Q$Q&g ÐõëõVu t‘xz)ðõdöVe){‘xÃ)’‘p»+—‘h“1pöËöVe1­‘xÃ1’‘p»3—‘h³9ÐöD÷Ve9­‘xÃ9’‘p9²‘`‚9²‘P»;—‘H¤€ ‹R — ¢… tš"FF$ ÄÝ2€P÷&Ë2]7 B… Mš"¤&Ð2Zÿ&Ë2¯&Ð2­ÿÛXP÷fûVÃX7‘ð_þX‘è_X‘à_‚ X7‘Ø_ÐZ2‘Ð_ [2‘È_Ë]2‘À_d‘¸_d‘°_d‘¨_uf7‘ _»f7‘˜_íf7‘_f7‘ˆ_!g‘€_)i7‘ø^-i7‘ð^2«ÀüVë7‘èŸþ«‘àŸ«‘ØŸ‚ «7‘ПЭ2‘ȟ˯2‘ÀŸu¶7‘¸Ÿ»¶7‘°Ÿí¶7‘¨Ÿ¶7‘ Ÿ!·‘˜ŸU¹‘ð_\¹‘ð¿)»7‘Ÿ-»7‘ˆŸ#c VÃ7‘x‘pu 7‘h¹ 7‘`† 7‘X#‰Cðû¿üVÃC7‘x«C‘p³C‘h¼C7‘`ÂC7‘X\C‘PuE7‘H»E7‘@#Ç3pûéûVÃ37‘x3‘p¼37‘hÂ37‘`U3‘Xu57‘P»57‘H77' ÿÒ åÝ4€ìc¿Vx븑p n$Q&¦±ÀV‘x릸‘p  ÃÓ¤ ÎÙ✠{5€•VeC‘xZ‘`gC‘XÃl‘P»l‘H2! Ve!‰‘x!Z‘`g!‰‘XÃ!l‘P»#l‘HH+•Ve+C‘x+Z‘`g+C‘XÃ+l‘P»-l‘H_4 Ve4‰‘x4Z‘`g4‰‘XÃ4l‘P»6l‘Hu=¶Ve=C‘x=Z‘`g=C‘X‚=Z‘@Ã=l‘¸»?l‘°FÀ,VeF‰‘xFZ‘`gF‰‘X‚FZ‘@ÃFl‘¸»Hl‘°¤O0ÉVeOC‘xOZ‘`¼O‰‘XgOC‘PÃOl‘H»Ql‘@¾XÐ>VeX‰‘xXZ‘`¼X‰‘XgX‰‘PÃXl‘H»Zl‘@Õa@ïVeaC‘xaZ‘`¼a‰‘XgaC‘PÃal‘H»cl‘@íjð^ Vej‰‘xjZ‘`¼j‰‘Xgj‰‘PÃjl‘H»ll‘@s` ´ VesC‘x½sl‘p¿sŽ‘hul‘`!ul‘X'ul‘P.vl‘H4vl‘@:vl‘¸Awl‘°Gwl‘¨Mwl‘ »xl‘˜Txl‘[zH‘ð~b•À ª Ve•C‘x½•“‘t¿•š‘h—“‘d!—“‘`'—“‘\.˜“‘X4˜“‘T:˜“‘PA™“‘LG™“‘HM™“‘D»š“‘@Tš“‘¼[œH‘H SR e$Q& w… ‚š"¤Zl“± }78€° !†; ÐGiL W… bš"¤‹&L° "VÅ&G‘x¹(­‘tQ û ../../include./Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/6.0/include/opt/local/include/usr/include/_typesfastsum_test.cinfft.hfastsum.hstddef.hnfft3.hfftw3.h_uint64_t.hcycle.h @ 6  j×°óó?óóóó»!!"‘"‘"‘"‘"‘"‘"‘"‘"‘"‘"‘"KP‹VËu¼hBõ/õZ­Zq>òu¼hBõ/õZ­º'­Y» &ö&å»#»»g»ªT-ôMíû ../../include./Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/6.0/include/opt/local/includefastsum.cinfft.hfastsum.hstddef.hnfft3.hfftw3.h ÐÖ *Ø= =jvs„ˆ÷.-kö úvyz€÷(  !È >Fö‰" à"à  ô($()[($()Ÿu­° (¹ Y;Ÿ£¢¢’Ÿ   »¼ ŸŸËô*½g;g®g®g®g®g®g®je )[/[Ÿ–}Ÿõ'*M×õ*/" À/3 Ÿ" ð/Ñ »ÉÉÉÊ÷ô 1ò Âó.=Bõ„tzòoXò °2 ƒ»»¤‘¢ #G{õ]"] X1óV÷'ù1óV÷ uñøó‹gOÒø{nXò(ó(  ð9ª ãõuF"øw ò>,øuF"ù7Döpò À=Ô (Z  >‹ *Ø= =j.-kö ú-†ù-†ù( Fë *Øô?2n¢ø5ˆz€÷%ƒ 0J¤ ƒ»»¤ E ò 1!c[33÷‰kt$ PM’ ,„'*Xo’Y}}!œwX Y}‚}+šuX rX¡K ÀTä pæÌ%¡Å¦× €TæÊ(wgJØÊˆ[ YYºÈ½ ^å »*Ì"$()Ÿu­Ž  dß gÛÊ wgBØÊš‚[š ‡YYX(' °h‚ u„(¼3ó5ó¼.ø$»¼Ÿ‘V  Pk ×5  k9 ­å„ #9û ../../includekernels.cinfft.h ðk( u>."6Bbr“Ÿ±¹Ù½ÃÁ? Àu u>.1ISaoy•™½ÁÃ?  |Ü u>.9CYow“—»¿£±›? °…ö @$.(IOO#O&O&&&&&(… Љ— @$.%*!!#%(… 0Œ³ @$.!#%&&&&(…  ŽÏ @$.((#('(+(2*… P‘ë @$.å!#%&&&(… °“‡ u>.-;O]ow“—»¿£±£? 𜡠u>$.$j–¶ÖôžÂî©ûåÙ… ®¼ "u[)ô7*l’´ÖöžÀî«ûãÙ„%  ¿Ü u>$.BvÕí–°Óó–¶Ùû… 0Ïø ?$.!#&&&&&&(…Bû assert.c °Ñ *·û /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/6.0/include../../includebessel_i0.cstddef.hinfft.h Ò¦ … Ÿ,(ó"%.  `Ó– &1 bS±û /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/6.0/include../../includeint.cstddef.hinfft.h PÔ É  pÔ ƒƒ„Ø»×Y  ÐÔ+ „„×É×˃ƒ!×Zר¹„ ÖÌ ô„Ø­­[ƒƒ!×ZØÙ¸­Û{û /usr/include/i386/usr/include/sys/_types../../includemalloc.c_types.h_size_t.hnfft3.h @× ½ׄÊZƒ  Ð×< » Ø/ »ØÉZ’ Ûû /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/6.0/include../../include/opt/local/includenfft.cstddef.hinfft.hnfft3.hfftw3.h `Ø“ ,&F–xX `:=5.;1¦š2#?tdt,  PÞÑ ,%F–xX X:=5.;1¦š2#?tft,  @ä± (<# F FB_з ö“  @è¯ 9æSxyX[St[*S7g!’#)Rož¼ô'\-‡chæ)Xkž#æ-•c_+•Xmž_•{ôÈXtž2  Ðûï åæ»-7ç”ö#39FB`9×·  ó -'æ&*d[ Szt [ *Zh»$# Akt¼"* "]‡cgå*) Gižæå V"-_+*•Giž\ "uô*ÈGpž'  °Æ åóåô»ì-*3M4|J5<<E9YZWxX eX]9‡r9Œt¢™y” sXö’  Àå $ååó»¾%SxyX[S˜["*7"]"hå*) "g*2õežæ"*7•"]‡cgå*)&”eg*2õbž!æ-•"]_+*•&`+*Ôõiž]•"uó*È1ó*Þõqž' A¤ ëåóåô»ç”ö#3M4|J5<<E9YZWxX eX]9‡r9Œt¢Ÿšy— sX  àKå 3åó»»ç&*d[ Sz˜ [* 7Zhå*)g*2 ìat"¼"*7 "]‡cgå*)&”eg*2 õ^ž%æå V"-_+*•&`+*Ôõcž\ "uó*È1ó*Þõmž' `ný' åóóåóô»ì-*3C4M7£$…>…OS[UEENEb$|9xrrrrrrstXX)PX1]9Šr9Œt9ŒtðàçÝçÝâsÚlXgXö’  0†«" &åóó»¼è8V{yX[V’[$*77V*&)h‘1)$'g*2$'g*2Ê[ž(æ$*77•V#-›ggå*)&¨ig*2&¨ig*2ÊWž,æ-•$]c+*•&d+*Ô&d+*ØÊ_ž"]•$uó*Ü1ó*ò1ó*òÊmž'  ¸€) ìåóóåóô»ç”ö#3C4M7£$…>…OS[UEENEb$|9xrrrrrrstXX)PX1]9Šr9Œt9ŒtóéçãçãßsÝlXgX  @Ðø% 5åó󻼿&*d[ Szý [!*7 7$])hå*)$'g*2$'g*2 ÊWž,¼$*77 V#-›ggå*)&¨ig*2&¨ig*2 ÊSž0æå V$-c+*•&d+*Ô&d+*ØÊ[ž&\ $uó*Ü1ó*ò1ó*òÊiž' Àý) »L××Ú˜ù”   ¾’ À“  ¾’ à£* »L××Ú˜ù” Àù  ¾’ àî ¾’ â* é3âyX  ò* è’lèx‹ pX   ù »8 € Ç #1 0 + ê’"lˆ!yXrX  Ö+   :FØ"* wا"(d1y4 !q‚ †, »‘‘‘‘ °ô, ¼¼)¼Ï¯Z¯®»‘ ’, ¾&3Y%’.,?"$$$G<Á$ƒƒ  ž- ,»»¼Ÿ »‘ p!¸- 4»»¼Ÿ »‘ À"Ñ- h #Ú- ,gg%  p#ã- 0ggg%  ð#í- …4’&Y’zX$/’%4‘vX ƒ Ð%Š. ½óôôôôôóóó (1 õƒ )Ì*  #/2£xX  à*Î 1 jZ%xX sXK Ð-ê "Õ8XÖ¥evXKA[XX›evXKA[XÆ$ 5¹ -%b!X1tS% wÖÅbd14X1Xx._X% wÖrDo-Xµbd14X1Xx._X% wÖÄCo-Xµbd14X1X% wÖè=ï-Xµbd14X1X% wÖËbd14X'S à[þ 5¹ -%`!X1tS% wÖÅ`d14X1Xx._X% wÖrDo-Xµ`d14X1Xx._X% wÖÄCo-Xµ`d14X1X% wÖè=ï-Xµ`d14X1X% wÖË`d14X'S €€‹ "Ò8XÖ¥evXKA[XX›evXKA[X$ à‰«   =áF smkX €‹·  m­­®7))-­-­I-qzX-vX -[-­-­I4q;qwX -sX 2Z-­4­I-qzX-­?-qzX-oX-[-­4­I4q;qwX -­?4q1qwX -iX7Z4­-­I-qzX-vX -­-­B-qzX-vX -Z4­-­I4q;qwX -sX-­-­B4q4qwX -sX2Z4­4­I-qzX-­?-qzX-oX-­4­B-qzX-­8-qzX-oX-Z4­4­I4q;qwX -­?4q1qwX -iX-­4­B4q4qwX -­84q*qwX -iX< P³ü !YƒYg$­­  ´Ð (  ´ X­­®#&&Ê*­*­F*qzX-vX -[*­*­F1q8qwX -sX 2Z*­1­F*qzX-­<*qzX-oX-[*­1­F1q8qwX -­<1q.qwX -iX7Z1­*­F*qzX-vX -­*­B*qzX-vX -Z1­*­F1q8qwX -sX-­*­B1q4qwX -sX2Z1­1­F*qzX-­<*qzX-oX-­1­B*qzX-­8*qzX-oX-Z1­1­F1q8qwX -­<1q.qwX -iX-­1­B1q4qwX -­81q*qwX -iX<  Û™ F­®. ××$­**fzX'Z$­*.ffwX ,ZØ(­**fzX'­&*fzX'[(­*.ffwX '­&.ffwX 1  Ðå« !YƒYg$­­  æ¿ ;­®  Ê××$­'$`zX'Z$­'(``wX ,ZØ(­'$`zX'­#$`zX'[(­'(``wX '­#(``wX 1¨y +„(Ø7O[;OO  0ò„ ÌY­­  ðò˜ +„(Ø{O[OO ?²û ../../include/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/6.0/includerand.cinfft.hstddef.h °õ L Ðõ  ¼” ðõ) õ5 pö1 õ Ðö9 )ü²û /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/6.0/include../../includesort.cstddef.hinfft.h P÷Ø <­Ø ¬vר `%g­U #%q×רZo pû3  ðûà (*  Àü« <® ¬v `%g­'LzX# %{6v8YwX    ½ŸPXUXY×YwX šdû ../../include/usr/include/_typestime.cinfft.hcycle.h_uint64_t.h  óL À¥ º:¸µû ../../include/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/6.0/includevector3.cinfft.hstddef.h  D  !   + D  4   = _ ÀÆ % 0Ï T ÐØ ) @á j ðê ) ` ó ô$9&6$ywX vX kX À • ìõØõ%'$yúwX òvX òkXòÒ´û /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/6.0/include../../includewindow.cstddef.hinfft.h ° & ƒ>,T}y}ƒvÐ~†1¡1t¡1§1v¸ø34u44vØ~R e ue x v@ÚPêPuêPQv@ÑRàRràRàRvð~ `ˆ`}ˆ`Þ`vøzº„8…}8…Ž…vøzGüaüraügüvðrír v°oJÈdÈrdÈjÈvØpÈÒâÒrâÒèÒv o2wLwrLwRwv€v9{S{rS{Y{vÀuìŒr v sÌIæIræIìIvðuîMNrNNv°ufX€Xr€X†Xv˜tš_´_r´_º_vsa*{*r{**v¸yˆ,¢,r¢,¨,v y³5Í5rÍ5Ó5v°x 'r'-v˜x¾ØrØÞvàw›&main<›œ&regkernÏkubintkernÎfastsum_init_gururfastsum_finalizeŸfastsum_exactfastsum_precomputeqfastsum_trafoÿSearchTreeÚkubintkern1ØSearchBoxYcalc_SearchBoxŠ regkern3 regkern1¶ BuildTreeQ quicksort BuildBoxå max_i( BasisPoly  fakÎ binomî7„&gaussian¡multiquadric inverse_multiquadricslogarithmÍthinplate_spline'one_over_squareone_over_modulusÛone_over_x5inverse_multiquadric3¤sinc_kernelcosc’kcotone_over_cube)»†&nfftl_assertion_failedqA&N1UM1bN2oM2|Q2»P2ÐQ1ñP1nfftl_bessel_i0‹evaluate_chebyshevf^!®&nfftl_exp2irnfftl_log2i½nfftl_next_power_of_2$nfftl_next_power_of_2_expy #w&nfftl_malloc_hookvnfftl_free_hook¤nfftl_die_hookãnfftl_malloc nfftl_freeKnfftl_dieJƒ$…@&nfftl_trafo_direct„nfftl_adjoint_directånfftl_trafo_1dnfftl_adjoint_1dÿnfftl_trafo_2d¥nfftl_adjoint_2dKnfftl_trafo_3dá nfftl_adjoint_3dw nfftl_trafo¤ nfftl_adjointÑ nfftl_precompute_lin_psi+nfftl_precompute_fg_psi¸nfftl_precompute_psicnfftl_precompute_full_psiûnfftl_precompute_one_psi(nfftl_init‘nfftl_init_guru6nfftl_init_linênfftl_init_1dDnfftl_init_2d­nfftl_init_3d%nfftl_checkvnfftl_finalize²init_helpbprecompute_phi_hut­intprod0uo·sortásort0ºD_TæD_serial_T`B_TŒB_serial_TB_A3B_serial_A®D_AÚD_serial_ATnfft_adjoint_3d_Bónfft_3d_init_fg_exp_l‹nfft_adjoint_3d_compute_serial5!uo2¬!nfft_adjoint_B_compute_full_psiè"nfft_trafo_3d_Bÿ&nfft_trafo_3d_compute§(nfft_adjoint_2d_BE,nfft_2d_init_fg_exp_lÝ,nfft_adjoint_2d_compute_serial.nfft_trafo_2d_B:2nfft_trafo_2d_computeo3nfft_adjoint_1d_Bú6nfft_1d_init_fg_exp_l¡7nfft_adjoint_1d_compute_serialf8nfft_trafo_1d_Bº<nfft_trafo_1d_computeˆe¸&nfftl_drand48Xnfftl_srand48ƒnfftl_vrand_unit_complexÊnfftl_vrand_shifted_unit_doublenfftl_vrand_realöÀf(&tmaxTradix_maskatmaxmradix_maskznfftl_sort_node_indices_radix_lsdf–nfftl_sort_node_indices_radix_msdf¢sort_node_indices_sort_bubblesort_node_indices_radix_rearrangesort_node_indices_radix_count4èjÖ&nfftl_elapsed_secondsuelapsedW¾k &nfftl_upd_axpy_complex‰nfftl_upd_axpy_doubleìnfftl_upd_xpay_complexOnfftl_upd_xpay_double²nfftl_upd_axpby_complex%nfftl_upd_axpby_double˜nfftl_upd_xpawy_complex nfftl_upd_xpawy_doubleznfftl_upd_axpwy_complexënfftl_upd_axpwy_double\nfftl_fftshift_complexRnfftl_fftshift_complex_int%^rµ&m2K_pnfftl_m2K›ÚintëcharC"complex)R4long doubleEfastsum_planPfastsum_plan_kernelunsigned intnfftl_plan÷_INTptrdiff_t long intfftwl_complexIintPfftwl_plan}ticksˆuint64_t“long long unsigned intÙ›œ½CÈcomplex! intŽ R™ long double kernelNfastsum_planYfastsum_plan_unsigned intnfftl_planõ_INTptrdiff_t long intfftwl_complexGintNfftwl_plan>7„Cšcomplex`Rklong doublerint»†wchar~intOA8INTCptrdiff_tNlong int¢R­long double´int1^!®UINT`ptrdiff_tklong int¤ #w<nfftl_malloc_type_functionYsize_td__darwin_size_tolong unsigned intŒnfftl_free_type_functionºnfftl_die_type_functionÜchar¼ƒ$…@ocharINTptrdiff_t)long int‰=nfftl_plani?_INTy?fftwl_complex…?complex¤?long double«?unsigned int¾?intÅ?fftwl_planæ?Cñ?R*@intYe¸FRQlong doubletlong int€C‹complex—INT¢ptrdiff_t9Àf(7INTBptrdiff_tMlong int intaèjÖcRnlong double±double¸ticksÃuint64_tÎlong long unsigned inta¾k HCScomplexZRelong doublelINTwptrdiff_t‚long int“intA^rµLINTWptrdiff_tblong intiint­intApple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)fastsum_test.c/Network/Servers/server.keiner.selfip.net/Users/jens/Programming/nfft/applications/fastsummainargcargvjkdNMnmpskernelcmy_fastsum_plandirectt0t1timeerroreps_Ieps_Br_maxr2intcharCcomplexRlong doublefastsum_planfastsum_plan_N_totalM_totalalphafxykernel_paramflagspre_Kbmv1mv2AdAddfft_planbox_countbox_count_per_dimbox_offsetbox_xbox_alphaMEASURE_TIME_tunsigned intnfftl_planf_hatmv_trafomv_adjointsigman_totalKfftw_flagsmy_fftw_plan1my_fftw_plan2c_phi_invpsipsi_index_gpsi_index_fgg_hatg1g2spline_coeffsindex_x_INTptrdiff_tlong intfftwl_complexfftwl_planfftwl_plan_sticksuint64_tlong long unsigned intfastsum.cregkernxxparamarsumkubintkernc1c2c3c4f0f1f2f3fastsum_init_guruthsnntsort_flags_trafosort_flags_adjointdeltafastsum_finalizefastsum_exactfastsum_precomputefastsum_trafoymaxSearchTreexminxmaxMinMaxMedianlEresultkubintkern1SearchBoxvaly_indmultiindexcalc_SearchBoxstartend_ltregkern3regkern1BuildTreequicksortlposrpospivottemp1temp2BuildBoxbox_indexindmax_iBasisPolyfakbinomkernels.cgaussiandervaluemultiquadricinverse_multiquadriclogarithmthinplate_splineone_over_squareone_over_modulusone_over_xinverse_multiquadric3sinc_kernelcoscsignkcotone_over_cubeassert.c/Network/Servers/server.keiner.selfip.net/Users/jens/Programming/nfft/kernel/utilnfftl_assertion_failedlinefilebessel_i0.cN1INTM1N2M2Q2P2Q1P1nfftl_bessel_i0evaluate_chebyshevint.cnfftl_exp2infftl_log2immnfftl_next_power_of_2ilognN_is_not_power_of_2nfftl_next_power_of_2_expmalloc.cnfftl_malloc_hooknfftl_malloc_type_functionsize_t__darwin_size_tlong unsigned intnfftl_free_hooknfftl_free_type_functionnfftl_die_hooknfftl_die_type_functionnfftl_mallocnfftl_freenfftl_dienfft.c/Network/Servers/server.keiner.selfip.net/Users/jens/Programming/nfft/kernel/nfftnfftl_trafo_directk_Lomegat2nfftl_adjoint_directnfftl_trafo_1df_hat1f_hat2g_hat1g_hat2c_phi_inv1c_phi_inv2nfftl_adjoint_1dnfftl_trafo_2dk0k1n0n1N0c_phi_inv01c_phi_inv02c_phi_inv11c_phi_inv12ck01ck02ck11ck12g_hat11f_hat11g_hat21f_hat21g_hat12f_hat12g_hat22f_hat22nfftl_adjoint_2dnfftl_trafo_3dk2n2c_phi_inv21c_phi_inv22ck21ck22g_hat111f_hat111g_hat211f_hat211g_hat121f_hat121g_hat221f_hat221g_hat112f_hat112g_hat212f_hat212g_hat122f_hat122g_hat222f_hat222nfftl_adjoint_3dnfftl_trafonfftl_adjointnfftl_precompute_lin_psistepnfftl_precompute_fg_psiuonfftl_precompute_psiljnfftl_precompute_full_psil_Llprodixix_oldnfftl_precompute_one_psinfftl_initnfftl_init_gurunfftl_init_linnfftl_init_1dnfftl_init_2dnfftl_init_3dN3nfftl_checknfftl_finalizeinit_helpWINDOW_idx_nprecompute_phi_hutksintprodvecuoupopact_dimxjsortsort0local_x_numlocal_xar_xhelprhighar_x_tempnprodu_jD_TD_serial_TB_TB_serial_Tfjl_fglj_fgtmpEXP1tmpEXP2tmpEXP2sqtmp1tmp2tmp3ip_wip_uip_sfg_exp_lB_AB_serial_AD_AD_serial_Anfft_adjoint_3d_Bfg_psij0fg_psij1fg_psij2psij_constip_ynfft_3d_init_fg_exp_lfg_exp_b0fg_exp_b1fg_exp_b2fg_exp_b0_sqnfft_adjoint_3d_compute_serialpsij_const0psij_const1psij_const2xj0xj1xj2u0o0l0u1o1l1u2o2l2gjpsij0psij1psij2uo2nfft_adjoint_B_compute_full_psinfft_trafo_3d_Bnfft_trafo_3d_computenfft_adjoint_2d_Bnfft_2d_init_fg_exp_lnfft_adjoint_2d_compute_serialnfft_trafo_2d_Bnfft_trafo_2d_computenfft_adjoint_1d_Bnfft_1d_init_fg_exp_lnfft_adjoint_1d_compute_serialpsijnfft_trafo_1d_Bm2p2nfft_trafo_1d_computerand.cnfftl_drand48nfftl_srand48seednfftl_vrand_unit_complexnfftl_vrand_shifted_unit_doublenfftl_vrand_realsort.ctmaxradix_masknfftl_sort_node_indices_radix_lsdfkeys0keys1rhigh_infromtotmphlcountstidtnumnfftl_sort_node_indices_radix_msdfcountsdisplssort_node_indices_sort_bubblekeystisort_node_indices_radix_rearrangekeys_inkeys_outshiftmasksort_node_indices_radix_counttime.cnfftl_elapsed_secondselapseddoublevector3.cnfftl_upd_axpy_complexnfftl_upd_axpy_doublenfftl_upd_xpay_complexnfftl_upd_xpay_doublenfftl_upd_axpby_complexnfftl_upd_axpby_doublenfftl_upd_xpawy_complexwnfftl_upd_xpawy_doublenfftl_upd_axpwy_complexnfftl_upd_axpwy_doublenfftl_fftshift_complexd_pred_actd_postN_preN_actN_postk_prek_actk_postk_swapx_swapnfftl_fftshift_complex_intwindow.cm2K_nfftl_m2KHSAHD‰  !"#ÿÿÿÿ&'(ÿÿÿÿ,ÿÿÿÿ0257;=>ÿÿÿÿ?BCEHKLMOPÿÿÿÿSVZ_defgjmrtux{}ÿÿÿÿ‚„ÿÿÿÿ…†@Ic5œêD«¡ìmZ]mPÔ½%òÕÂÕ/‹T=;ƒ÷QcceÇúAídðd(`dNÎ\t&û™ ÖrLKb3ˆ‡*ˆž|HêWlÀ€$Õð•ÄÞ=Ô^êWl& r«çtYkæ 5ètY$Û5hkhàe”—!Œ›åêÒ:|ctY£ë’—dtYÙdà­¦ÿp jš|òѬ0¹Ž¬m@•|tsr2+yöo™|žK'âÜÑPT Ad€&^Î4ˆìú×'%Ìx'؇ ÏŠæbóc5ô¤úÊè!†©à‡ å-EvlŸÙþ$¨¦úÊ®NHrç–š}0+u>î*u>Š [b¦Îk·qˆ À·IbPˆ¼ÉyY¹ÿp }t&ûއiQZö}¬VÔK¯;t&ûŒÑˆ9 k™í™îÑPG'êWlq\îe›ŠÝk)ËÉ÷hàÆtY:؇ Š4­öšøøÇtY³ˆ »Éû!†øK>„tYœÍ¼à‡ x“—”Â^ñ…tYâÆi§ûŸë«¼^9FøKÜÅžûùXÄ ‘E¬ù`!Û¢UG*BóÞv޳™|¢ç¯*ƒØßˆxE?O™Ô&V÷mž|Õ<†aêý̶&»*þ&N-zUs¡5 .Ï©R€èøÂ ÌÓdjtwâP®òãmF¸X1‹ï4õhÍòãB\Õóªê+u>OÐWTxˆ˜¨¸ÈØèø(8HXhxŒœ¬¼ÌÜìü ,<L\l|Œœ¬¼ÌÜìü ,<L\l|Œœ¬¼ÌÜìü  , < L \ l | Œ œ ¬ ¼ Ì Ü ì ü  , < L \ l | Œ œ ¬ ¼ Ì Ü ì ü  , < L \ l | Œ œ ¬ ¼ Ì Ü ì ü  , < L \ l | Œ œ ¬ ¼ Ì Ü ì ü  , < L ` p €   ° À Ð à ð X ‚Kð ¨7upm‰Äií }[j££ ¶ ]kò '2s¼]ý(+-™ «4øu Ëæf!gß 07i8 ‚#^ d:à m6D„! Éš ½ãmÛ:gH kG 58ìk–'é\ °„ ¶=ª&' ×?Û òWZJ‚"NÛdÉ€ ÈP•: G 2°#ÜA¬i¤Vn Š=ÇPjY.eH» ]? 1??i9 09 ®2?%€ ~48l Î, h'$\³2#¨;f,$ü ù7E ³9¯ <Õ d/_"æ ú1Õ8oJ†(¥ Dí©oÏØ±äkÑ Ç6d vCQQbq2Vh2 « ã;¸#ôü$ ¸EžÃ  i;Áÿg³fœ =;µ —RÔ©$ £2GlPÐ!+Ì û“Òe¾Çnn *M# å8cbig`e†„r_ m[ìHªlR æ3´ ¹5Y ::( /Fô&Yï#<=aÒáp T2Ðg-gñª¤ 5qW$: ;3Å ½V– `Q‹Îr ^˜€[‚)z‹eHSAH  ÿÿÿÿÿÿÿÿÿÿÿÿ ŸeO}’PÍ“<²µà&ïÐó‡ 0€ˆ ÃamP¶›leÓèµë‚‰Ob ìvº£\íSc •| [=ù÷µoh’|†Û».–U“òÐæ‡VM1LÉP½|5û­{Õû8e‡´Ë$¿áE“á;ªÁØ'‹¸ÚIk‚™»Ò­/5²/5üc/52E†„Þk醄Þkâ$ÁþΩ$ÁþÎ.d$ÁþÎçp#)פÖyDœ9 ³!Dœ9 –9Dœ9 ŸfDœ9 ÷fDœ9 *rDœ9 ªrDœ9  Ú$¤(: I$¤(: ¼$¤(: â$¤(: ©$¤(: 9$¤(: õ$¤(: Ad$¤(: ­d$¤(: àj$¤(: Qr$¤(: Çr$¤(: s$¤(: Ó}7÷* k7÷*&4$„,ó/4$„,ó/¢$„,ó/î$„,ó/'d$„,ó/Ye$„,ó/Vk$„,ó/#r$„,ó/"$‘.Þ¬c$‘.Þ¬Ñ$‘.Þ¬d$‘.Þ¬“f$‘.Þ¬r$‘.Þ¬\±‡ X\±‡ Æ\±‡ id\±‡ ˆf\±‡ r\±‡ »P œ…é œ…Hd œ…ï}7hÓ°}7hÓ b}7hÓ¤ $,}˜¦$,}˜$,}˜É!$,}˜¬9$,}˜|f$,}˜ g$,}˜@r$,}˜Àr$,}˜AÆ#êä‚ÅH#Ps²Hë$W×{“2$W×{“è#$W×{“ò7$W×{“ ™k$Ÿ­d$)k±‡ )k±‡ —k±‡ ãk±‡ tdk±‡ Nek±‡ Kkk±‡ rk±‡ •÷cy“cy“ìccy“ËzSKt¥zSKtš {GnI›{GnI„{GnI¾!{GnI¡9{GnIªf{GnIg{GnI5r{GnIµr{GnIÙˆö¦æ«kö¦æàe#‡6A‡˜#Ú³í?P¥¯çô¥¯ç÷{#$1à ºâ“$¡'E¶k$¡'EHSAH ÿÿÿÿHSAH ÿÿÿÿnfft-3.3.2/applications/fastsum/fastsum_test.m000066400000000000000000000030621300072027400215170ustar00rootroot00000000000000% Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 % Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. % % Simple test program for fast NFFT-based summation algorithm. % Markus Fenn, 2006. % d=2; % N=4000; % M=4000; % n=128; % m=4; % p=3; % kernel='multiquadric'; % c=1/sqrt(N); % % system(sprintf('./fastsum_test %d %d %d %d %d %d %s %e',d,N,M,n,m,p,kernel,c)); N = 2000; M = 2000; kernel = 'multiquadric'; c = 1/sqrt(N); m = 4; p = 3; n = 156; eps_I = p/n; eps_B = 1/16; %random source nodes in circle of radius 0.25-eps_B/2 r = sqrt(rand(N,1))*(0.25-eps_B/2); phi = rand(N,1)*2*pi; x = [r.*cos(phi) r.*sin(phi)]; %random coefficients alpha = rand(N,1)+i*rand(N,1); %random target nodes in circle of radius 0.25-eps_B/2 r = sqrt(rand(M,1))*(0.25-eps_B/2); phi = rand(M,1)*2*pi; y = [r.*cos(phi) r.*sin(phi)]; %fast NFFT-based summation [f,f_direct] = fastsum(x,alpha,y,kernel,c,m,n,p,eps_I,eps_B); nfft-3.3.2/applications/fastsum/kernels.c000066400000000000000000000626741300072027400204450ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /*! \file kernels.c * \brief File with predefined kernels for the fast summation algorithm. */ #include "config.h" #include #include #include #ifdef HAVE_COMPLEX_H #include #endif #include "kernels.h" /** * \addtogroup applications_fastsum * \{ */ C gaussian(R x, int der, const R *param) /* K(x)=EXP(-x^2/c^2) */ { R c = param[0]; R value = K(0.0); switch (der) { case 0 : value = EXP(-x*x/(c*c)); break; case 1 : value = -K(2.0)*x/(c*c)*EXP(-x*x/(c*c)); break; case 2 : value = K(2.0)*EXP(-x*x/(c*c))*(-c*c+K(2.0)*x*x)/(c*c*c*c); break; case 3 : value = -K(4.0)*x*EXP(-x*x/(c*c))*(-K(3.0)*c*c+K(2.0)*x*x)/(c*c*c*c*c*c); break; case 4 : value = K(4.0)*EXP(-x*x/(c*c))*(K(3.0)*c*c*c*c-K(12.0)*c*c*x*x+K(4.0)*x*x*x*x)/(c*c*c*c*c*c*c*c); break; case 5 : value = -K(8.0)*x*EXP(-x*x/(c*c))*(K(15.0)*c*c*c*c-K(20.0)*c*c*x*x+K(4.0)*x*x*x*x)/POW(c,K(10.0)); break; case 6 : value = K(8.0)*EXP(-x*x/(c*c))*(-K(15.0)*c*c*c*c*c*c+K(90.0)*x*x*c*c*c*c-K(60.0)*x*x*x*x*c*c+K(8.0)*x*x*x*x*x*x)/POW(c,K(12.0)); break; case 7 : value = -K(16.0)*x*EXP(-x*x/(c*c))*(-K(105.0)*c*c*c*c*c*c+K(210.0)*x*x*c*c*c*c-K(84.0)*x*x*x*x*c*c+K(8.0)*x*x*x*x*x*x)/POW(c,K(14.0)); break; case 8 : value = K(16.0)*EXP(-x*x/(c*c))*(K(105.0)*c*c*c*c*c*c*c*c-K(840.0)*x*x*c*c*c*c*c*c+K(840.0)*x*x*x*x*c*c*c*c-K(224.0)*x*x*x*x*x*x*c*c+K(16.0)*x*x*x*x*x*x*x*x)/POW(c,K(16.0)); break; case 9 : value = -K(32.0)*x*EXP(-x*x/(c*c))*(K(945.0)*c*c*c*c*c*c*c*c-K(2520.0)*x*x*c*c*c*c*c*c+K(1512.0)*x*x*x*x*c*c*c*c-K(288.0)*x*x*x*x*x*x*c*c+K(16.0)*x*x*x*x*x*x*x*x)/POW(c,K(18.0)); break; case 10 : value = K(32.0)*EXP(-x*x/(c*c))*(-K(945.0)*POW(c,K(10.0))+K(9450.0)*x*x*c*c*c*c*c*c*c*c-K(12600.0)*x*x*x*x*c*c*c*c*c*c+K(5040.0)*x*x*x*x*x*x*c*c*c*c-K(720.0)*x*x*x*x*x*x*x*x*c*c+K(32.0)*POW(x,K(10.0)))/POW(c,K(20.0)); break; case 11 : value = -K(64.0)*x*EXP(-x*x/(c*c))*(-K(10395.0)*POW(c,K(10.0))+K(34650.0)*x*x*c*c*c*c*c*c*c*c-K(27720.0)*x*x*x*x*c*c*c*c*c*c+K(7920.0)*x*x*x*x*x*x*c*c*c*c-K(880.0)*x*x*x*x*x*x*x*x*c*c+K(32.0)*POW(x,K(10.0)))/POW(c,K(22.0)); break; case 12 : value = K(64.0)*EXP(-x*x/(c*c))*(K(10395.0)*POW(c,K(12.0))-K(124740.0)*x*x*POW(c,K(10.0))+K(207900.0)*x*x*x*x*c*c*c*c*c*c*c*c-K(110880.0)*x*x*x*x*x*x*c*c*c*c*c*c+K(23760.0)*x*x*x*x*x*x*x*x*c*c*c*c-K(2112.0)*POW(x,K(10.0))*c*c+K(64.0)*POW(x,K(12.0)))/POW(c,K(24.0)); break; default : value = K(0.0); } return value; } C multiquadric(R x, int der, const R *param) /* K(x)=SQRT(x^2+c^2) */ { R c=param[0]; R value=K(0.0); switch (der) { case 0 : value=SQRT(x*x+c*c); break; case 1 : value=K(1.0)/(SQRT(x*x+c*c))*x; break; case 2 : value=c*c/SQRT(POW(x*x+c*c,K(3.0))); break; case 3 : value=-K(3.0)*x*c*c/SQRT(POW(x*x+c*c,K(5.0))); break; case 4 : value=K(3.0)*c*c*(K(4.0)*x*x-c*c)/SQRT(POW(x*x+c*c,K(7.0))); break; case 5 : value=-K(15.0)*x*c*c*(K(4.0)*x*x-K(3.0)*c*c)/SQRT(POW(x*x+c*c,K(9.0))); break; case 6 : value=K(45.0)*c*c*(K(8.0)*x*x*x*x-K(12.0)*x*x*c*c+c*c*c*c)/SQRT(POW(x*x+c*c,K(11.0))); break; case 7 : value=-K(315.0)*x*c*c*(K(8.0)*x*x*x*x-K(20.0)*x*x*c*c+K(5.0)*c*c*c*c)/SQRT(POW(x*x+c*c,K(13.0))); break; case 8 : value=K(315.0)*c*c*(K(64.0)*x*x*x*x*x*x-K(240.0)*x*x*x*x*c*c+K(120.0)*x*x*c*c*c*c-K(5.0)*c*c*c*c*c*c)/SQRT(POW(x*x+c*c,K(15.0))); break; case 9 : value=-K(2835.0)*x*c*c*(K(64.0)*x*x*x*x*x*x-K(336.0)*x*x*x*x*c*c+K(280.0)*x*x*c*c*c*c-K(35.0)*c*c*c*c*c*c)/SQRT(POW(x*x+c*c,K(17.0))); break; case 10 : value=K(14175.0)*c*c*(K(128.0)*x*x*x*x*x*x*x*x-K(896.0)*x*x*x*x*x*x*c*c+K(1120.0)*x*x*x*x*c*c*c*c-K(280.0)*x*x*c*c*c*c*c*c+K(7.0)*c*c*c*c*c*c*c*c)/SQRT(POW(x*x+c*c,K(19.0))); break; case 11 : value=-K(155925.0)*x*c*c*(K(128.0)*x*x*x*x*x*x*x*x-K(1152.0)*x*x*x*x*x*x*c*c+K(2016.0)*x*x*x*x*c*c*c*c-K(840.0)*x*x*c*c*c*c*c*c+K(63.0)*c*c*c*c*c*c*c*c)/SQRT(POW(x*x+c*c,K(21.0))); break; case 12 : value=K(467775.0)*c*c*(K(1260.0)*x*x*c*c*c*c*c*c*c*c-K(21.0)*POW(c,K(10.0))+K(512.0)*POW(x,K(10.0))-K(5760.0)*x*x*x*x*x*x*x*x*c*c+K(13440.0)*x*x*x*x*x*x*c*c*c*c-K(8400.0)*x*x*x*x*c*c*c*c*c*c)/SQRT(POW(x*x+c*c,K(23.0))); break; default : value=K(0.0); } return value; } C inverse_multiquadric(R x, int der, const R *param) /* K(x)=1/SQRT(x^2+c^2) */ { R c=param[0]; R value=K(0.0); switch (der) { case 0 : value=K(1.0)/SQRT(x*x+c*c); break; case 1 : value=-K(1.0)/(SQRT(POW(x*x+c*c,K(3.0))))*x; break; case 2 : value=(K(2.0)*x*x-c*c)/SQRT(POW(x*x+c*c,K(5.0))); break; case 3 : value=-K(3.0)*x*(K(2.0)*x*x-K(3.0)*c*c)/SQRT(POW(x*x+c*c,K(7.0))); break; case 4 : value=K(3.0)*(K(8.0)*x*x*x*x-K(24.0)*x*x*c*c+K(3.0)*c*c*c*c)/SQRT(POW(x*x+c*c,K(9.0))); break; case 5 : value=-K(15.0)*x*(K(8.0)*x*x*x*x-K(40.0)*x*x*c*c+K(15.0)*c*c*c*c)/SQRT(POW(x*x+c*c,K(11.0))); break; case 6 : value=K(45.0)*(K(16.0)*x*x*x*x*x*x-K(120.0)*x*x*x*x*c*c+K(90.0)*x*x*c*c*c*c-K(5.0)*c*c*c*c*c*c)/SQRT(POW(x*x+c*c,K(13.0))); break; case 7 : value=-K(315.0)*x*(K(16.0)*x*x*x*x*x*x-K(168.0)*x*x*x*x*c*c+K(210.0)*x*x*c*c*c*c-K(35.0)*c*c*c*c*c*c)/SQRT(POW(x*x+c*c,K(15.0))); break; case 8 : value=K(315.0)*(K(128.0)*x*x*x*x*x*x*x*x-K(1792.0)*x*x*x*x*x*x*c*c+K(3360.0)*x*x*x*x*c*c*c*c-K(1120.0)*x*x*c*c*c*c*c*c+K(35.0)*c*c*c*c*c*c*c*c)/SQRT(POW(x*x+c*c,K(17.0))); break; case 9 : value=-K(2835.0)*x*(K(128.0)*x*x*x*x*x*x*x*x-K(2304.0)*x*x*x*x*x*x*c*c+K(6048.0)*x*x*x*x*c*c*c*c-K(3360.0)*x*x*c*c*c*c*c*c+K(315.0)*c*c*c*c*c*c*c*c)/SQRT(POW(x*x+c*c,K(19.0))); break; case 10 : value=K(14175.0)*(K(256.0)*POW(x,K(10.0))-K(5760.0)*x*x*x*x*x*x*x*x*c*c+K(20160.0)*x*x*x*x*x*x*c*c*c*c-K(16800.0)*x*x*x*x*c*c*c*c*c*c+K(3150.0)*x*x*c*c*c*c*c*c*c*c-K(63.0)*POW(c,K(10.0)))/SQRT(POW(x*x+c*c,K(21.0))); break; case 11 : value=-K(155925.0)*x*(K(256.0)*POW(x,K(10.0))-K(7040.0)*x*x*x*x*x*x*x*x*c*c+K(31680.0)*x*x*x*x*x*x*c*c*c*c-K(36960.0)*x*x*x*x*c*c*c*c*c*c+K(11550.0)*x*x*c*c*c*c*c*c*c*c-K(693.0)*POW(c,K(10.0)))/SQRT(POW(x*x+c*c,K(23.0))); break; case 12 : value=K(467775.0)*(K(231.0)*POW(c,K(12.0))+K(190080.0)*x*x*x*x*x*x*x*x*c*c*c*c-K(16632.0)*x*x*POW(c,K(10.0))-K(295680.0)*x*x*x*x*x*x*c*c*c*c*c*c+K(138600.0)*x*x*x*x*c*c*c*c*c*c*c*c+K(1024.0)*POW(x,K(12.0))-K(33792.0)*POW(x,K(10.0))*c*c)/SQRT(POW(x*x+c*c,K(25.0))); break; default : value=K(0.0); } return value; } C logarithm(R x, int der, const R *param) /* K(x)=LOG |x| */ { R value=K(0.0); (void)param; if (FABS(x) #endif #include "nfft3.h" #include "infft.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** * \addtogroup applications_fastsum * \{ */ C gaussian(R x, int der, const R *param); /* K(x)=exp(-x^2/c^2) */ C multiquadric(R x, int der, const R *param); /* K(x)=sqrt(x^2+c^2) */ C inverse_multiquadric(R x, int der, const R *param); /* K(x)=1/sqrt(x^2+c^2) */ C logarithm(R x, int der, const R *param); /* K(x)=log |x| */ C thinplate_spline(R x, int der, const R *param); /* K(x) = x^2 log |x| */ C one_over_square(R x, int der, const R *param); /* K(x) = 1/x^2 */ C one_over_modulus(R x, int der, const R *param); /* K(x) = 1/|x| */ C one_over_x(R x, int der, const R *param); /* K(x) = 1/x */ C inverse_multiquadric3(R x, int der, const R *param); /* K(x) = 1/sqrt(x^2+c^2)^3 */ C sinc_kernel(R x, int der, const R *param); /* K(x) = sin(cx)/x */ C cosc(R x, int der, const R *param); /* K(x) = cos(cx)/x */ C kcot(R x, int der, const R *param); /* K(x) = cot(cx) */ C one_over_cube(R x, int der, const R *param); /* K(x) = 1/x^3 */ /* \} */ #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* kernels.h */ nfft-3.3.2/applications/fastsumS2/000077500000000000000000000000001300072027400170245ustar00rootroot00000000000000nfft-3.3.2/applications/fastsumS2/Makefile.am000066400000000000000000000003671300072027400210660ustar00rootroot00000000000000AM_CPPFLAGS = -I$(top_srcdir)/include noinst_PROGRAMS = fastsumS2 fastsumS2_SOURCES = fastsumS2.c doxygen.h fastsumS2_LDADD = $(top_builddir)/libnfft3.la -lm EXTRA_DIST = fastsumS2.m writeTestcase.m readTestcase.m README example.in example.out nfft-3.3.2/applications/fastsumS2/README000066400000000000000000000241641300072027400177130ustar00rootroot00000000000000fastsumS2 - Fast summation of radial functions on the sphere Introduction ------------ This application deals with approximations to sums of the form L-1 - f(xi_d) = > b_l K(eta_l - xi_d) (d=0,...,D-1) (1) - l=0 where xi_d, eta_l are arbitrary nodes on the sphere S^2 given in spherical coordinates (theta,phi) from [0,pi] x [0,2pi), b_l are complex coefficients and K: [-1,1] -> C is a kernel function. Such kernels include the Abel-Poisson and singularity kernels as well as locally supported kernels and the spherical Gaussian kernel. In the following, we will assume that the reader is familiar with the general procedure. A detailed description can be found in [1]. The fast approximate algorithm usees the fast spherical Fourier transform for arbitrary nodes (NFSFT). For more information on this algorithm and notation in detail, we refer to [1] and [2]. Alternatively, one can replace the individual steps of the NFSFT algirithm by exact but asymptotically slower versions or use a direct evaluation and summation of the kernel functions in (1). Directory contents ------------------ fastsumS2.c Example C program example.in Example input for fastsum.c example.out Example output of fastsum.c on input example.in README This file Makefile.am Automake template fastsumS2.m MATLAB example file that re-produces figures and tables from [1] using fastsumS2.c readTestcase.m MATLAB function that reads output of fastsumS2.c writeTestcase.m MATLAB function that writes input for fastsumS2.c fastsumS2.c ----------- The C program fastsumS2.c computes approximations to the sums in (1) using the aforementioned different algorithms. It reads input from the standard input stream and writes output to the standard output stream. The input consists of one ore more testcases. Each testcase specifies - the algorithm(s) and corresponding parameters, - the kernel function and corresponding parameters, - the cut-off degree(s) M for the approximation to the kernel function, - the numbers D and L of nodes. The D and L nodes xi_d and eta_l in (1) are chosen uniformly randomly distributed over the sphere S^2. The coefficients b_l in (1) are chosen uniformly randomly distributed in the complex square [-1/2,1/2] x i[-1/2,1/2]. For more information, see the example input file example.in . Each parameter is specified by an assignment of the form 'name=value'. Each assignment is seperated from the others by at least one whitespace. All parameter values are integer or floating point numbers. There are obligatory parameters which have to be specified in every testcase and extra parameters which are only necessary if the parameters on which each of them depends take certain values. The parameters must be specified in the order as above. Every parameter has a range of admissible values. The behaviour of the program for illegal values of parameters is unspecified. The first parameter specification is 'testcases=...' which specifies the number of testcases to follow. Each testcase has the following parameters with extra parameters marked by an asterisk: - nfsft If set to 1, the NFSFT algorithm is used. If set to 0, the direct NDSFT algorithm is used. * nfft If set to 1, the NFSFT algorithm will internally use the NFFT algorithm. If set to 0, the NFSFT algorithm will instead use the direct NDSFT algorithm. Extra parameter. Specified only if nfsft=1. * cutoff An integer > 0 specifying the NFFT cut-off parameter. Extra parameter. Specified only if nfft=1. * fpt If set to 1, the NFSFT algorithm will internally use the fast polynomial transform algorithm (FPT). If set to 0, the NFSFT algorithm will instead use the direct discrete polynomial transform algorithm (direct DPT). Extra parameter. Specified only if nfsft=1. * threshold A floating point number > 0 specifying the threshold parameter for the FPT algorithm. Extra parameter. Specified only if fpt=1. - kernel An integer from {0,1,2,3} specifying the type of kernel function to be used. The different kernel functions available are + the Abel-Poisson kernel Q_h with real parameter h from (0,1), + the singularity kernel S_h with real parameter h from (0,1), + the locally supported kernel L_h,lambda real parameter h from (-1,1) and integer parameter lambda >= 0. + the spherical Gaussian kernel G_sigma with real parameter sigma > 0. - parameter_sets An integer > 0 specifying the number of parameter sets to follow for the chosen type of kernel function. In a testcase, the specified type of kernel function can be used with more than one set of distinct parameters to yield different kernel functions. - parameters An integer > 0 specifying the number of parameters that specifies each individual kernel function (one for Abel-Poisson, singularity and spherical Gaussian kernel, two for the locally supported kernel). The parameters' values are given afterwards a list floating point numbers order as in the description of the kernel functions above and grouped by kernel function instance. - bandwidths The number of different cut-off degrees M to be used in the approximation. There follows a list of positive integers specifying the distinct cut-off degrees. - node_sets An integer > 0 specifying the number of sets of nodes to follow - L An integer > 0 specifying the number of source nodes. - D An integer > 0 specifying the number of target nodes. - compare If set to 1, the result of the approximate algorithm is compared to the result of the direct evaluation. If set to 0, no comparison is performed. * precomputed If set to 1, all values in the sum (1) are precomputed and the time measurement for the direct evaluation only measures the time needed to sum up these values. Extra parameter. Specified only if compare=1. * repetitions An integer > 0 specifying the number of times the summation process is repeated. Time emasurements are averaged over all repetitions. This can be used to compensate for inaccuracies in the time measurements for very small computation times. The output of the program containes all the input but without the parameter names and, in addition, the results of time and error measurements after each testcase. See the file example.out for an example output on input the contents of example.in. To each combination of kernel function, cut-off degree, and node set corresponds a single run of the summation algorithm and therefore a set of six resulting values grouped together. These are - the time needed for direct evaluation of the sums (1), - the time needed for direct evaluation of the sums (1) with the values of the kernel functions precomputed, - the time needed by the fast summation algorithm using the direct NDSFT algorithm, - the time needed by the fast summation algorithm using the NFSFT algorithm, - the error E_infty for the fast summation algorithm using the direct NDSFT algorithm, - the error E_infty for the fast summation algorithm using the NFSFT algorithm. Here, the error E_infty is defined as ||f - f_M||_infty / ||b||_1 with the infinity norm ||.||_infty, the one norm ||.||_1, the vector f of function values computed by direct evaluation of the sums in (1), f_M the vector computed by the fast summation algorithm, using either the direct NDSFT or the NFSFT algorithm, and the vector b containing the coefficients b_l from (1). Depending on the parameter combination, some of these (always positive) values might be undefined. This indicated by setting these values to -1.0. The blocks of resulting values for a single run are grouped for each testcase first by the kernel parameters, second by the node sets and third by the cut-off bandwidths ordered as in the input. fastsumS2.m ----------- This MATLAB function demonstrates the fast summation algorithm using the C program fastsumS2.c . It allows for selecting different testcases to reproduce the figures and tables from [1]. On choosing a testcase, input for the C program fastsumS2.c is generated and written to the file data.in , fastsumS2.c is called with the generated input writing the result to the file data.out where it is read again into MATLAB. In MATLAB, type "help fatsumS2" for more information. readTestcase.m -------------- This MATLAB function is used by fatsumS2.m and allows for reading testcase specifications and results from a file. In MATLAB, type "help readTestcase" for more information. writeTestcase.m --------------- This MATLAB function is used by fatsumS2.m and allows for writing testcase specifications to a file. In MATLAB, type "help readTestcase" for more information. References ---------- [1] Keiner, J., Kunis, S. and Potts, D., Fast summation of radial functions on the sphere, Computing 78, 1-15 , 2006 [2] Kunis, S. and Potts, D., Fast spherical Fourier algorithms, J. Comput. Appl. Math. 161, 75-98, 2003 Feedback -------- If you have comments, questions, or suggestions regarding NFFT, don't hesitate to contact us. For more information, news and updates see the NFFT website at http://www.tu-chemnitz.de/~potts/nfft/ nfft-3.3.2/applications/fastsumS2/doxygen.h000066400000000000000000000016231300072027400206540ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \defgroup applications_fastsumS2 Fast summation of radial functions on the sphere * \ingroup applications */ nfft-3.3.2/applications/fastsumS2/example.in000066400000000000000000000023161300072027400210110ustar00rootroot00000000000000testcases=3 nfsft=1 nfft=0 fpt=1 threshold=1.000000e+03 kernel=0 parameter_sets=1 parameters=1 0.800000 bandwidths=64 4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 112 116 120 124 128 132 136 140 144 148 152 156 160 164 168 172 176 180 184 188 192 196 200 204 208 212 216 220 224 228 232 236 240 244 248 252 256 node_sets=1 L=1000 D=1000 compare=1 precomputed=0 repetitions=1 nfsft=1 nfft=1 cutoff=3 fpt=1 threshold=1.000000e+03 kernel=0 parameter_sets=1 parameters=1 0.800000 bandwidths=64 4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 112 116 120 124 128 132 136 140 144 148 152 156 160 164 168 172 176 180 184 188 192 196 200 204 208 212 216 220 224 228 232 236 240 244 248 252 256 node_sets=1 L=1000 D=1000 compare=1 precomputed=0 repetitions=1 nfsft=1 nfft=1 cutoff=6 fpt=1 threshold=1.000000e+03 kernel=0 parameter_sets=1 parameters=1 0.800000 bandwidths=64 4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 112 116 120 124 128 132 136 140 144 148 152 156 160 164 168 172 176 180 184 188 192 196 200 204 208 212 216 220 224 228 232 236 240 244 248 252 256 node_sets=1 L=1000 D=1000 compare=1 precomputed=0 repetitions=1 nfft-3.3.2/applications/fastsumS2/example.out000066400000000000000000000403321300072027400212120ustar00rootroot000000000000003 1 0 1 1000.000000 0 1 1 0.800000 64 4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 112 116 120 124 128 132 136 140 144 148 152 156 160 164 168 172 176 180 184 188 192 196 200 204 208 212 216 220 224 228 232 236 240 244 248 252 256 1 1000 1000 1 0 1 1.946635e-01 -1.000000e+00 -1.000000e+00 2.047332e-03 -1.000000e+00 1.576067e-02 1.946635e-01 -1.000000e+00 -1.000000e+00 5.450238e-02 -1.000000e+00 7.145489e-03 1.946635e-01 -1.000000e+00 -1.000000e+00 1.053569e-01 -1.000000e+00 5.295336e-03 1.946635e-01 -1.000000e+00 -1.000000e+00 1.765255e-01 -1.000000e+00 2.590083e-03 1.946635e-01 -1.000000e+00 -1.000000e+00 2.840986e-01 -1.000000e+00 1.171801e-03 1.946635e-01 -1.000000e+00 -1.000000e+00 3.880245e-01 -1.000000e+00 4.232169e-04 1.946635e-01 -1.000000e+00 -1.000000e+00 5.134875e-01 -1.000000e+00 2.067225e-04 1.946635e-01 -1.000000e+00 -1.000000e+00 6.593283e-01 -1.000000e+00 8.173716e-05 1.946635e-01 -1.000000e+00 -1.000000e+00 8.628760e-01 -1.000000e+00 3.865388e-05 1.946635e-01 -1.000000e+00 -1.000000e+00 1.073047e+00 -1.000000e+00 1.853350e-05 1.946635e-01 -1.000000e+00 -1.000000e+00 1.285226e+00 -1.000000e+00 5.975031e-06 1.946635e-01 -1.000000e+00 -1.000000e+00 1.514456e+00 -1.000000e+00 3.461024e-06 1.946635e-01 -1.000000e+00 -1.000000e+00 1.714600e+00 -1.000000e+00 1.451071e-06 1.946635e-01 -1.000000e+00 -1.000000e+00 2.044110e+00 -1.000000e+00 5.647944e-07 1.946635e-01 -1.000000e+00 -1.000000e+00 2.320307e+00 -1.000000e+00 2.420518e-07 1.946635e-01 -1.000000e+00 -1.000000e+00 2.570554e+00 -1.000000e+00 1.113257e-07 1.946635e-01 -1.000000e+00 -1.000000e+00 3.194016e+00 -1.000000e+00 4.139858e-08 1.946635e-01 -1.000000e+00 -1.000000e+00 3.211849e+00 -1.000000e+00 1.791441e-08 1.946635e-01 -1.000000e+00 -1.000000e+00 3.545357e+00 -1.000000e+00 7.180275e-09 1.946635e-01 -1.000000e+00 -1.000000e+00 3.927218e+00 -1.000000e+00 3.205551e-09 1.946635e-01 -1.000000e+00 -1.000000e+00 4.417985e+00 -1.000000e+00 1.607196e-09 1.946635e-01 -1.000000e+00 -1.000000e+00 4.780440e+00 -1.000000e+00 6.027812e-10 1.946635e-01 -1.000000e+00 -1.000000e+00 5.210072e+00 -1.000000e+00 2.730937e-10 1.946635e-01 -1.000000e+00 -1.000000e+00 5.687245e+00 -1.000000e+00 9.956485e-11 1.946635e-01 -1.000000e+00 -1.000000e+00 6.234587e+00 -1.000000e+00 3.650232e-11 1.946635e-01 -1.000000e+00 -1.000000e+00 6.775789e+00 -1.000000e+00 1.735506e-11 1.946635e-01 -1.000000e+00 -1.000000e+00 7.207870e+00 -1.000000e+00 7.175873e-12 1.946635e-01 -1.000000e+00 -1.000000e+00 7.745034e+00 -1.000000e+00 2.552043e-12 1.946635e-01 -1.000000e+00 -1.000000e+00 8.369756e+00 -1.000000e+00 1.223144e-12 1.946635e-01 -1.000000e+00 -1.000000e+00 8.847885e+00 -1.000000e+00 4.934419e-13 1.946635e-01 -1.000000e+00 -1.000000e+00 9.429349e+00 -1.000000e+00 1.941885e-13 1.946635e-01 -1.000000e+00 -1.000000e+00 1.004512e+01 -1.000000e+00 9.104275e-14 1.946635e-01 -1.000000e+00 -1.000000e+00 1.065165e+01 -1.000000e+00 3.849784e-14 1.946635e-01 -1.000000e+00 -1.000000e+00 1.127894e+01 -1.000000e+00 1.654996e-14 1.946635e-01 -1.000000e+00 -1.000000e+00 1.203556e+01 -1.000000e+00 6.889145e-15 1.946635e-01 -1.000000e+00 -1.000000e+00 1.269827e+01 -1.000000e+00 2.463302e-15 1.946635e-01 -1.000000e+00 -1.000000e+00 1.344654e+01 -1.000000e+00 1.075163e-15 1.946635e-01 -1.000000e+00 -1.000000e+00 1.413678e+01 -1.000000e+00 6.001767e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 1.497025e+01 -1.000000e+00 6.664539e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 1.574484e+01 -1.000000e+00 5.081251e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 1.651622e+01 -1.000000e+00 5.596748e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 1.725102e+01 -1.000000e+00 5.154897e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 1.819202e+01 -1.000000e+00 5.191758e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 1.895847e+01 -1.000000e+00 5.449481e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 1.985140e+01 -1.000000e+00 5.412642e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 2.084157e+01 -1.000000e+00 5.228557e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 2.194042e+01 -1.000000e+00 5.412647e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 2.303024e+01 -1.000000e+00 5.412638e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 2.368777e+01 -1.000000e+00 5.449467e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 2.463637e+01 -1.000000e+00 5.596745e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 2.523590e+01 -1.000000e+00 5.596740e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 2.634064e+01 -1.000000e+00 5.596744e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 2.724900e+01 -1.000000e+00 5.523099e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 2.838764e+01 -1.000000e+00 5.523099e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 2.941623e+01 -1.000000e+00 5.523099e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 3.046437e+01 -1.000000e+00 5.523099e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 3.217433e+01 -1.000000e+00 5.523099e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 3.287034e+01 -1.000000e+00 5.523099e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 3.385329e+01 -1.000000e+00 5.523099e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 3.507951e+01 -1.000000e+00 5.523099e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 3.613248e+01 -1.000000e+00 5.523099e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 3.724638e+01 -1.000000e+00 5.523099e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 4.029788e+01 -1.000000e+00 5.523099e-16 1.946635e-01 -1.000000e+00 -1.000000e+00 4.159665e+01 -1.000000e+00 5.523099e-16 1 1 3 1 1000.000000 0 1 1 0.800000 64 4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 112 116 120 124 128 132 136 140 144 148 152 156 160 164 168 172 176 180 184 188 192 196 200 204 208 212 216 220 224 228 232 236 240 244 248 252 256 1 1000 1000 1 0 1 1.995145e-01 -1.000000e+00 -1.000000e+00 2.058164e-03 -1.000000e+00 2.206196e-02 1.995145e-01 -1.000000e+00 -1.000000e+00 4.916940e-04 -1.000000e+00 9.230374e-03 1.995145e-01 -1.000000e+00 -1.000000e+00 6.749389e-04 -1.000000e+00 4.864291e-03 1.995145e-01 -1.000000e+00 -1.000000e+00 8.122652e-04 -1.000000e+00 2.274209e-03 1.995145e-01 -1.000000e+00 -1.000000e+00 1.344094e-03 -1.000000e+00 1.062196e-03 1.995145e-01 -1.000000e+00 -1.000000e+00 1.875128e-03 -1.000000e+00 5.580252e-04 1.995145e-01 -1.000000e+00 -1.000000e+00 2.285584e-03 -1.000000e+00 2.077600e-04 1.995145e-01 -1.000000e+00 -1.000000e+00 2.904276e-03 -1.000000e+00 8.803162e-05 1.995145e-01 -1.000000e+00 -1.000000e+00 5.139147e-03 -1.000000e+00 3.748478e-05 1.995145e-01 -1.000000e+00 -1.000000e+00 5.730155e-03 -1.000000e+00 1.851213e-05 1.995145e-01 -1.000000e+00 -1.000000e+00 6.591798e-03 -1.000000e+00 6.665944e-06 1.995145e-01 -1.000000e+00 -1.000000e+00 7.545517e-03 -1.000000e+00 2.975418e-06 1.995145e-01 -1.000000e+00 -1.000000e+00 8.549193e-03 -1.000000e+00 1.440584e-06 1.995145e-01 -1.000000e+00 -1.000000e+00 9.308123e-03 -1.000000e+00 5.872307e-07 1.995145e-01 -1.000000e+00 -1.000000e+00 1.009069e-02 -1.000000e+00 2.603293e-07 1.995145e-01 -1.000000e+00 -1.000000e+00 1.134565e-02 -1.000000e+00 1.228668e-07 1.995145e-01 -1.000000e+00 -1.000000e+00 2.156919e-02 -1.000000e+00 9.576442e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 2.221613e-02 -1.000000e+00 7.410972e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 2.560731e-02 -1.000000e+00 6.331626e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 2.638115e-02 -1.000000e+00 6.034587e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 2.947786e-02 -1.000000e+00 8.006522e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 3.124964e-02 -1.000000e+00 5.849066e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 3.579587e-02 -1.000000e+00 6.006391e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 4.662405e-02 -1.000000e+00 6.394056e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 4.080721e-02 -1.000000e+00 6.404895e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 4.293288e-02 -1.000000e+00 8.404899e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 4.483403e-02 -1.000000e+00 7.138842e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 4.858419e-02 -1.000000e+00 6.475614e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 5.733759e-02 -1.000000e+00 5.546687e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 5.257779e-02 -1.000000e+00 8.905276e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 6.502895e-02 -1.000000e+00 6.703670e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 6.476594e-02 -1.000000e+00 7.281137e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 1.012439e-01 -1.000000e+00 8.602497e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 1.087701e-01 -1.000000e+00 5.322486e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 1.072860e-01 -1.000000e+00 7.190318e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 1.130813e-01 -1.000000e+00 6.175638e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 1.816289e-01 -1.000000e+00 5.544125e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 1.350188e-01 -1.000000e+00 6.333313e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 1.300539e-01 -1.000000e+00 5.665348e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 1.456071e-01 -1.000000e+00 6.575343e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 2.438004e-01 -1.000000e+00 6.158477e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 1.599971e-01 -1.000000e+00 7.265016e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 1.924899e-01 -1.000000e+00 5.685559e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 1.756611e-01 -1.000000e+00 7.989629e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 1.831965e-01 -1.000000e+00 7.176792e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 1.987849e-01 -1.000000e+00 7.284645e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 2.130107e-01 -1.000000e+00 6.510812e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 2.211764e-01 -1.000000e+00 8.360268e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 2.186293e-01 -1.000000e+00 5.326091e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 2.508298e-01 -1.000000e+00 7.017699e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 2.675460e-01 -1.000000e+00 6.326950e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 2.450898e-01 -1.000000e+00 6.094832e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 2.961816e-01 -1.000000e+00 5.504172e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 2.485896e-01 -1.000000e+00 7.642313e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 2.592066e-01 -1.000000e+00 5.956123e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 2.689671e-01 -1.000000e+00 6.318204e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 3.005800e-01 -1.000000e+00 5.306546e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 3.204003e-01 -1.000000e+00 7.470833e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 4.306144e-01 -1.000000e+00 5.091598e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 3.088647e-01 -1.000000e+00 6.035399e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 5.040653e-01 -1.000000e+00 6.030642e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 3.757050e-01 -1.000000e+00 6.749314e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 3.436299e-01 -1.000000e+00 5.168785e-08 1.995145e-01 -1.000000e+00 -1.000000e+00 3.934722e-01 -1.000000e+00 4.541723e-08 1 1 6 1 1000.000000 0 1 1 0.800000 64 4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 112 116 120 124 128 132 136 140 144 148 152 156 160 164 168 172 176 180 184 188 192 196 200 204 208 212 216 220 224 228 232 236 240 244 248 252 256 1 1000 1000 1 0 1 1.911687e-01 -1.000000e+00 -1.000000e+00 2.039949e-03 -1.000000e+00 2.014872e-02 1.911687e-01 -1.000000e+00 -1.000000e+00 9.502748e-04 -1.000000e+00 8.659336e-03 1.911687e-01 -1.000000e+00 -1.000000e+00 1.132988e-03 -1.000000e+00 5.506680e-03 1.911687e-01 -1.000000e+00 -1.000000e+00 1.253998e-03 -1.000000e+00 2.229810e-03 1.911687e-01 -1.000000e+00 -1.000000e+00 1.803338e-03 -1.000000e+00 1.095621e-03 1.911687e-01 -1.000000e+00 -1.000000e+00 2.449043e-03 -1.000000e+00 4.469697e-04 1.911687e-01 -1.000000e+00 -1.000000e+00 2.783493e-03 -1.000000e+00 2.390019e-04 1.911687e-01 -1.000000e+00 -1.000000e+00 3.634455e-03 -1.000000e+00 7.240590e-05 1.911687e-01 -1.000000e+00 -1.000000e+00 5.709544e-03 -1.000000e+00 4.524542e-05 1.911687e-01 -1.000000e+00 -1.000000e+00 6.624406e-03 -1.000000e+00 1.984394e-05 1.911687e-01 -1.000000e+00 -1.000000e+00 7.271370e-03 -1.000000e+00 7.150170e-06 1.911687e-01 -1.000000e+00 -1.000000e+00 8.539940e-03 -1.000000e+00 3.311000e-06 1.911687e-01 -1.000000e+00 -1.000000e+00 8.987270e-03 -1.000000e+00 1.317728e-06 1.911687e-01 -1.000000e+00 -1.000000e+00 1.014274e-02 -1.000000e+00 5.724193e-07 1.911687e-01 -1.000000e+00 -1.000000e+00 1.100352e-02 -1.000000e+00 2.082067e-07 1.911687e-01 -1.000000e+00 -1.000000e+00 1.253078e-02 -1.000000e+00 8.020459e-08 1.911687e-01 -1.000000e+00 -1.000000e+00 2.277670e-02 -1.000000e+00 4.033054e-08 1.911687e-01 -1.000000e+00 -1.000000e+00 2.353545e-02 -1.000000e+00 1.910061e-08 1.911687e-01 -1.000000e+00 -1.000000e+00 2.701967e-02 -1.000000e+00 8.209719e-09 1.911687e-01 -1.000000e+00 -1.000000e+00 2.731132e-02 -1.000000e+00 3.415467e-09 1.911687e-01 -1.000000e+00 -1.000000e+00 2.969884e-02 -1.000000e+00 1.611355e-09 1.911687e-01 -1.000000e+00 -1.000000e+00 3.248629e-02 -1.000000e+00 5.897510e-10 1.911687e-01 -1.000000e+00 -1.000000e+00 3.718490e-02 -1.000000e+00 2.275297e-10 1.911687e-01 -1.000000e+00 -1.000000e+00 4.144712e-02 -1.000000e+00 1.005764e-10 1.911687e-01 -1.000000e+00 -1.000000e+00 4.078063e-02 -1.000000e+00 3.669910e-11 1.911687e-01 -1.000000e+00 -1.000000e+00 4.461497e-02 -1.000000e+00 1.799338e-11 1.911687e-01 -1.000000e+00 -1.000000e+00 4.949561e-02 -1.000000e+00 7.267821e-12 1.911687e-01 -1.000000e+00 -1.000000e+00 6.140988e-02 -1.000000e+00 2.961840e-12 1.911687e-01 -1.000000e+00 -1.000000e+00 6.233617e-02 -1.000000e+00 1.899627e-12 1.911687e-01 -1.000000e+00 -1.000000e+00 6.199885e-02 -1.000000e+00 4.898336e-13 1.911687e-01 -1.000000e+00 -1.000000e+00 7.246404e-02 -1.000000e+00 2.540395e-13 1.911687e-01 -1.000000e+00 -1.000000e+00 8.287569e-02 -1.000000e+00 1.419295e-13 1.911687e-01 -1.000000e+00 -1.000000e+00 1.356708e-01 -1.000000e+00 1.077694e-13 1.911687e-01 -1.000000e+00 -1.000000e+00 1.666573e-01 -1.000000e+00 1.166215e-13 1.911687e-01 -1.000000e+00 -1.000000e+00 1.449886e-01 -1.000000e+00 1.040598e-13 1.911687e-01 -1.000000e+00 -1.000000e+00 1.602449e-01 -1.000000e+00 1.045409e-13 1.911687e-01 -1.000000e+00 -1.000000e+00 2.615239e-01 -1.000000e+00 9.447209e-14 1.911687e-01 -1.000000e+00 -1.000000e+00 1.784918e-01 -1.000000e+00 1.110954e-13 1.911687e-01 -1.000000e+00 -1.000000e+00 1.523209e-01 -1.000000e+00 8.527835e-14 1.911687e-01 -1.000000e+00 -1.000000e+00 1.713088e-01 -1.000000e+00 9.703811e-14 1.911687e-01 -1.000000e+00 -1.000000e+00 2.399460e-01 -1.000000e+00 1.111198e-13 1.911687e-01 -1.000000e+00 -1.000000e+00 1.662828e-01 -1.000000e+00 7.758726e-14 1.911687e-01 -1.000000e+00 -1.000000e+00 2.028379e-01 -1.000000e+00 9.356213e-14 1.911687e-01 -1.000000e+00 -1.000000e+00 1.902028e-01 -1.000000e+00 9.564702e-14 1.911687e-01 -1.000000e+00 -1.000000e+00 1.946892e-01 -1.000000e+00 1.116358e-13 1.911687e-01 -1.000000e+00 -1.000000e+00 2.118433e-01 -1.000000e+00 1.074939e-13 1.911687e-01 -1.000000e+00 -1.000000e+00 2.307004e-01 -1.000000e+00 8.718194e-14 1.911687e-01 -1.000000e+00 -1.000000e+00 2.337525e-01 -1.000000e+00 9.001991e-14 1.911687e-01 -1.000000e+00 -1.000000e+00 2.218771e-01 -1.000000e+00 7.784874e-14 1.911687e-01 -1.000000e+00 -1.000000e+00 2.530055e-01 -1.000000e+00 1.154430e-13 1.911687e-01 -1.000000e+00 -1.000000e+00 2.583145e-01 -1.000000e+00 8.167511e-14 1.911687e-01 -1.000000e+00 -1.000000e+00 2.524221e-01 -1.000000e+00 9.630596e-14 1.911687e-01 -1.000000e+00 -1.000000e+00 3.072517e-01 -1.000000e+00 9.168991e-14 1.911687e-01 -1.000000e+00 -1.000000e+00 2.624353e-01 -1.000000e+00 9.037553e-14 1.911687e-01 -1.000000e+00 -1.000000e+00 2.775889e-01 -1.000000e+00 9.259290e-14 1.911687e-01 -1.000000e+00 -1.000000e+00 2.816421e-01 -1.000000e+00 9.142843e-14 1.911687e-01 -1.000000e+00 -1.000000e+00 3.490324e-01 -1.000000e+00 7.655178e-14 1.911687e-01 -1.000000e+00 -1.000000e+00 3.635086e-01 -1.000000e+00 1.163181e-13 1.911687e-01 -1.000000e+00 -1.000000e+00 4.702578e-01 -1.000000e+00 8.073900e-14 1.911687e-01 -1.000000e+00 -1.000000e+00 3.472053e-01 -1.000000e+00 8.085754e-14 1.911687e-01 -1.000000e+00 -1.000000e+00 5.798098e-01 -1.000000e+00 8.861487e-14 1.911687e-01 -1.000000e+00 -1.000000e+00 7.018026e-01 -1.000000e+00 8.376872e-14 1.911687e-01 -1.000000e+00 -1.000000e+00 4.815139e-01 -1.000000e+00 1.069780e-13 1.911687e-01 -1.000000e+00 -1.000000e+00 4.015164e-01 -1.000000e+00 9.420015e-14 nfft-3.3.2/applications/fastsumS2/fastsumS2.c000066400000000000000000001223551300072027400210670ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \defgroup applications_fastsumS2_test fastsumS2_matlab * \ingroup applications_fastsumS2 * \{ */ #include "config.h" /* standard headers */ #include #include #include #include #ifdef HAVE_COMPLEX_H #include #endif /* NFFT3 header */ #include "nfft3.h" /* NFFT3 utilities */ #include "infft.h" /* Fourier-Legendre coefficients for Abel-Poisson kernel */ #define SYMBOL_ABEL_POISSON(k,h) (pow(h,k)) /* Fourier-Legendre coefficients for singularity kernel */ #define SYMBOL_SINGULARITY(k,h) ((2.0/(2*k+1))*pow(h,k)) /* Flags for the different kernel functions */ /** Abel-Poisson kernel */ #define KT_ABEL_POISSON (0) /** Singularity kernel */ #define KT_SINGULARITY (1) /** Locally supported kernel */ #define KT_LOC_SUPP (2) /** Gaussian kernel */ #define KT_GAUSSIAN (3) /** Enumeration type for yes/no/both-type parameters */ enum pvalue {NO = 0, YES = 1, BOTH = 2}; static inline int scaled_modified_bessel_i_series(const R x, const R alpha, const int nb, const int ize, R *b) { const R enmten = K(4.0)*nfft_float_property(NFFT_R_MIN); R tempa = K(1.0), empal = K(1.0) + alpha, halfx = K(0.0), tempb = K(0.0); int n, ncalc = nb; if (enmten < x) halfx = x/K(2.0); if (alpha != K(0.0)) tempa = POW(halfx, alpha)/TGAMMA(empal); if (ize == 2) tempa *= EXP(-x); if (K(1.0) < x + K(1.0)) tempb = halfx*halfx; b[0] = tempa + tempa*tempb/empal; if (x != K(0.0) && b[0] == K(0.0)) ncalc = 0; if (nb == 1) return ncalc; if (K(0.0) < x) { R tempc = halfx, tover = (enmten + enmten)/x; if (tempb != K(0.0)) tover = enmten/tempb; for (n = 1; n < nb; n++) { tempa /= empal; empal += K(1.0); tempa *= tempc; if (tempa <= tover*empal) tempa = K(0.0); b[n] = tempa + tempa*tempb/empal; if (b[n] == K(0.0) && n < ncalc) ncalc = n; } } else for (n = 1; n < nb; n++) b[n] = K(0.0); return ncalc; } static inline void scaled_modified_bessel_i_normalize(const R x, const R alpha, const int nb, const int ize, R *b, const R sum_) { const R enmten = K(4.0)*nfft_float_property(NFFT_R_MIN); R sum = sum_, tempa; int n; /* Normalize, i.e., divide all b[n] by sum */ if (alpha != K(0.0)) sum = sum * TGAMMA(K(1.0) + alpha) * POW(x/K(2.0), -alpha); if (ize == 1) sum *= EXP(-x); tempa = enmten; if (K(1.0) < sum) tempa *= sum; for (n = 1; n <= nb; n++) { if (b[n-1] < tempa) b[n-1] = K(0.0); b[n-1] /= sum; } } /** * Calculates the modified bessel function \f$I_{n+\alpha}(x)\f$, possibly * scaled by \f$\mathrm{e}^{-x}\f$, for real non-negative \f$x,alpha\f$ with * \f$0 \le \alpha < 1\f$, and \f$n=0,1,\ldots,nb-1\f$. * * \arg[in] \c x non-negative real number in \f$I_{n+\alpha}(x)\f$ * \arg[in] \c alpha non-negative real number with \f$0 \le \alpha < 1\f$ in * \f$I_{n+\alpha}(x)\f$ * \arg[in] \c nb number of functions to be calculated * \arg[in] \c ize switch between no scaling (\c ize = 1) and exponential * scaling (\c ize = 2) * \arg[out] \c b real output vector to contain \f$I_{n+\alpha}(x)\f$, * \f$n=0,1,\ldots,nb-1\f$ * \return error indicator. Only if this value is identical to \c nb, then all * values in \c b have been calculated to full accuracy. If not, errors are * indicated using the following scheme: * - ncalc < 0: At least one of the arguments was out of range (e.g. nb <= 0, * ize neither equals 1 nor 2, \f$|x| \ge exparg\f$). In this case, the * output vector b is not calculated and \c ncalc is set to * \f$\min(nb,0)-1\f$. * - 0 < ncalc < nb: Not all requested functions could be calculated to full * accuracy. This can occur when nb is much larger than |x|. in this case, * the values \f$I_{n+\alpha}(x)\f$ are calculated to full accuracy for * \f$n=0,1,\ldots,ncalc\f$. The rest of the values up to * \f$n=0,1,\ldots,nb-1\f$ is calculated to a lower accuracy. * * \acknowledgement * * This program is based on a program written by David J. Sookne [2] that * computes values of the Bessel functions \f$J_{\nu}(x)\f$ or \f$I_{\nu}(x)\f$ * for real argument \f$x\f$ and integer order \f$\nu\f$. modifications include * the restriction of the computation to the Bessel function \f$I_{\nu}(x)\f$ * for non-negative real argument, the extension of the computation to arbitrary * non-negative orders \f$\nu\f$, and the elimination of most underflow. * * References: * [1] F. W. J. Olver and D. J. Sookne, A note on backward recurrence * algorithms", Math. Comput. (26), 1972, pp 125 -- 132. * [2] D. J. Sookne, "Bessel functions of real argument and int order", NBS * Jour. of Res. B. (77B), 1973, pp. 125 -- 132. * * Modified by W. J. Cody, Applied Mathematics Division, Argonne National * Laboratory, Argonne, IL, 60439, USA * * Modified by Jens Keiner, Institute of Mathematics, University of Lübeck, * 23560 Lübeck, Germany */ static int smbi(const R x, const R alpha, const int nb, const int ize, R *b) { /* machine dependent parameters */ /* NSIG - DECIMAL SIGNIFICANCE DESIRED. SHOULD BE SET TO */ /* IFIX(ALOG10(2)*NBIT+1), WHERE NBIT IS THE NUMBER OF */ /* BITS IN THE MANTISSA OF A WORKING PRECISION VARIABLE. */ /* SETTING NSIG LOWER WILL RESULT IN DECREASED ACCURACY */ /* WHILE SETTING NSIG HIGHER WILL INCREASE CPU TIME */ /* WITHOUT INCREASING ACCURACY. THE TRUNCATION ERROR */ /* IS LIMITED TO A RELATIVE ERROR OF T=.5*10**(-NSIG). */ /* ENTEN - 10.0 ** K, WHERE K IS THE LARGEST int SUCH THAT */ /* ENTEN IS MACHINE-REPRESENTABLE IN WORKING PRECISION. */ /* ENSIG - 10.0 ** NSIG. */ /* RTNSIG - 10.0 ** (-K) FOR THE SMALLEST int K SUCH THAT */ /* K .GE. NSIG/4. */ /* ENMTEN - THE SMALLEST ABS(X) SUCH THAT X/4 DOES NOT UNDERFLOW. */ /* XLARGE - UPPER LIMIT ON THE MAGNITUDE OF X WHEN IZE=2. BEAR */ /* IN MIND THAT IF ABS(X)=N, THEN AT LEAST N ITERATIONS */ /* OF THE BACKWARD RECURSION WILL BE EXECUTED. */ /* EXPARG - LARGEST WORKING PRECISION ARGUMENT THAT THE LIBRARY */ /* EXP ROUTINE CAN HANDLE AND UPPER LIMIT ON THE */ /* MAGNITUDE OF X WHEN IZE=1. */ const int nsig = MANT_DIG + 2; const R enten = nfft_float_property(NFFT_R_MAX); const R ensig = POW(K(10.0),(R)nsig); const R rtnsig = POW(K(10.0),-CEIL((R)nsig/K(4.0))); const R xlarge = K(1E4); const R exparg = FLOOR(LOG(POW(K(R_RADIX),K(DBL_MAX_EXP-1)))); /* System generated locals */ int l, n, nend, magx, nbmx, ncalc, nstart; R p, em, en, sum, pold, test, empal, tempa, tempb, tempc, psave, plast, tover, emp2al, psavel; magx = LRINT(FLOOR(x)); /* return if x, nb, or ize out of range */ if ( nb <= 0 || x < K(0.0) || alpha < K(0.0) || K(1.0) <= alpha || ((ize != 1 || exparg < x) && (ize != 2 || xlarge < x))) return (MIN(nb,0) - 1); /* 2-term ascending series for small x */ if (x < rtnsig) return scaled_modified_bessel_i_series(x,alpha,nb,ize,b); ncalc = nb; /* forward sweep, Olver's p-sequence */ nbmx = nb - magx; n = magx + 1; en = (R) (n+n) + (alpha+alpha); plast = K(1.0); p = en/x; /* significance test */ test = ensig + ensig; if ((5*nsig) < (magx << 1)) test = SQRT(test*p); else test /= POW(K(1.585),(R)magx); if (3 <= nbmx) { /* calculate p-sequence until n = nb-1 */ tover = enten/ensig; nstart = magx+2; nend = nb - 1; for (n = nstart; n <= nend; n++) { en += K(2.0); pold = plast; plast = p; p = en*plast/x + pold; if (p > tover) { /* divide p-sequence by tover to avoid overflow. Calculate p-sequence * until 1 <= |p| */ tover = enten; p /= tover; plast /= tover; psave = p; psavel = plast; nstart = n + 1; do { n++; en += K(2.0); pold = plast; plast = p; p = en*plast/x + pold; } while (p <= K(1.0)); tempb = en/x; /* Backward test. Find ncalc as the largest n such that test is passed. */ test = pold*plast*(K(0.5) - K(0.5)/(tempb * tempb))/ensig; p = plast*tover; n--; en -= K(2.0); nend = MIN(nb,n); for (ncalc = nstart; ncalc <= nend; ncalc++) { pold = psavel; psavel = psave; psave = en*psavel/x + pold; if (test < psave * psavel) break; } ncalc--; goto L80; } } n = nend; en = (R) (n+n) + (alpha+alpha); /* special significance test for 2 <= nbmx */ test = FMAX(test,SQRT(plast*ensig)*SQRT(p+p)); } /* calculate p-sequence until significance test is passed */ do { n++; en += K(2.0); pold = plast; plast = p; p = en*plast/x + pold; } while (p < test); /* Initialize backward recursion and normalization sum. */ L80: n++; en += K(2.0); tempb = K(0.0); tempa = K(1.0)/p; em = (R)(n-1); empal = em + alpha; emp2al = em - K(1.0) + (alpha+alpha); sum = tempa*empal*emp2al/em; nend = n-nb; if (nend < 0) { /* We have n <= nb. So store b[n] and set higher orders to zero */ b[n-1] = tempa; nend = -nend; for (l = 1; l <= nend; ++l) b[n-1 + l] = K(0.0); } else { if (nend != 0) { /* recur backward via difference equation, calculating b[n] until n = nb */ for (l = 1; l <= nend; ++l) { n--; en -= K(2.0); tempc = tempb; tempb = tempa; tempa = en*tempb/x + tempc; em -= K(1.0); emp2al -= K(1.0); if (n == 1) break; if (n == 2) emp2al = K(1.0); empal -= K(1.0); sum = (sum + tempa*empal)*emp2al/em; } } /* store b[nb] */ b[n-1] = tempa; if (nb <= 1) { sum = sum + sum + tempa; scaled_modified_bessel_i_normalize(x,alpha,nb,ize,b,sum); return ncalc; } /* calculate and store b[nb-1] */ n--; en -= 2.0; b[n-1] = en*tempa/x + tempb; if (n == 1) { sum = sum + sum + b[0]; scaled_modified_bessel_i_normalize(x,alpha,nb,ize,b,sum); return ncalc; } em -= K(1.0); emp2al -= K(1.0); if (n == 2) emp2al = K(1.0); empal -= K(1.0); sum = (sum + b[n-1]*empal)*emp2al/em; } nend = n - 2; if (nend != 0) { /* Calculate and store b[n] until n = 2. */ for (l = 1; l <= nend; ++l) { n--; en -= K(2.0); b[n-1] = en*b[n]/x + b[n+1]; em -= K(1.0); emp2al -= K(1.0); if (n == 2) emp2al = K(1.0); empal -= K(1.0); sum = (sum + b[n-1]*empal)*emp2al/em; } } /* calculate b[1] */ b[0] = K(2.0)*empal*b[1]/x + b[2]; sum = sum + sum + b[0]; scaled_modified_bessel_i_normalize(x,alpha,nb,ize,b,sum); return ncalc; } /** * Computes the \f$\mathbb{R}^3\f$ standard inner product between two vectors * on the unit sphere \f$\mathbb{S}^2\f$ given in spherical coordinates. * * \arg phi1 The angle \f$\varphi_1 \in [-\pi,\pi)\f$ of the first vector * \arg theta1 The angle \f$\vartheta_1 \in [0,\pi]\f$ of the first vector * \arg phi2 The angle \f$\varphi_2 \in [-\pi,\pi)\f$ of the second vector * \arg theta2 The angle \f$\vartheta_2 \in [0,\pi]\f$ of the second vector * * \return The inner product \f$\cos \vartheta_1 \cos \vartheta_2 + * \sin \vartheta_1 \sin(\vartheta_2 \cos(\varphi_1 - \varphi_2)\f$ * * \author Jens Keiner */ static inline double innerProduct(const double phi1, const double theta1, const double phi2, const double theta2) { double pi2theta1 = K2PI*theta1, pi2theta2 = K2PI*theta2; return (cos(pi2theta1)*cos(pi2theta2) + sin(pi2theta1)*sin(pi2theta2)*cos(K2PI*(phi1-phi2))); } /** * Evaluates the Poisson kernel \f$Q_h: [-1,1] \rightarrow \mathbb{R}\f$ at a * node \f$x \in [-1,1]\f$. * * \arg x The node \f$x \in [-1,1]\f$ * \arg h The parameter \f$h \in (0,1)\f$ * * \return The value of the Poisson kernel \f$Q_h(x)\f$ at the node \f$x\f$ * * \author Jens Keiner */ static inline double poissonKernel(const double x, const double h) { return (1.0/(K4PI))*((1.0-h)*(1.0+h))/pow(sqrt(1.0-2.0*h*x+h*h),3.0); } /** * Evaluates the singularity kernel \f$S_h: [-1,1] \rightarrow \mathbb{R}\f$ at * a node \f$x \in [-1,1]\f$. * * \arg x The node \f$x \in [-1,1]\f$ * \arg h The parameter \f$h \in (0,1)\f$ * * \return The value of the Poisson kernel \f$S_h(x)\f$ at the node \f$x\f$ * * \author Jens Keiner */ static inline double singularityKernel(const double x, const double h) { return (1.0/(K2PI))/sqrt(1.0-2.0*h*x+h*h); } /** * Evaluates the locally supported kernel \f$L_{h,\lambda}: [-1,1] \rightarrow * \mathbb{R}\f$ at a node \f$x \in [-1,1]\f$. * * \arg x The node \f$x \in [-1,1]\f$ * \arg h The parameter \f$h \in (0,1)\f$ * \arg lambda The parameter \f$\lambda \in \mathbb{N}_0\f$ * * \return The value of the locally supported kernel \f$L_{h,\lambda}(x)\f$ at * the node \f$x\f$ * * \author Jens Keiner */ static inline double locallySupportedKernel(const double x, const double h, const double lambda) { return (x<=h)?(0.0):(pow((x-h),lambda)); } /** * Evaluates the spherical Gaussian kernel \f$G_\sigma: [-1,1] \rightarrow * \mathbb{R}\f$ at a node \f$x \in [-1,1]\f$. * * \arg x The node \f$x \in [-1,1]\f$ * \arg sigma The parameter \f$\sigma \in \mathbb{R}_+\f$ * * \return The value of the pherical Gaussian kernel \f$G_\sigma(x)\f$ at the * node \f$x\f$ * * \author Jens Keiner */ static inline double gaussianKernel(const double x, const double sigma) { return exp(2.0*sigma*(x-1.0)); } /** * The main program. * * \param argc The number of arguments * \param argv An array containing the arguments as C-strings * * \return Exit code * * \author Jens Keiner */ int main (int argc, char **argv) { double **p; /* The array containing the parameter sets * * for the kernel functions */ int *m; /* The array containing the cut-off degrees M */ int **ld; /* The array containing the numbers of source * * and target nodes, L and D */ int ip; /* Index variable for p */ int im; /* Index variable for m */ int ild; /* Index variable for l */ int ipp; /* Index for kernel parameters */ int ip_max; /* The maximum index for p */ int im_max; /* The maximum index for m */ int ild_max; /* The maximum index for l */ int ipp_max; /* The maximum index for ip */ int tc_max; /* The number of testcases */ int m_max; /* The maximum cut-off degree M for the * * current dataset */ int l_max; /* The maximum number of source nodes L for * * the current dataset */ int d_max; /* The maximum number of target nodes D for * * the current dataset */ long ld_max_prec; /* The maximum number of source and target * * nodes for precomputation multiplied */ long l_max_prec; /* The maximum number of source nodes for * * precomputation */ int tc; /* Index variable for testcases */ int kt; /* The kernel function */ int cutoff; /* The current NFFT cut-off parameter */ double threshold; /* The current NFSFT threshold parameter */ double t_d; /* Time for direct algorithm in seconds */ double t_dp; /* Time for direct algorithm with * precomputation in seconds */ double t_fd; /* Time for fast direct algorithm in seconds */ double t_f; /* Time for fast algorithm in seconds */ double temp; /* */ double err_f; /* Error E_infty for fast algorithm */ double err_fd; /* Error E_\infty for fast direct algorithm */ ticks t0, t1; /* */ int precompute = NO; /* */ fftw_complex *ptr; /* */ double* steed; /* */ fftw_complex *b; /* The weights (b_l)_{l=0}^{L-1} */ fftw_complex *f_hat; /* The spherical Fourier coefficients */ fftw_complex *a; /* The Fourier-Legendre coefficients */ double *xi; /* Target nodes */ double *eta; /* Source nodes */ fftw_complex *f_m; /* Approximate function values */ fftw_complex *f; /* Exact function values */ fftw_complex *prec = NULL; /* */ nfsft_plan plan; /* NFSFT plan */ nfsft_plan plan_adjoint; /* adjoint NFSFT plan */ int i; /* */ int k; /* */ int n; /* */ int d; /* */ int l; /* */ int use_nfsft; /* */ int use_nfft; /* */ int use_fpt; /* */ int rinc; /* */ double constant; /* */ /* Read the number of testcases. */ fscanf(stdin,"testcases=%d\n",&tc_max); fprintf(stdout,"%d\n",tc_max); /* Process each testcase. */ for (tc = 0; tc < tc_max; tc++) { /* Check if the fast transform shall be used. */ fscanf(stdin,"nfsft=%d\n",&use_nfsft); fprintf(stdout,"%d\n",use_nfsft); if (use_nfsft != NO) { /* Check if the NFFT shall be used. */ fscanf(stdin,"nfft=%d\n",&use_nfft); fprintf(stdout,"%d\n",use_nfft); if (use_nfft != NO) { /* Read the cut-off parameter. */ fscanf(stdin,"cutoff=%d\n",&cutoff); fprintf(stdout,"%d\n",cutoff); } else { /* TODO remove this */ /* Initialize unused variable with dummy value. */ cutoff = 1; } /* Check if the fast polynomial transform shall be used. */ fscanf(stdin,"fpt=%d\n",&use_fpt); fprintf(stdout,"%d\n",use_fpt); /* Read the NFSFT threshold parameter. */ fscanf(stdin,"threshold=%lf\n",&threshold); fprintf(stdout,"%lf\n",threshold); } else { /* TODO remove this */ /* Set dummy values. */ cutoff = 3; threshold = 1000000000000.0; } /* Initialize bandwidth bound. */ m_max = 0; /* Initialize source nodes bound. */ l_max = 0; /* Initialize target nodes bound. */ d_max = 0; /* Initialize source nodes bound for precomputation. */ l_max_prec = 0; /* Initialize source and target nodes bound for precomputation. */ ld_max_prec = 0; /* Read the kernel type. This is one of KT_ABEL_POISSON, KT_SINGULARITY, * KT_LOC_SUPP and KT_GAUSSIAN. */ fscanf(stdin,"kernel=%d\n",&kt); fprintf(stdout,"%d\n",kt); /* Read the number of parameter sets. */ fscanf(stdin,"parameter_sets=%d\n",&ip_max); fprintf(stdout,"%d\n",ip_max); /* Allocate memory for pointers to parameter sets. */ p = (double**) nfft_malloc(ip_max*sizeof(double*)); /* We now read in the parameter sets. */ /* Read number of parameters. */ fscanf(stdin,"parameters=%d\n",&ipp_max); fprintf(stdout,"%d\n",ipp_max); for (ip = 0; ip < ip_max; ip++) { /* Allocate memory for the parameters. */ p[ip] = (double*) nfft_malloc(ipp_max*sizeof(double)); /* Read the parameters. */ for (ipp = 0; ipp < ipp_max; ipp++) { /* Read the next parameter. */ fscanf(stdin,"%lf\n",&p[ip][ipp]); fprintf(stdout,"%lf\n",p[ip][ipp]); } } /* Read the number of cut-off degrees. */ fscanf(stdin,"bandwidths=%d\n",&im_max); fprintf(stdout,"%d\n",im_max); m = (int*) nfft_malloc(im_max*sizeof(int)); /* Read the cut-off degrees. */ for (im = 0; im < im_max; im++) { /* Read cut-off degree. */ fscanf(stdin,"%d\n",&m[im]); fprintf(stdout,"%d\n",m[im]); m_max = MAX(m_max,m[im]); } /* Read number of node specifications. */ fscanf(stdin,"node_sets=%d\n",&ild_max); fprintf(stdout,"%d\n",ild_max); ld = (int**) nfft_malloc(ild_max*sizeof(int*)); /* Read the run specification. */ for (ild = 0; ild < ild_max; ild++) { /* Allocate memory for the run parameters. */ ld[ild] = (int*) nfft_malloc(5*sizeof(int)); /* Read number of source nodes. */ fscanf(stdin,"L=%d ",&ld[ild][0]); fprintf(stdout,"%d\n",ld[ild][0]); l_max = MAX(l_max,ld[ild][0]); /* Read number of target nodes. */ fscanf(stdin,"D=%d ",&ld[ild][1]); fprintf(stdout,"%d\n",ld[ild][1]); d_max = MAX(d_max,ld[ild][1]); /* Determine whether direct and fast algorithm shall be compared. */ fscanf(stdin,"compare=%d ",&ld[ild][2]); fprintf(stdout,"%d\n",ld[ild][2]); /* Check if precomputation for the direct algorithm is used. */ if (ld[ild][2] == YES) { /* Read whether the precomputed version shall also be used. */ fscanf(stdin,"precomputed=%d\n",&ld[ild][3]); fprintf(stdout,"%d\n",ld[ild][3]); /* Read the number of repetitions over which measurements are * averaged. */ fscanf(stdin,"repetitions=%d\n",&ld[ild][4]); fprintf(stdout,"%d\n",ld[ild][4]); /* Update ld_max_prec and l_max_prec. */ if (ld[ild][3] == YES) { /* Update ld_max_prec. */ ld_max_prec = MAX(ld_max_prec,ld[ild][0]*ld[ild][1]); /* Update l_max_prec. */ l_max_prec = MAX(l_max_prec,ld[ild][0]); /* Turn on the precomputation for the direct algorithm. */ precompute = YES; } } else { /* Set default value for the number of repetitions. */ ld[ild][4] = 1; } } /* Allocate memory for data structures. */ b = (fftw_complex*) nfft_malloc(l_max*sizeof(fftw_complex)); eta = (double*) nfft_malloc(2*l_max*sizeof(double)); f_hat = (fftw_complex*) nfft_malloc(NFSFT_F_HAT_SIZE(m_max)*sizeof(fftw_complex)); a = (fftw_complex*) nfft_malloc((m_max+1)*sizeof(fftw_complex)); xi = (double*) nfft_malloc(2*d_max*sizeof(double)); f_m = (fftw_complex*) nfft_malloc(d_max*sizeof(fftw_complex)); f = (fftw_complex*) nfft_malloc(d_max*sizeof(fftw_complex)); /* Allocate memory for precomputed data. */ if (precompute == YES) { prec = (fftw_complex*) nfft_malloc(ld_max_prec*sizeof(fftw_complex)); } /* Generate random source nodes and weights. */ for (l = 0; l < l_max; l++) { b[l] = (((double)rand())/RAND_MAX) - 0.5; eta[2*l] = (((double)rand())/RAND_MAX) - 0.5; eta[2*l+1] = acos(2.0*(((double)rand())/RAND_MAX) - 1.0)/(K2PI); } /* Generate random target nodes. */ for (d = 0; d < d_max; d++) { xi[2*d] = (((double)rand())/RAND_MAX) - 0.5; xi[2*d+1] = acos(2.0*(((double)rand())/RAND_MAX) - 1.0)/(K2PI); } /* Do precomputation. */ nfsft_precompute(m_max,threshold, ((use_nfsft==NO)?(NFSFT_NO_FAST_ALGORITHM):(0U/*NFSFT_NO_DIRECT_ALGORITHM*/)), 0U); /* Process all parameter sets. */ for (ip = 0; ip < ip_max; ip++) { /* Compute kernel coeffcients up to the maximum cut-off degree m_max. */ switch (kt) { case KT_ABEL_POISSON: /* Compute Fourier-Legendre coefficients for the Poisson kernel. */ for (k = 0; k <= m_max; k++) a[k] = SYMBOL_ABEL_POISSON(k,p[ip][0]); break; case KT_SINGULARITY: /* Compute Fourier-Legendre coefficients for the singularity * kernel. */ for (k = 0; k <= m_max; k++) a[k] = SYMBOL_SINGULARITY(k,p[ip][0]); break; case KT_LOC_SUPP: /* Compute Fourier-Legendre coefficients for the locally supported * kernel. */ a[0] = 1.0; if (1 <= m_max) a[1] = ((p[ip][1]+1+p[ip][0])/(p[ip][1]+2.0))*a[0]; for (k = 2; k <= m_max; k++) a[k] = (1.0/(k+p[ip][1]+1))*((2*k-1)*p[ip][0]*a[k-1] - (k-p[ip][1]-2)*a[k-2]); break; case KT_GAUSSIAN: /* Fourier-Legendre coefficients */ steed = (double*) nfft_malloc((m_max+1)*sizeof(double)); smbi(2.0*p[ip][0],0.5,m_max+1,2,steed); for (k = 0; k <= m_max; k++) a[k] = K2PI*(sqrt(KPI/p[ip][0]))*steed[k]; nfft_free(steed); break; } /* Normalize Fourier-Legendre coefficients. */ for (k = 0; k <= m_max; k++) a[k] *= (2*k+1)/(K4PI); /* Process all node sets. */ for (ild = 0; ild < ild_max; ild++) { /* Check if the fast algorithm shall be used. */ if (ld[ild][2] != NO) { /* Check if the direct algorithm with precomputation should be * tested. */ if (ld[ild][3] != NO) { /* Get pointer to start of data. */ ptr = prec; /* Calculate increment from one row to the next. */ rinc = l_max_prec-ld[ild][0]; /* Process al target nodes. */ for (d = 0; d < ld[ild][1]; d++) { /* Process all source nodes. */ for (l = 0; l < ld[ild][0]; l++) { /* Compute inner product between current source and target * node. */ temp = innerProduct(eta[2*l],eta[2*l+1],xi[2*d],xi[2*d+1]); /* Switch by the kernel type. */ switch (kt) { case KT_ABEL_POISSON: /* Evaluate the Poisson kernel for the current value. */ *ptr++ = poissonKernel(temp,p[ip][0]); break; case KT_SINGULARITY: /* Evaluate the singularity kernel for the current * value. */ *ptr++ = singularityKernel(temp,p[ip][0]); break; case KT_LOC_SUPP: /* Evaluate the localized kernel for the current * value. */ *ptr++ = locallySupportedKernel(temp,p[ip][0],p[ip][1]); break; case KT_GAUSSIAN: /* Evaluate the spherical Gaussian kernel for the current * value. */ *ptr++ = gaussianKernel(temp,p[ip][0]); break; } } /* Increment pointer for next row. */ ptr += rinc; } /* Initialize cumulative time variable. */ t_dp = 0.0; /* Initialize time measurement. */ t0 = getticks(); /* Cycle through all runs. */ for (i = 0; i < ld[ild][4]; i++) { /* Reset pointer to start of precomputed data. */ ptr = prec; /* Calculate increment from one row to the next. */ rinc = l_max_prec-ld[ild][0]; /* Check if the localized kernel is used. */ if (kt == KT_LOC_SUPP) { /* Perform final summation */ /* Calculate the multiplicative constant. */ constant = ((p[ip][1]+1)/(K2PI*pow(1-p[ip][0],p[ip][1]+1))); /* Process all target nodes. */ for (d = 0; d < ld[ild][1]; d++) { /* Initialize function value. */ f[d] = 0.0; /* Process all source nodes. */ for (l = 0; l < ld[ild][0]; l++) f[d] += b[l]*(*ptr++); /* Multiply with the constant. */ f[d] *= constant; /* Proceed to next row. */ ptr += rinc; } } else { /* Process all target nodes. */ for (d = 0; d < ld[ild][1]; d++) { /* Initialize function value. */ f[d] = 0.0; /* Process all source nodes. */ for (l = 0; l < ld[ild][0]; l++) f[d] += b[l]*(*ptr++); /* Proceed to next row. */ ptr += rinc; } } } /* Calculate the time needed. */ t1 = getticks(); t_dp = nfft_elapsed_seconds(t1,t0); /* Calculate average time needed. */ t_dp = t_dp/((double)ld[ild][4]); } else { /* Initialize cumulative time variable with dummy value. */ t_dp = -1.0; } /* Initialize cumulative time variable. */ t_d = 0.0; /* Initialize time measurement. */ t0 = getticks(); /* Cycle through all runs. */ for (i = 0; i < ld[ild][4]; i++) { /* Switch by the kernel type. */ switch (kt) { case KT_ABEL_POISSON: /* Process all target nodes. */ for (d = 0; d < ld[ild][1]; d++) { /* Initialize function value. */ f[d] = 0.0; /* Process all source nodes. */ for (l = 0; l < ld[ild][0]; l++) { /* Compute the inner product for the current source and * target nodes. */ temp = innerProduct(eta[2*l],eta[2*l+1],xi[2*d],xi[2*d+1]); /* Evaluate the Poisson kernel for the current value and add * to the result. */ f[d] += b[l]*poissonKernel(temp,p[ip][0]); } } break; case KT_SINGULARITY: /* Process all target nodes. */ for (d = 0; d < ld[ild][1]; d++) { /* Initialize function value. */ f[d] = 0.0; /* Process all source nodes. */ for (l = 0; l < ld[ild][0]; l++) { /* Compute the inner product for the current source and * target nodes. */ temp = innerProduct(eta[2*l],eta[2*l+1],xi[2*d],xi[2*d+1]); /* Evaluate the Poisson kernel for the current value and add * to the result. */ f[d] += b[l]*singularityKernel(temp,p[ip][0]); } } break; case KT_LOC_SUPP: /* Calculate the multiplicative constant. */ constant = ((p[ip][1]+1)/(K2PI*pow(1-p[ip][0],p[ip][1]+1))); /* Process all target nodes. */ for (d = 0; d < ld[ild][1]; d++) { /* Initialize function value. */ f[d] = 0.0; /* Process all source nodes. */ for (l = 0; l < ld[ild][0]; l++) { /* Compute the inner product for the current source and * target nodes. */ temp = innerProduct(eta[2*l],eta[2*l+1],xi[2*d],xi[2*d+1]); /* Evaluate the Poisson kernel for the current value and add * to the result. */ f[d] += b[l]*locallySupportedKernel(temp,p[ip][0],p[ip][1]); } /* Multiply result with constant. */ f[d] *= constant; } break; case KT_GAUSSIAN: /* Process all target nodes. */ for (d = 0; d < ld[ild][1]; d++) { /* Initialize function value. */ f[d] = 0.0; /* Process all source nodes. */ for (l = 0; l < ld[ild][0]; l++) { /* Compute the inner product for the current source and * target nodes. */ temp = innerProduct(eta[2*l],eta[2*l+1],xi[2*d],xi[2*d+1]); /* Evaluate the Poisson kernel for the current value and add * to the result. */ f[d] += b[l]*gaussianKernel(temp,p[ip][0]); } } break; } } /* Calculate and add the time needed. */ t1 = getticks(); t_d = nfft_elapsed_seconds(t1,t0); /* Calculate average time needed. */ t_d = t_d/((double)ld[ild][4]); } else { /* Initialize cumulative time variable with dummy value. */ t_d = -1.0; t_dp = -1.0; } /* Initialize error and cumulative time variables for the fast * algorithm. */ err_fd = -1.0; err_f = -1.0; t_fd = -1.0; t_f = -1.0; /* Process all cut-off bandwidths. */ for (im = 0; im < im_max; im++) { /* Init transform plans. */ nfsft_init_guru(&plan_adjoint, m[im],ld[ild][0], ((use_nfft!=0)?(0U):(NFSFT_USE_NDFT)) | ((use_fpt!=0)?(0U):(NFSFT_USE_DPT)), PRE_PHI_HUT | PRE_PSI | FFTW_INIT | FFT_OUT_OF_PLACE, cutoff); nfsft_init_guru(&plan,m[im],ld[ild][1], ((use_nfft!=0)?(0U):(NFSFT_USE_NDFT)) | ((use_fpt!=0)?(0U):(NFSFT_USE_DPT)), PRE_PHI_HUT | PRE_PSI | FFTW_INIT | FFT_OUT_OF_PLACE, cutoff); plan_adjoint.f_hat = f_hat; plan_adjoint.x = eta; plan_adjoint.f = b; plan.f_hat = f_hat; plan.x = xi; plan.f = f_m; nfsft_precompute_x(&plan_adjoint); nfsft_precompute_x(&plan); /* Check if direct algorithm shall also be tested. */ if (use_nfsft == BOTH) { /* Initialize cumulative time variable. */ t_fd = 0.0; /* Initialize time measurement. */ t0 = getticks(); /* Cycle through all runs. */ for (i = 0; i < ld[ild][4]; i++) { /* Execute adjoint direct NDSFT transformation. */ nfsft_adjoint_direct(&plan_adjoint); /* Multiplication with the Fourier-Legendre coefficients. */ for (k = 0; k <= m[im]; k++) for (n = -k; n <= k; n++) f_hat[NFSFT_INDEX(k,n,&plan_adjoint)] *= a[k]; /* Execute direct NDSFT transformation. */ nfsft_trafo_direct(&plan); } /* Calculate and add the time needed. */ t1 = getticks(); t_fd = nfft_elapsed_seconds(t1,t0); /* Calculate average time needed. */ t_fd = t_fd/((double)ld[ild][4]); /* Check if error E_infty should be computed. */ if (ld[ild][2] != NO) { /* Compute the error E_infinity. */ err_fd = X(error_l_infty_1_complex)(f, f_m, ld[ild][1], b, ld[ild][0]); } } /* Check if the fast NFSFT algorithm shall also be tested. */ if (use_nfsft != NO) { /* Initialize cumulative time variable for the NFSFT algorithm. */ t_f = 0.0; } else { /* Initialize cumulative time variable for the direct NDSFT * algorithm. */ t_fd = 0.0; } /* Initialize time measurement. */ t0 = getticks(); /* Cycle through all runs. */ for (i = 0; i < ld[ild][4]; i++) { /* Check if the fast NFSFT algorithm shall also be tested. */ if (use_nfsft != NO) { /* Execute the adjoint NFSFT transformation. */ nfsft_adjoint(&plan_adjoint); } else { /* Execute the adjoint direct NDSFT transformation. */ nfsft_adjoint_direct(&plan_adjoint); } /* Multiplication with the Fourier-Legendre coefficients. */ for (k = 0; k <= m[im]; k++) for (n = -k; n <= k; n++) f_hat[NFSFT_INDEX(k,n,&plan_adjoint)] *= a[k]; /* Check if the fast NFSFT algorithm shall also be tested. */ if (use_nfsft != NO) { /* Execute the NFSFT transformation. */ nfsft_trafo(&plan); } else { /* Execute the NDSFT transformation. */ nfsft_trafo_direct(&plan); } } /* Check if the fast NFSFT algorithm has been used. */ t1 = getticks(); if (use_nfsft != NO) t_f = nfft_elapsed_seconds(t1,t0); else t_fd = nfft_elapsed_seconds(t1,t0); /* Check if the fast NFSFT algorithm has been used. */ if (use_nfsft != NO) { /* Calculate average time needed. */ t_f = t_f/((double)ld[ild][4]); } else { /* Calculate average time needed. */ t_fd = t_fd/((double)ld[ild][4]); } /* Check if error E_infty should be computed. */ if (ld[ild][2] != NO) { /* Check if the fast NFSFT algorithm has been used. */ if (use_nfsft != NO) { /* Compute the error E_infinity. */ err_f = X(error_l_infty_1_complex)(f, f_m, ld[ild][1], b, ld[ild][0]); } else { /* Compute the error E_infinity. */ err_fd = X(error_l_infty_1_complex)(f, f_m, ld[ild][1], b, ld[ild][0]); } } /* Print out the error measurements. */ fprintf(stdout,"%e\n%e\n%e\n%e\n%e\n%e\n\n",t_d,t_dp,t_fd,t_f,err_fd, err_f); /* Finalize the NFSFT plans */ nfsft_finalize(&plan_adjoint); nfsft_finalize(&plan); } /* for (im = 0; im < im_max; im++) - Process all cut-off * bandwidths.*/ } /* for (ild = 0; ild < ild_max; ild++) - Process all node sets. */ } /* for (ip = 0; ip < ip_max; ip++) - Process all parameter sets. */ /* Delete precomputed data. */ nfsft_forget(); /* Check if memory for precomputed data of the matrix K has been * allocated. */ if (precompute == YES) { /* Free memory for precomputed matrix K. */ nfft_free(prec); } /* Free data arrays. */ nfft_free(f); nfft_free(f_m); nfft_free(xi); nfft_free(eta); nfft_free(a); nfft_free(f_hat); nfft_free(b); /* Free memory for node sets. */ for (ild = 0; ild < ild_max; ild++) nfft_free(ld[ild]); nfft_free(ld); /* Free memory for cut-off bandwidths. */ nfft_free(m); /* Free memory for parameter sets. */ for (ip = 0; ip < ip_max; ip++) nfft_free(p[ip]); nfft_free(p); } /* for (tc = 0; tc < tc_max; tc++) - Process each testcase. */ /* Return exit code for successful run. */ return EXIT_SUCCESS; } /* \} */ nfft-3.3.2/applications/fastsumS2/fastsumS2.m000066400000000000000000000216261300072027400211000ustar00rootroot00000000000000function fastsumS2() %FASTSUMS2 % % Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 % Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. % % The input file's name for fastsumS2.c infilename = 'data.in'; % The output file name. outfilename = 'data.out'; % The name of the fastsumS2.c executable if ispc programname='fastsumS2.exe'; else programname='./fastsumS2'; end % The name of the file to write the time measurements table to. texfilename = 'table.tex'; % Create the menu selection = menu(... ['fastsumS2 - Fast summation of radial functions on the sphere'],... 'Generate Figure 5.1 (a)','Generate Figure 5.1 (b)',... 'Generate Figure 5.1 (c)','Generate Figure 5.1 (d)',... 'Generate Table 5.1') % Open the file for the input to fastsumS2.c file = fopen(infilename,'w'); % Check if the error plots are to be generated if (selection > 0 && selection <= 4) % Write the number of testcases to the file. fprintf(file,'testcases=3\n'); % Set the single node set to be used. The values in the vector signify % - 1000 Use 1000 source nodes, % - 1000 use 1000 target nodes, % - 1 Compare with direct evaluation of the sums (1 = Yes, 0 = No), % - 0 Don't use precomputed values for direct evaluation (1 = Yes, 0 = No), % - 1 Do the summation process 1 time. nodes = [1000, 1000, 1, 0, 1]; % Switch by kernel type. if (selection == 1) % Generate figure 5.1 (a) % Set the kernel to be the Abel-Poisson kernel. kernel = 0; % Set the parameter h. parameters = [0.8]; % Set the cut-off bandwidth m = 4:4:256; % Generate the theoretical error bound function from [1]. bound = inline(sprintf(['((%d.^(x+1))./(4*pi)).*((2*x+1)./(1-%d)+(2)./',... '((1-%d).^2))'],parameters(1),parameters(1),parameters(1))); elseif (selection == 2) % Generate figure 5.1 (b) % Set the kernel to be the singularity kernel. kernel=1; % Set the parameter h. parameters = [0.8]; % Set the cut-off bandwidth m = 4:4:256; % Generate the theoretical error bound function from [1]. bound = inline(sprintf(['((%d.^(x+1))./(4*pi)).*((2*x+1)./(2*(1-%d))+',... '(4*x)./((1-%d).^2)+(4)./((1-%d).^3))'], parameters(1),... parameters(1),parameters(1),parameters(1))); elseif (selection == 3) % Generate figure 5.1 (c) % Set the kernel to be the locally supported kernel. kernel=2; % Set the parameter h and lambda. parameters = [0.3 7]; % Set the cut-off bandwidth m = 4:4:256; % Generate the theoretical error bound function from [1]. bound = inline(sprintf(['(1/(pi*sqrt(2*pi))).*(((%d+1).^2)./(%d-0.5)).*',... '(1./((1-%d).^(2*%d+1).*sqrt(sqrt(1-abs(%d))))).*(1./((x-%d).^',... '(%d-0.5)))'], parameters(2), parameters(2), parameters(1),... parameters(2), parameters(1), parameters(2), parameters(2))); elseif (selection == 4) % Generate figure 5.1 (c) % Set the kernel to be the spherical gaussian kernel. kernel=3; % Set the parameter sigma. parameters = [2.5]; % Set the cut-off bandwidth m = 1:1:32; % Generate the theoretical error bound function from [1]. bound = inline(sprintf('(sqrt(pi*%d).*(exp(%d)-1).*%d.^(x-0.5))./(gamma(x+0.5))',... parameters(1),parameters(1),parameters(1))); end % Write three testcases for testing three different algorithms and parameters % to the input file. % NFSFT algorithm with direct NDFT and direct DPT writeTestcase(file,1,0,0,1,1000,kernel,parameters,m,nodes); % NFSFT algorithm with NFFT (cut-off parameter 3) and FPT algorithm % (threshold 1000.0) writeTestcase(file,1,1,3,1,1000,kernel,parameters,m,nodes); % NFSFT algorithm with NFFT (cut-off parameter 6) and FPT algorithm % (threshold 1000.0) writeTestcase(file,1,1,6,1,1000,kernel,parameters,m,nodes); % Close the input file. fclose(file); % Call fastsumS2.c with the generated input file writing the output to the % output file. system(sprintf('%s < %s > %s',programname,infilename,outfilename)); % Open the output file. file = fopen(outfilename,'r'); % Read the testcases into a cell array. T = readTestcase(file); % Close the output file. fclose(file); % Generate the values of the theoretical error bound function. y4 = feval(bound,T{1}.bandwidths); % Generate a new figure. figure('Color',[1 1 1],'InvertHardcopy','off','PaperSize',[20.98 29.68]); % Add the different error curves to the figure % Get the cut-off degree values. x = T{1}.bandwidths; % First testcase semilogy(x,T{1}.data{1}(:,6),'-','LineWidth',2,'Color',[0,0,0]); % Prevent old curves from being deleted by adding the next curve hold on % Second testcase semilogy(x,T{2}.data{1}(:,6),'-.','LineWidth',2,'Color',[0,0,0]); % Third testcase semilogy(x,T{3}.data{1}(:,6),'--','LineWidth',2,'Color',[0,0,0]); % Theoretical error bound semilogy(x,y4,':','LineWidth',2,'Color',[0,0,0]); % Adjust the axis limits. axis([x(1) x(end) 1e-17 1]) % Add axis labels. xlabel('M'); ylabel('E_{\infty}','Rotation',0); elseif (selection == 5) % Generate Table 5.1 % Write the number of testcases to the file. fprintf(file,'testcases=1\n'); % Set node sets to be used. We use L = D source and target nodes as a power % of two from 2^6 up to 2^21. Up to L = D = 2^18, we use the direct sum % evaluation and compute the error E_infty. Up to L = D = 2^12 we also use % precomputed kernel function values to compare the time needed. For small % node numbers and computation times, we use repetitions to obtain time % measurements averaged over multiple computations. nodes = [... 2^6, 2^6, 1, 1, 60;... 2^7, 2^7, 1, 1, 50;... 2^8, 2^8, 1, 1, 35;... 2^9, 2^9, 1, 1, 20;... 2^10, 2^10, 1, 1, 10;... 2^11, 2^11, 1, 1, 10;... 2^12, 2^12, 1, 1, 10;... 2^13, 2^13, 1, 0, 1;... 2^14, 2^14, 1, 0, 1;... 2^15, 2^15, 1, 0, 1;... 2^16, 2^16, 1, 0, 1;... 2^17, 2^17, 1, 0, 1;... 2^18, 2^18, 1, 0, 1;... 2^19, 2^19, 0, 0, 1;... 2^20, 2^20, 0, 0, 1;... 2^21, 2^21, 0, 0, 1]; % Set the kernel to be the Abel-Poisson kernel. kernel = 0; % Set the parameter h. parameters = [0.6]; %Set the cut-off degree. m = 128; % Write the testcase to the input file. writeTestcase(file,2,1,6,1,1000,kernel,parameters,m,nodes); % Close the input file. fclose(file); % Call fastsumS2.c with the generated input file writing the output to the % output file. system(sprintf('%s < %s > %s',programname,infilename,outfilename)); % Open the output file. file = fopen(outfilename,'r'); % Read the testcases into a cell array. T = readTestcase(file); % Close the output file. fclose(file); % Open the file to write the table in TeX format to. file = fopen(texfilename,'w'); % Generate the table in TeX format and write it to the output file. fprintf(file,'\\begin{table}[ht!]\n \\begin{center}\n '); fprintf(file,'\\begin{tabular}{r|r|r|r|r|r}\n '); fprintf(file,'$L = D$ & direct alg. & w/pre-comp. & '); fprintf(file,'FS, NDSFT & FS, NFSFT & error '); fprintf(file,'$E_{\\infty}$\\\\\\hline\\\\[-2.0ex]\n'); for i = 1:size(T{1}.data,2) fprintf(file,' $2^{%d}$ & %s & %s & %s & %s & %s\\\\\n',... round(log2(T{1}.nodes(i,1))),texFormat(T{1}.data{i}(1)),... texFormat(T{1}.data{i}(2)),texFormat(T{1}.data{i}(3)),... texFormat(T{1}.data{i}(4)),texFormat(T{1}.data{i}(6))); end fprintf(file,' \\end{tabular}\n'); fprintf(file,' \\end{center}\n'); fprintf(file,'\\end{table}\n'); % Close the output file. fclose(file); else % Error due to invalid selection. error('Invalid selection!'); end % End of the function return; function s = texFormat(d) % TEXFORMAT Output positive numbers in TeX verbatim font style % TEXFORMAT(d) converts any number d > 0 to a string in TeX verbatim % font style. The number is converted into scientfic format with one decimal % digit precision. If d <= 0 a dash in Tex verbatim font style is returned in % place of the number. % Check if number is greater zero. if d > 0 % Convert number to TeX verbatim font style and scientif format. s = sprintf('\\verb#%.1E#',d); else % Return a dash in TeX verbatim font style. s = '\verb#-#'; end nfft-3.3.2/applications/fastsumS2/readTestcase.m000066400000000000000000000151041300072027400216120ustar00rootroot00000000000000function T = readTestcase(file) % READTESTCASE Read fastsumS2.c testcase results from file % READTESTCASE(FILE) reads fastsumS2.c testcase results from the file FILE. % The testcase results are returned as a cell vector containing the data for % each individual testcase as a structure with the following fields: % - USENFSFT If true, the NFSFT algorithm has been used, otherwise the direct % NDSFT algorithm % - USENFFT If true, the NFFT algorithm has been used, otherwise the direct % NDFT algorithm (undefined if USENFSFT is false), % - CUTOFF The NFFT cut-off parameter (undefined if USENFFT is false) % - USEFPT If true, the fast polynomial transform has been used, otherwise the % direct polynomial transform algorithm (undefined if USENFSFT is false), % - THRESHOLD The fast polynomial transform threshold parameter (undefined if % USEFPT is false), % - kernel The kernel function used (0 = Abel-Poisson kernel, 1 = % singularity kernel, 2 = locally supported kernel, 3 = spherical Gaussian % kernel), % - parameters A m x n matrix containing the kernel function parameters, % m is the number of parameter sets and n is the number of kernel function % parameters (1 for Abel-Poisson, singularity and spherical Gaussian kernel, % 2 for the locally supported kernel) % - bandwidths A vector containing the cut-off degrees for the approximation % - nodes A m x 5 matrix containing the node sets used, where m is the number % of different node sets. Each row contains a node set specification % containing % - in the first column the number of source nodes, % - in the second colum the number of target nodes, % - in the third column whether the direct sum evaluation has been performed % to compute the error E_infty, % - in the fourth column whether the precomputed direct sum evaluation has % been used (undefined if direct sum evaluation has not been used), % - in the fifth column the error E_infty (undefined if direct sum % evaluation has not been used). % - data A m x n cell array containing the result data where m is the number % of parameter sets and n is the number of node sets. Cell (m,n) correspond % to the given ordering of parameter sets and node sets and is % a j x 6 matrix, where j is the number of cut-off degrees. Each row % represents the result data for a single cut-off degree and contains % - in the first column the time needed for direct sum evaluation, % - in the second column the time needed for direct sum evaluation with % precomputation, % - in the third column the time needed by the fast summation algorithm % using the direct NDSFT algorithm, % - in the fourth column the time needed by the fast summation algorithm % using the NFSFT algorithm, % - in the fifth column the error E_infty for the fast summation algorithm % using the direct NDSFT algorithm, % - in the sixth column the error E_infty for the fast summation algorithm % using the NFSFT algorithm. % Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 % Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. % % Read the number of testcases. tc_max = fscanf(file,'%d',1); % Create empty cell array for the testcases. T = cell(tc_max,1); % Cycle through all testcases. for i = 1:tc_max % Create structure. t = struct('USENFSFT',[0],'USENFFT',[0],'CUTOFF',[0],'USEFPT',[0],... 'THRESHOLD',[0],'kernel',[0],'parameters',{0},'bandwidths',[0],... 'nodes',{0},'data',{0}); % Read NFSFT usage flag. v = fscanf(file,'%d',1); if (v >= 1) % Set NFSFT usage flag in the structure. t.USENFSFT = [true]; % Read NFFT usage flag. v = fscanf(file,'%d',1); if (v >= 1) % Set NFSFT usage flag in the structure. t.USENFFFT = [true]; % Read the NFFT cut-off parameter. v = fscanf(file,'%d',1); t.CUTOFF = [v]; else % Set NFSFT usage flag in the structure. t.USENFFFT = [false]; end % Read FPT usage flag. v = fscanf(file,'%d',1); if (v >= 1) % Set NFSFT usage flag in the structure. t.USEFPT = [false]; else % Set NFSFT usage flag in the structure. t.USEFPT = [false]; end % Read the FPT threshold. v = fscanf(file,'%lf',1); t.THRESHOLD = [v]; else % Set NFSFT usage flag in the structure. t.USENFSFT = [false]; end % Read the kernel type. v = fscanf(file,'%d',1); t.kernel = [v]; % Read the number of parameter sets. ip_max = fscanf(file,'%d',1); % Read the number of parameters. ipp_max = fscanf(file,'%d',1); % Create empty array for parameters. p = zeros(ipp_max,ip_max); % Read parameters. p = fscanf(file,'%lf',[ipp_max,ip_max]); % Transpose matrix to get dimensions right. t.parameters = p'; % Read number of cut-off degrees bandwidths = fscanf(file,'%d',1); % Read the cut-off degrees m = fscanf(file,'%d',bandwidths); t.bandwidths = m; % Read number of node sets. ild_max = fscanf(file,'%d',1); % Read node sets. nodes = zeros(ild_max,5); for j=1:ild_max % Read first three parameters. nodes(j,1) = fscanf(file,'%d',1); nodes(j,2) = fscanf(file,'%d',1); nodes(j,3) = fscanf(file,'%d',1); % Check for for parameters. if (nodes(j,3) == 1) % Read two more parameters. nodes(j,4) = fscanf(file,'%d',1); nodes(j,5) = fscanf(file,'%d',1); end end % Assign node set matrix to data field in structure. t.nodes = nodes; % Create cell array for result data datacell = {ip_max,ild_max}; % For each parameter set and node set combination read the result data for % every cut-off degree into a matrix. for j=1:ip_max for k=1:ild_max data = fscanf(file,'%e',[6,bandwidths]); datacell{j,k} = data'; end end % Assign cell array to data field in structure. t.data = datacell; % Assign testcase structure to field in cell array. T{i} = t; end % End of the function return; nfft-3.3.2/applications/fastsumS2/writeTestcase.m000066400000000000000000000103621300072027400220320ustar00rootroot00000000000000function writeTestcase(file,usenfsft,usenfft,cutoff,usefpt,threshold,kernel,... parameters,bandwidths,nodes) % WRITETESTCASE Write a fastsumS2 testcase definition to a file % WRITETESTCASE(FILE, USENFSFT, USENFFT, CUTOFF, USEFPT, THRESHOLD, KERNEL, % PARAMETERS, BANDWIDTHS, NODES) writes a fastsumS2 testcase specification to % the file associated with the file handle FILE. % The parameters are % - FILE The file handle associated with the file to write to, % - USENFSFT If true, the NFSFT algorithm is used, otherwise the direct NDSFT % algorithm, % - USENFFT If true, the NFFT algorithm is used, otherwise the direct NDSFT % algorithm (ignored if USENFSFT is false), % - CUTOFF The NFFT cut-off parameter (ignored if USENFFT is false) % - USEFPT If true, the fast polynomial transform is used, otherwise the % direct polynomial transform algorithm (ignored if USENFSFT is false), % - THRESHOLD The fast polynomial transform threshold parameter (ignored if % USEFPT is false), % - KERNEL The kernel function to be used (0 = Abel-Poisson kernel, 1 = % singularity kernel, 2 = locally supported kernel, 3 = spherical Gaussian % kernel), % - PARAMETERS A m x n matrix containing the kernel function parameters, % m is the number of parameter sets and n is the number of kernel function % parameters (1 for Abel-Poisson, singularity and spherical Gaussian kernel, % 2 for the locally supported kernel) % - BANDWIDTH A vector containing the cut-off degrees for the approximation % - NODES A m x 5 matrix containing the node sets used, where m is the number % of different node sets. Each row contains a node set specification % containing % - in the first column the number of source nodes, % - in the second colum the number of target nodes, % - in the third column whether the direct sum evaluation has been performed % to compute the error E_infty, % - in the fourth column whether the precomputed direct sum evaluation has % been used (undefined if direct sum evaluation has not been used), % - in the fifth column the error E_infty (undefined if direct sum % evaluation has not been used). % Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 % Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. % % Write NFSFT usage flag. fprintf(file,'nfsft=%d\n',usenfsft); if (usenfsft == true) % Write NFFT usage flag. fprintf(file,'nfft=%d\n',usenfft); if (usenfft == true) % Write NFFT cut-off parameter. fprintf(file,'cutoff=%d\n',cutoff); end % Write FPT usage flag. fprintf(file,'fpt=%d\n',usefpt); % Write FPT threshold. fprintf(file,'threshold=%e\n',threshold); end % Write kernel type fprintf(file,'kernel=%d\n',kernel); % Write number of parameter sets. fprintf(file,'parameter_sets=%d\n',size(parameters,1)); % Write number of parameters. fprintf(file,'parameters=%d\n',size(parameters,2)); % Write parameters sets. for j=1:size(parameters,1) for k=1:size(parameters,2) % Write parameter k of parameter sets j. fprintf(file,'%f\n',parameters(j,k)); end end % Write number of bandwidths. fprintf(file,'bandwidths=%d\n',length(bandwidths)); % Write bandwidths. fprintf(file,'%d\n',bandwidths); % Write number of node sets. fprintf(file,'node_sets=%d\n',size(nodes,1)); % Write node sets. for j = 1:size(nodes,1) fprintf(file,'L=%d\n',nodes(j,1)); fprintf(file,'D=%d\n',nodes(j,2)); fprintf(file,'compare=%d\n',nodes(j,3)); if (nodes(j,3) == 1) fprintf(file,'precomputed=%d\n',nodes(j,4)); fprintf(file,'repetitions=%d\n',nodes(j,5)); end end % End of function return; nfft-3.3.2/applications/iterS2/000077500000000000000000000000001300072027400163055ustar00rootroot00000000000000nfft-3.3.2/applications/iterS2/Makefile.am000066400000000000000000000004351300072027400203430ustar00rootroot00000000000000AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/kernel/nfsft noinst_PROGRAMS = iterS2 iterS2_SOURCES = iterS2.c doxygen.h iterS2_LDADD = $(top_builddir)/libnfft3.la @fftw3_LDFLAGS@ @fftw3_LIBS@ EXTRA_DIST = writeTestcase.m writeImageTestcase.m README #iterS2.m readTestcase.m nfft-3.3.2/applications/iterS2/README000066400000000000000000000026771300072027400172010ustar00rootroot00000000000000iterS2 - Iterative reconstruction on the sphere S2. !!! THIS EXAMPLE IS CURRENTLY NOT FUNCTIONAL !!! Introduction ------------ Directory contents ------------------ iterS2.c Example C program example.in Example input for iterS2.c example.out Example output of iterS2.c on input example.in README This file Makefile.am Automake template iterS2.m MATLAB example file that preproduces figures from [1] using iterS2.c readTestcase.m MATLAB function that reads output of iterS2.c writeTestcase.m MATLAB function that writes input for iterS2.c writeImageTestcase.m MATLAB function that writes input for iterS2.c iterS2.c ----------- iterS2.m ----------- readTestcase.m -------------- This MATLAB function is used by iterS2.m and allows for reading testcase specifications and results from a file. In MATLAB, type "help readTestcase" for more information. writeTestcase.m --------------- This MATLAB function is used by iterS2.m and allows for writing testcase specifications to a file. In MATLAB, type "help readTestcase" for more information. References ---------- Feedback -------- If you have comments, questions, or suggestions regarding NFFT, don't hesitate to contact us. For more information, news and updates see the NFFT website at http://www.tu-chemnitz.de/~potts/nfft/ nfft-3.3.2/applications/iterS2/doxygen.h000066400000000000000000000016111300072027400201320ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \defgroup applications_iterS2 Iterative reconstruction on the sphere S2 * \ingroup applications */ nfft-3.3.2/applications/iterS2/iterS2.c000066400000000000000000000342161300072027400176270ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* iterS2 - Iterative reconstruction on the sphere S2 */ /** * \defgroup applications_iterS2_matlab iterS2_matlab * \ingroup applications_iterS2 * \{ */ #include "config.h" /* Include standard C headers. */ #include #include #include #ifdef HAVE_COMPLEX_H #include #endif /* Include NFFT 3 utilities headers. */ /* Include NFFT3 library header. */ #include "nfft3.h" #include "infft.h" #include "legendre.h" static void voronoi_weights_S2(R *w, R *xi, INT M) { R *x; R *y; R *z; int j; int k; int el; int Mlocal = M; int lnew; int ier; int *list; int *lptr; int *lend; int *near; int *next; R *dist; int *ltri; int *listc; int nb; R *xc; R *yc; R *zc; R *rc; R *vr; int lp; int lpl; int kv; R a; /* Allocate memory for auxilliary arrays. */ x = (R*)X(malloc)(M * sizeof(R)); y = (R*)X(malloc)(M * sizeof(R)); z = (R*)X(malloc)(M * sizeof(R)); list = (int*)X(malloc)((6*M-12+1)*sizeof(int)); lptr = (int*)X(malloc)((6*M-12+1)*sizeof(int)); lend = (int*)X(malloc)((M+1)*sizeof(int)); near = (int*)X(malloc)((M+1)*sizeof(int)); next = (int*)X(malloc)((M+1)*sizeof(int)); dist = (R*)X(malloc)((M+1)*sizeof(R)); ltri = (int*)X(malloc)((6*M+1)*sizeof(int)); listc = (int*)X(malloc)((6*M-12+1)*sizeof(int)); xc = (R*)X(malloc)((2*M-4+1)*sizeof(R)); yc = (R*)X(malloc)((2*M-4+1)*sizeof(R)); zc = (R*)X(malloc)((2*M-4+1)*sizeof(R)); rc = (R*)X(malloc)((2*M-4+1)*sizeof(R)); vr = (R*)X(malloc)(3*(2*M-4+1)*sizeof(R)); /* Convert from spherical Coordinates in [0,1/2]x[-1/2,1/2) to Cartesian * coordinates. */ for (k = 0; k < M; k++) { x[k] = SIN(K2PI*xi[2*k+1])*COS(K2PI*xi[2*k]); y[k] = SIN(K2PI*xi[2*k+1])*SIN(K2PI*xi[2*k]); z[k] = COS(K2PI*xi[2*k+1]); } /* Generate Delaunay triangulation. */ trmesh_(&Mlocal, x, y, z, list, lptr, lend, &lnew, near, next, dist, &ier); /* Check error flag. */ if (ier == 0) { /* Get Voronoi vertices. */ crlist_(&Mlocal, &Mlocal, x, y, z, list, lend, lptr, &lnew, ltri, listc, &nb, xc, yc, zc, rc, &ier); if (ier == 0) { /* Calcuate sizes of Voronoi regions. */ for (k = 0; k < M; k++) { /* Get last neighbour index. */ lpl = lend[k]; lp = lpl; j = 0; vr[3*j] = x[k]; vr[3*j+1] = y[k]; vr[3*j+2] = z[k]; do { j++; /* Get next neighbour. */ lp = lptr[lp-1]; kv = listc[lp-1]; vr[3*j] = xc[kv-1]; vr[3*j+1] = yc[kv-1]; vr[3*j+2] = zc[kv-1]; /* fprintf(stderr, "lp = %ld\t", lp); */ } while (lp != lpl); a = 0; for (el = 0; el < j; el++) { a += areas_(vr, &vr[3*(el+1)],&vr[3*(((el+1)%j)+1)]); } w[k] = a; } } } /* Deallocate memory. */ X(free)(x); X(free)(y); X(free)(z); X(free)(list); X(free)(lptr); X(free)(lend); X(free)(near); X(free)(next); X(free)(dist); X(free)(ltri); X(free)(listc); X(free)(xc); X(free)(yc); X(free)(zc); X(free)(rc); X(free)(vr); } /** Enumeration for parameter values */ enum boolean {NO = 0, YES = 1}; /** * The main program. * * \param argc The number of arguments * \param argv An array containing the arguments as C-strings * * \return Exit code * * \author Jens Keiner */ int main (int argc, char **argv) { int T; int N; int M; int M2; int t; /* Index variable for testcases */ nfsft_plan plan; /* NFSFT plan */ nfsft_plan plan2; /* NFSFT plan */ solver_plan_complex iplan; /* NFSFT plan */ int j; /* */ int k; /* */ int m; /* */ int use_nfsft; /* */ int use_nfft; /* */ int use_fpt; /* */ int cutoff; /**< The current NFFT cut-off parameter */ double threshold; /**< The current NFSFT threshold parameter */ double re; double im; double a; double xs; double *ys; double *temp; double _Complex *temp2; int qlength; double *qweights; fftw_plan fplan; fpt_set set; int npt; int npt_exp; double *alpha, *beta, *gamma; /* Read the number of testcases. */ fscanf(stdin,"testcases=%d\n",&T); fprintf(stderr,"%d\n",T); /* Process each testcase. */ for (t = 0; t < T; t++) { /* Check if the fast transform shall be used. */ fscanf(stdin,"nfsft=%d\n",&use_nfsft); fprintf(stderr,"%d\n",use_nfsft); if (use_nfsft != NO) { /* Check if the NFFT shall be used. */ fscanf(stdin,"nfft=%d\n",&use_nfft); fprintf(stderr,"%d\n",use_nfsft); if (use_nfft != NO) { /* Read the cut-off parameter. */ fscanf(stdin,"cutoff=%d\n",&cutoff); fprintf(stderr,"%d\n",cutoff); } else { /* TODO remove this */ /* Initialize unused variable with dummy value. */ cutoff = 1; } /* Check if the fast polynomial transform shall be used. */ fscanf(stdin,"fpt=%d\n",&use_fpt); fprintf(stderr,"%d\n",use_fpt); if (use_fpt != NO) { /* Read the NFSFT threshold parameter. */ fscanf(stdin,"threshold=%lf\n",&threshold); fprintf(stderr,"%lf\n",threshold); } else { /* TODO remove this */ /* Initialize unused variable with dummy value. */ threshold = 1000.0; } } else { /* TODO remove this */ /* Set dummy values. */ use_nfft = NO; use_fpt = NO; cutoff = 3; threshold = 1000.0; } /* Read the bandwidth. */ fscanf(stdin,"bandwidth=%d\n",&N); fprintf(stderr,"%d\n",N); /* Do precomputation. */ nfsft_precompute(N,threshold, ((use_nfsft==NO)?(NFSFT_NO_FAST_ALGORITHM):(0U/*NFSFT_NO_DIRECT_ALGORITHM*/)), 0U); /* Read the number of nodes. */ fscanf(stdin,"nodes=%d\n",&M); fprintf(stderr,"%d\n",M); /* */ if ((N+1)*(N+1) > M) { X(next_power_of_2_exp_int)(N, &npt, &npt_exp); fprintf(stderr, "npt = %d, npt_exp = %d\n", npt, npt_exp); fprintf(stderr,"Optimal interpolation!\n"); ys = (double*) nfft_malloc((N+1)*sizeof(double)); temp = (double*) nfft_malloc((2*N+1)*sizeof(double)); temp2 = (double _Complex*) nfft_malloc((N+1)*sizeof(double _Complex)); a = 0.0; for (j = 0; j <= N; j++) { xs = 2.0 + (2.0*j)/(N+1); ys[j] = (2.0-((j == 0)?(1.0):(0.0)))*4.0*nfft_bsplines(4,xs); //fprintf(stdout,"%3d: g(%le) = %le\n",j,xs,ys[j]); a += ys[j]; } //fprintf(stdout,"a = %le\n",a); for (j = 0; j <= N; j++) { ys[j] *= 1.0/a; } qlength = 2*N+1; qweights = (double*) nfft_malloc(qlength*sizeof(double)); fplan = fftw_plan_r2r_1d(N+1, qweights, qweights, FFTW_REDFT00, 0U); for (j = 0; j < N+1; j++) { qweights[j] = -2.0/(4*j*j-1); } fftw_execute(fplan); qweights[0] *= 0.5; for (j = 0; j < N+1; j++) { qweights[j] *= 1.0/(2.0*N+1.0); qweights[2*N+1-1-j] = qweights[j]; } fplan = fftw_plan_r2r_1d(2*N+1, temp, temp, FFTW_REDFT00, 0U); for (j = 0; j <= N; j++) { temp[j] = ((j==0 || j == 2*N)?(1.0):(0.5))*ys[j]; } for (j = N+1; j < 2*N+1; j++) { temp[j] = 0.0; } fftw_execute(fplan); for (j = 0; j < 2*N+1; j++) { temp[j] *= qweights[j]; } fftw_execute(fplan); for (j = 0; j < 2*N+1; j++) { temp[j] *= ((j==0 || j == 2*N)?(1.0):(0.5)); if (j <= N) { temp2[j] = temp[j]; } } set = fpt_init(1, npt_exp, 0U); alpha = (double*) nfft_malloc((N+2)*sizeof(double)); beta = (double*) nfft_malloc((N+2)*sizeof(double)); gamma = (double*) nfft_malloc((N+2)*sizeof(double)); alpha_al_row(alpha, N, 0); beta_al_row(beta, N, 0); gamma_al_row(gamma, N, 0); fpt_precompute(set, 0, alpha, beta, gamma, 0, 1000.0); fpt_transposed(set,0, temp2, temp2, N, 0U); fpt_finalize(set); nfft_free(alpha); nfft_free(beta); nfft_free(gamma); fftw_destroy_plan(fplan); nfft_free(qweights); nfft_free(ys); nfft_free(temp); } /* Init transform plans. */ nfsft_init_guru(&plan, N, M, ((use_nfft!=0)?(0U):(NFSFT_USE_NDFT)) | ((use_fpt!=0)?(0U):(NFSFT_USE_DPT)) | NFSFT_MALLOC_F | NFSFT_MALLOC_X | NFSFT_MALLOC_F_HAT | NFSFT_NORMALIZED | NFSFT_ZERO_F_HAT, PRE_PHI_HUT | PRE_PSI | FFTW_INIT | FFT_OUT_OF_PLACE, cutoff); if ((N+1)*(N+1) > M) { solver_init_advanced_complex(&iplan, (nfft_mv_plan_complex*)(&plan), CGNE | PRECOMPUTE_DAMP); } else { solver_init_advanced_complex(&iplan, (nfft_mv_plan_complex*)(&plan), CGNR | PRECOMPUTE_WEIGHT | PRECOMPUTE_DAMP); } /* Read the nodes and function values. */ for (j = 0; j < M; j++) { fscanf(stdin,"%le %le %le %le\n",&plan.x[2*j+1],&plan.x[2*j],&re,&im); plan.x[2*j+1] = plan.x[2*j+1]/(2.0*KPI); plan.x[2*j] = plan.x[2*j]/(2.0*KPI); if (plan.x[2*j] >= 0.5) { plan.x[2*j] = plan.x[2*j] - 1; } iplan.y[j] = re + _Complex_I * im; fprintf(stderr,"%le %le %le %le\n",plan.x[2*j+1],plan.x[2*j], creal(iplan.y[j]),cimag(iplan.y[j])); } /* Read the number of nodes. */ fscanf(stdin,"nodes_eval=%d\n",&M2); fprintf(stderr,"%d\n",M2); /* Init transform plans. */ nfsft_init_guru(&plan2, N, M2, ((use_nfft!=0)?(0U):(NFSFT_USE_NDFT)) | ((use_fpt!=0)?(0U):(NFSFT_USE_DPT)) | NFSFT_MALLOC_F | NFSFT_MALLOC_X | NFSFT_MALLOC_F_HAT | NFSFT_NORMALIZED | NFSFT_ZERO_F_HAT, PRE_PHI_HUT | PRE_PSI | FFTW_INIT | FFT_OUT_OF_PLACE, cutoff); /* Read the nodes and function values. */ for (j = 0; j < M2; j++) { fscanf(stdin,"%le %le\n",&plan2.x[2*j+1],&plan2.x[2*j]); plan2.x[2*j+1] = plan2.x[2*j+1]/(2.0*KPI); plan2.x[2*j] = plan2.x[2*j]/(2.0*KPI); if (plan2.x[2*j] >= 0.5) { plan2.x[2*j] = plan2.x[2*j] - 1; } fprintf(stderr,"%le %le\n",plan2.x[2*j+1],plan2.x[2*j]); } nfsft_precompute_x(&plan); nfsft_precompute_x(&plan2); /* Frequency weights. */ if ((N+1)*(N+1) > M) { /* Compute Voronoi weights. */ //voronoi_weights_S2(iplan.w, plan.x, M); /* Print out Voronoi weights. */ /*a = 0.0; for (j = 0; j < plan.M_total; j++) { fprintf(stderr,"%le\n",iplan.w[j]); a += iplan.w[j]; } fprintf(stderr,"sum = %le\n",a);*/ for (j = 0; j < plan.N_total; j++) { iplan.w_hat[j] = 0.0; } for (k = 0; k <= N; k++) { for (j = -k; j <= k; j++) { iplan.w_hat[NFSFT_INDEX(k,j,&plan)] = 1.0/(pow(k+1.0,2.0)); /*temp2[j]*/; } } } else { for (j = 0; j < plan.N_total; j++) { iplan.w_hat[j] = 0.0; } for (k = 0; k <= N; k++) { for (j = -k; j <= k; j++) { iplan.w_hat[NFSFT_INDEX(k,j,&plan)] = 1/(pow(k+1.0,2.5)); } } /* Compute Voronoi weights. */ voronoi_weights_S2(iplan.w, plan.x, M); /* Print out Voronoi weights. */ a = 0.0; for (j = 0; j < plan.M_total; j++) { fprintf(stderr,"%le\n",iplan.w[j]); a += iplan.w[j]; } fprintf(stderr,"sum = %le\n",a); } fprintf(stderr, "N_total = %d\n", plan.N_total); fprintf(stderr, "M_total = %d\n", plan.M_total); /* init some guess */ for (k = 0; k < plan.N_total; k++) { iplan.f_hat_iter[k] = 0.0; } /* inverse trafo */ solver_before_loop_complex(&iplan); /*for (k = 0; k < plan.M_total; k++) { printf("%le %le\n",creal(iplan.r_iter[k]),cimag(iplan.r_iter[k])); }*/ for (m = 0; m < 29; m++) { fprintf(stderr,"Residual ||r||=%e,\n",sqrt(iplan.dot_r_iter)); solver_loop_one_step_complex(&iplan); } /*CSWAP(iplan.f_hat_iter, plan.f_hat); nfsft_trafo(&plan); CSWAP(iplan.f_hat_iter, plan.f_hat); a = 0.0; b = 0.0; for (k = 0; k < plan.M_total; k++) { printf("%le %le %le\n",cabs(iplan.y[k]),cabs(plan.f[k]), cabs(iplan.y[k]-plan.f[k])); a += cabs(iplan.y[k]-plan.f[k])*cabs(iplan.y[k]-plan.f[k]); b += cabs(iplan.y[k])*cabs(iplan.y[k]); } fprintf(stderr,"relative error in 2-norm: %le\n",a/b);*/ CSWAP(iplan.f_hat_iter, plan2.f_hat); nfsft_trafo(&plan2); CSWAP(iplan.f_hat_iter, plan2.f_hat); for (k = 0; k < plan2.M_total; k++) { fprintf(stdout,"%le\n",cabs(plan2.f[k])); } solver_finalize_complex(&iplan); nfsft_finalize(&plan); nfsft_finalize(&plan2); /* Delete precomputed data. */ nfsft_forget(); if ((N+1)*(N+1) > M) { nfft_free(temp2); } } /* Process each testcase. */ /* Return exit code for successful run. */ return EXIT_SUCCESS; } /* \} */ nfft-3.3.2/applications/iterS2/writeImageTestcase.m000066400000000000000000000050511300072027400222550ustar00rootroot00000000000000function writeTestcase(file,usenfsft,usenfft,cutoff,usefpt,threshold,... bandwidth,img,itheta,iphi) %WRITEIMAGETESTCASE % WRITETESTCASE(FILE, USENFSFT, USENFFT, CUTOFF, USEFPT, THRESHOLD, % BANDWIDTH, THETA, PHI, F) % % Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 % Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. % % Write NFSFT usage flag. fprintf(file,'nfsft=%d\n',usenfsft); if (usenfsft == true) % Write NFFT usage flag. fprintf(file,'nfft=%d\n',usenfft); if (usenfft == true) % Write NFFT cut-off parameter. fprintf(file,'cutoff=%d\n',cutoff); end % Write FPT usage flag. fprintf(file,'fpt=%d\n',usefpt); if (usefpt == true) % Write FPT threshold. fprintf(file,'threshold=%e\n',threshold); end end % Write bandwidth fprintf(file,'bandwidth=%d\n',bandwidth); % Generate Image [m,n] = size(img) dtheta = pi/m; dphi = 2*pi/n; if (exist('itheta','var') == false) ts = 1; te = m; else ts = itheta(1) te = itheta(2) end if (exist('iphi','var') == false) ps = 1; pe = n; else ps = iphi(1) pe = iphi(2) end im = img(ts:te,ps:pe); r = length(find(im == 0)) theta = ((ts-0.5):(te-0.5))*dtheta; phi = ((ps-1):(pe-1))*dphi; % Write number of nodes. fprintf(file,'nodes=%d\n',((te-ts+1)*(pe-ps+1))-r); % Write nodes and function values. for j=1:length(theta) for k=1:length(phi) % Write node (j,k) and corresponding function value. if (abs(im(j,k)) ~= 0) fprintf(file,'%f %f %f %f\n',theta(j),phi(k),real(im(j,k)),imag(im(j,k))); end end end theta = ((ts-0.5):0.25:(te-0.5))*dtheta; phi = ((ps-1):0.25:(pe-1))*dphi; % Write number of nodes. fprintf(file,'nodes_eval=%d\n',length(theta)*length(phi)); % Write nodes and function values. for j=1:length(theta) for k=1:length(phi) fprintf(file,'%f %f\n',theta(j),phi(k)); end end % End of function return; nfft-3.3.2/applications/iterS2/writeTestcase.m000066400000000000000000000040351300072027400213130ustar00rootroot00000000000000function writeTestcase(file,usenfsft,usenfft,cutoff,usefpt,threshold,... bandwidth,theta,phi,f) %WRITETESTCASE - Write an iterS2 testcase definition to a file % WRITETESTCASE(FILE, USENFSFT, USENFFT, CUTOFF, USEFPT, THRESHOLD, % BANDWIDTH, THETA, PHI, F) % % Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 % Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. % % Write NFSFT usage flag. fprintf(file,'nfsft=%d\n',usenfsft); if (usenfsft == true) % Write NFFT usage flag. fprintf(file,'nfft=%d\n',usenfft); if (usenfft == true) % Write NFFT cut-off parameter. fprintf(file,'cutoff=%d\n',cutoff); end % Write FPT usage flag. fprintf(file,'fpt=%d\n',usefpt); if (usefpt == true) % Write FPT threshold. fprintf(file,'threshold=%e\n',threshold); end end % Write bandwidth fprintf(file,'bandwidth=%d\n',bandwidth); % Write number of nodes. fprintf(file,'nodes=%d\n',length(theta)); % Write nodes and function values. for j=1:length(theta) % Write node j and corresponding function value. fprintf(file,'%f %f %f %f\n',theta(j),phi(j),real(f(j)),imag(f(j))); end % Write number of nodes. fprintf(file,'nodes_eval=%d\n',m*n); % Write nodes and function values. for j=1:length(theta) for k=1:length(phi) fprintf(file,'%f %f\n',theta(j),phi(k)); end end % End of function return; nfft-3.3.2/applications/mri/000077500000000000000000000000001300072027400157245ustar00rootroot00000000000000nfft-3.3.2/applications/mri/Makefile.am000066400000000000000000000000551300072027400177600ustar00rootroot00000000000000SUBDIRS = mri2d mri3d EXTRA_DIST = doxygen.cnfft-3.3.2/applications/mri/doxygen.c000066400000000000000000000016051300072027400175470ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \defgroup applications_mri Transforms in magnetic resonance imaging * \ingroup applications */ nfft-3.3.2/applications/mri/mri2d/000077500000000000000000000000001300072027400167415ustar00rootroot00000000000000nfft-3.3.2/applications/mri/mri2d/Makefile.am000066400000000000000000000030201300072027400207700ustar00rootroot00000000000000AM_CPPFLAGS = -I$(top_srcdir)/include noinst_PROGRAMS = \ construct_data_2d \ construct_data_inh_2d1d \ construct_data_inh_3d \ reconstruct_data_gridding \ reconstruct_data_2d \ reconstruct_data_inh_3d \ reconstruct_data_inh_2d1d \ reconstruct_data_inh_nnfft construct_data_2d_SOURCES = construct_data_2d.c doxygen.h construct_data_2d_LDADD = $(top_builddir)/libnfft3.la -lm construct_data_inh_2d1d_SOURCES = construct_data_inh_2d1d.c construct_data_inh_2d1d_LDADD = $(top_builddir)/libnfft3.la -lm construct_data_inh_3d_SOURCES = construct_data_inh_3d.c construct_data_inh_3d_LDADD = $(top_builddir)/libnfft3.la -lm reconstruct_data_gridding_SOURCES = reconstruct_data_gridding.c reconstruct_data_gridding_LDADD = $(top_builddir)/libnfft3.la -lm reconstruct_data_2d_SOURCES = reconstruct_data_2d.c reconstruct_data_2d_LDADD = $(top_builddir)/libnfft3.la -lm reconstruct_data_inh_3d_SOURCES = reconstruct_data_inh_3d.c reconstruct_data_inh_3d_LDADD = $(top_builddir)/libnfft3.la -lm reconstruct_data_inh_2d1d_SOURCES = reconstruct_data_inh_2d1d.c reconstruct_data_inh_2d1d_LDADD = $(top_builddir)/libnfft3.la -lm reconstruct_data_inh_nnfft_SOURCES = reconstruct_data_inh_nnfft.c reconstruct_data_inh_nnfft_LDADD = $(top_builddir)/libnfft3.la -lm EXTRA_DIST = construct_inh.m \ construct_readout_time.m \ precompute_weights.m \ construct_knots_linogram.m \ mri_inh.m \ rms.m \ construct_knots_radial.m \ mri.m \ construct_knots_rose.m \ visualize_data.m \ construct_knots_spiral.m \ phantom.m \ README nfft-3.3.2/applications/mri/mri2d/README000066400000000000000000000015541300072027400176260ustar00rootroot00000000000000Based on the research paper: A note on the iterative MRI reconstruction from nonuniform k-space data by Tobias Knopp, Stefan Kunis and Daniel Potts Available from: http://www.mathematik.tu-chemnitz.de/~potts see also: http://www.tu-chemnitz.de/~potts/projecte/projekt_mri.php http://www.tu-chemnitz.de/~potts/projects/mri/ Furthermore see the Paper Field Inhomogeneity Correction based on Gridding Reconstruction for Magnetic Resonance Imaging by H. Eggers, Tobias Knopp, and Daniel Potts -------------------------------------------------------------------- Open MATLAB and run the script file mri.m or mri_inh.m. mri.m and mri_inh are an examples for the usage of the programs. mri.m uses a simple model without considering a field inhomogenity against what mri_inh.m considers the field inhomogeneity For questions mail us: tobias.knopp@informatik.uni-luebeck.de nfft-3.3.2/applications/mri/mri2d/construct_data_2d.c000066400000000000000000000042021300072027400225050ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include #include #ifdef HAVE_COMPLEX_H #include #endif #include "nfft3.h" /** * \defgroup applications_mri2d_construct_data_2d construct_data_2d * \ingroup applications_mri2d * \{ */ /** * construct makes an 2d-nfft */ static void construct(char * file, int N, int M) { int j,k; /* some variables */ double real; nfft_plan my_plan; /* plan for the two dimensional nfft */ FILE* fp; FILE* fk; FILE* fi; /* initialise my_plan */ nfft_init_2d(&my_plan,N,N,M); fp=fopen("knots.dat","r"); for(j=0;j #include #include #ifdef HAVE_COMPLEX_H #include #endif #include "nfft3.h" #ifndef MAX #define MAX(a,b) (((a)>(b))?(a):(b)) #endif /** * \defgroup applications_mri2d_construct_data_inh_2d1d construct_data__inh_2d1d * \ingroup applications_mri2d * \{ */ /** * construct */ static void construct(char * file, int N, int M) { int j; /* some variables */ double real; double w; double time,min_time,max_time,min_inh,max_inh; mri_inh_2d1d_plan my_plan; FILE *fp,*fout,*fi,*finh,*ftime; int my_N[3],my_n[3]; int flags = PRE_PHI_HUT| PRE_PSI |MALLOC_X| MALLOC_F_HAT| MALLOC_F| FFTW_INIT| FFT_OUT_OF_PLACE| FFTW_MEASURE| FFTW_DESTROY_INPUT; double Ts; double W,T; int N3; int m=2; double sigma = 1.25; ftime=fopen("readout_time.dat","r"); finh=fopen("inh.dat","r"); min_time=INT_MAX; max_time=INT_MIN; for(j=0;jmax_time) max_time = time; } fclose(ftime); Ts=(min_time+max_time)/2.0; min_inh=INT_MAX; max_inh=INT_MIN; for(j=0;jmax_inh) max_inh = w; } fclose(finh); N3=ceil((MAX(fabs(min_inh),fabs(max_inh))*(max_time-min_time)/2.0+m/(2*sigma))*4*sigma); T=((max_time-min_time)/2.0)/(0.5-((double) m)/N3); W=N3/T; my_N[0]=N; my_n[0]=ceil(N*sigma); my_N[1]=N; my_n[1]=ceil(N*sigma); my_N[2]=N3; my_n[2]=N3; /* initialise nfft */ mri_inh_2d1d_init_guru(&my_plan, my_N, M, my_n, m, sigma, flags, FFTW_MEASURE| FFTW_DESTROY_INPUT); ftime=fopen("readout_time.dat","r"); fp=fopen("knots.dat","r"); for(j=0;j #include #include #ifdef HAVE_COMPLEX_H #include #endif #include "nfft3.h" #ifndef MAX #define MAX(a,b) (((a)>(b))?(a):(b)) #endif /** * \defgroup applications_mri2d_construct_data_inh_3d construct_data_inh_3d * \ingroup applications_mri2d * \{ */ /** * construct */ static void construct(char * file, int N, int M) { int j; /* some variables */ double real; double w; double time,min_time,max_time,min_inh,max_inh; mri_inh_3d_plan my_plan; FILE *fp,*fout,*fi,*finh,*ftime; int my_N[3],my_n[3]; int flags = PRE_PHI_HUT| PRE_PSI |MALLOC_X| MALLOC_F_HAT| MALLOC_F| FFTW_INIT| FFT_OUT_OF_PLACE| FFTW_MEASURE| FFTW_DESTROY_INPUT; double Ts; double W; int N3; int m=2; double sigma = 1.25; ftime=fopen("readout_time.dat","r"); finh=fopen("inh.dat","r"); min_time=INT_MAX; max_time=INT_MIN; for(j=0;jmax_time) max_time = time; } fclose(ftime); Ts=(min_time+max_time)/2.0; min_inh=INT_MAX; max_inh=INT_MIN; for(j=0;jmax_inh) max_inh = w; } fclose(finh); N3=ceil((MAX(fabs(min_inh),fabs(max_inh))*(max_time-min_time)/2.0+m/(2*sigma))*4*sigma); W= MAX(fabs(min_inh),fabs(max_inh))/(0.5-((double)m)/N3); my_N[0]=N; my_n[0]=ceil(N*sigma); my_N[1]=N; my_n[1]=ceil(N*sigma); my_N[2]=N3; my_n[2]=ceil(N3*sigma); /* initialise nfft */ mri_inh_3d_init_guru(&my_plan, my_N, M, my_n, m, sigma, flags, FFTW_MEASURE| FFTW_DESTROY_INPUT); ftime=fopen("readout_time.dat","r"); fp=fopen("knots.dat","r"); for(j=0;jmax_distance), area(j)=max_distance; end sum_area = sum_area + area(j); end % norm the weights area = area / sum_area; save weights.dat -ascii area nfft-3.3.2/applications/mri/mri2d/reconstruct_data_2d.c000066400000000000000000000113331300072027400230370ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include "nfft3.h" /** * \defgroup applications_mri2d_reconstruct_data_2d reconstruct_data_2d * \ingroup applications_mri2d * \{ */ /** * reconstruct makes an inverse 2d nfft */ static void reconstruct(char* filename,int N,int M,int iteration, int weight) { int j,k,l; /* some variables */ double t0, t1; double real,imag,t; /* to read the real and imag part of a complex number */ nfft_plan my_plan; /* plan for the two dimensional nfft */ solver_plan_complex my_iplan; /* plan for the two dimensional infft */ FILE* fin; /* input file */ FILE* fout_real; /* output file */ FILE* fout_imag; /* output file */ int my_N[2],my_n[2]; /* to init the nfft */ double epsilon=0.0000003; /* epsilon is a the break criterium for the iteration */ unsigned infft_flags = CGNR | PRECOMPUTE_DAMP; /* flags for the infft*/ int m = 6; double alpha = 2.0; /* initialise my_plan */ my_N[0]=N; my_n[0]=ceil(N*alpha); my_N[1]=N; my_n[1]=ceil(N*alpha); nfft_init_guru(&my_plan, 2, my_N, M, my_n, m, PRE_PHI_HUT| PRE_PSI| MALLOC_X| MALLOC_F_HAT| MALLOC_F| FFTW_INIT| FFT_OUT_OF_PLACE, FFTW_MEASURE| FFTW_DESTROY_INPUT); /* precompute lin psi if set */ if(my_plan.flags & PRE_LIN_PSI) nfft_precompute_lin_psi(&my_plan); /* set the flags for the infft*/ if (weight) infft_flags = infft_flags | PRECOMPUTE_WEIGHT; /* initialise my_iplan, advanced */ solver_init_advanced_complex(&my_iplan,(nfft_mv_plan_complex*)&my_plan, infft_flags ); /* get the weights */ if(my_iplan.flags & PRECOMPUTE_WEIGHT) { fin=fopen("weights.dat","r"); for(j=0;j(double) N/2) my_iplan.w_hat[j*N+k]=0.0; else my_iplan.w_hat[j*N+k]=1.0; } } } /* open the input file */ fin=fopen(filename,"r"); /* read x,y,freal and fimag from the knots */ for(j=0;j #include #ifdef HAVE_COMPLEX_H #include #endif #include "nfft3.h" /** * \defgroup applications_mri2d_construct_data_gridding construct_data_gridding * \ingroup applications_mri2d * \{ */ /** * reconstruct makes a 2d-adjoint-nfft */ static void reconstruct(char* filename, int N, int M, int weight) { int j; /* some variables */ double weights; /* store one weight temporary */ double real,imag; /* to read the real and imag part of a complex number */ nfft_plan my_plan; /* plan for the two dimensional nfft */ FILE* fin; /* input file */ FILE* fweight; /* input file for the weights */ FILE *fout_real; /* output file */ FILE *fout_imag; /* output file */ int my_N[2],my_n[2]; int flags = PRE_PHI_HUT| PRE_PSI |MALLOC_X| MALLOC_F_HAT| MALLOC_F| FFTW_INIT| FFT_OUT_OF_PLACE| FFTW_MEASURE| FFTW_DESTROY_INPUT; /* initialise nfft */ my_N[0]=N; my_n[0]=ceil(N*1.2); my_N[1]=N; my_n[1]=ceil(N*1.2); nfft_init_guru(&my_plan, 2, my_N, M, my_n, 6,flags, FFTW_MEASURE| FFTW_DESTROY_INPUT); fin=fopen(filename,"r"); fweight=fopen("weights.dat","r"); for(j=0;j #include #include #include #include "nfft3.h" #ifndef MAX #define MAX(a,b) (((a)>(b))?(a):(b)) #endif /** * \defgroup applications_mri2d_reconstruct_data_inh_2d1d reconstruct_data__inh_2d1d * \ingroup applications_mri2d * \{ */ static void reconstruct(char* filename,int N,int M,int iteration , int weight) { int j,k,l; double time,min_time,max_time,min_inh,max_inh; double t0, t1; double t,real,imag; double w,epsilon=0.0000003; /* epsilon is a the break criterium for the iteration */; mri_inh_2d1d_plan my_plan; solver_plan_complex my_iplan; FILE* fp,*fw,*fout_real,*fout_imag,*finh,*ftime; int my_N[3],my_n[3]; int flags = PRE_PHI_HUT| PRE_PSI |MALLOC_X| MALLOC_F_HAT| MALLOC_F| FFTW_INIT| FFT_OUT_OF_PLACE; unsigned infft_flags = CGNR | PRECOMPUTE_DAMP; double Ts; double W,T; int N3; int m=2; double sigma = 1.25; ftime=fopen("readout_time.dat","r"); finh=fopen("inh.dat","r"); min_time=INT_MAX; max_time=INT_MIN; for(j=0;jmax_time) max_time = time; } fclose(ftime); Ts=(min_time+max_time)/2.0; min_inh=INT_MAX; max_inh=INT_MIN; for(j=0;jmax_inh) max_inh = w; } fclose(finh); N3=ceil((MAX(fabs(min_inh),fabs(max_inh))*(max_time-min_time)/2.0+(m)/(2*sigma))*4*sigma); /* N3 has to be even */ if(N3%2!=0) N3++; T=((max_time-min_time)/2.0)/(0.5-((double) (m))/N3); W=N3/T; my_N[0]=N; my_n[0]=ceil(N*sigma); my_N[1]=N; my_n[1]=ceil(N*sigma); my_N[2]=N3; my_n[2]=N3; /* initialise nfft */ mri_inh_2d1d_init_guru(&my_plan, my_N, M, my_n, m, sigma, flags, FFTW_MEASURE| FFTW_DESTROY_INPUT); /* precompute lin psi if set */ if(my_plan.plan.flags & PRE_LIN_PSI) nfft_precompute_lin_psi(&my_plan.plan); if (weight) infft_flags = infft_flags | PRECOMPUTE_WEIGHT; /* initialise my_iplan, advanced */ solver_init_advanced_complex(&my_iplan,(nfft_mv_plan_complex*)(&my_plan), infft_flags ); /* get the weights */ if(my_iplan.flags & PRECOMPUTE_WEIGHT) { fw=fopen("weights.dat","r"); for(j=0;j(double) N/2) my_iplan.w_hat[j*N+k]=0.0; else my_iplan.w_hat[j*N+k]=1.0; } } } fp=fopen(filename,"r"); ftime=fopen("readout_time.dat","r"); for(j=0;j #include #include #include #include "nfft3.h" #ifndef MAX #define MAX(a,b) (((a)>(b))?(a):(b)) #endif /** * \defgroup applications_mri2d_reconstruct_data_inh_3d reconstruct_data_inh_3d * \ingroup applications_mri2d * \{ */ static void reconstruct(char* filename,int N,int M,int iteration , int weight) { int j,k,l; double t0, t1; double time,min_time,max_time,min_inh,max_inh; double t,real,imag; double w,epsilon=0.0000003; /* epsilon is a the break criterium for the iteration */; mri_inh_3d_plan my_plan; solver_plan_complex my_iplan; FILE* fp,*fw,*fout_real,*fout_imag,*finh,*ftime; int my_N[3],my_n[3]; int flags = PRE_PHI_HUT| PRE_PSI |MALLOC_X| MALLOC_F_HAT| MALLOC_F| FFTW_INIT| FFT_OUT_OF_PLACE; unsigned infft_flags = CGNR | PRECOMPUTE_DAMP; double Ts; double W; int N3; int m=2; double sigma = 1.25; ftime=fopen("readout_time.dat","r"); finh=fopen("inh.dat","r"); min_time=INT_MAX; max_time=INT_MIN; for(j=0;jmax_time) max_time = time; } fclose(ftime); Ts=(min_time+max_time)/2.0; min_inh=INT_MAX; max_inh=INT_MIN; for(j=0;jmax_inh) max_inh = w; } fclose(finh); N3=ceil((MAX(fabs(min_inh),fabs(max_inh))*(max_time-min_time)/2.0+m/(2*sigma))*4*sigma); /* N3 has to be even */ if(N3%2!=0) N3++; W= MAX(fabs(min_inh),fabs(max_inh))/(0.5-((double) m)/N3); my_N[0]=N;my_n[0]=ceil(N*sigma); my_N[1]=N; my_n[1]=ceil(N*sigma); my_N[2]=N3; my_n[2]=ceil(N3*sigma); /* initialise nfft */ mri_inh_3d_init_guru(&my_plan, my_N, M, my_n, m, sigma, flags, FFTW_MEASURE| FFTW_DESTROY_INPUT); if (weight) infft_flags = infft_flags | PRECOMPUTE_WEIGHT; /* initialise my_iplan, advanced */ solver_init_advanced_complex(&my_iplan,(nfft_mv_plan_complex*)(&my_plan), infft_flags ); /* get the weights */ if(my_iplan.flags & PRECOMPUTE_WEIGHT) { fw=fopen("weights.dat","r"); for(j=0;j(double) N/2) my_iplan.w_hat[j*N+k]=0.0; else my_iplan.w_hat[j*N+k]=1.0; } } } fp=fopen(filename,"r"); ftime=fopen("readout_time.dat","r"); for(j=0;j #include #include #include #include "nfft3.h" #ifndef MAX #define MAX(a,b) (((a)>(b))?(a):(b)) #endif /** * \defgroup applications_mri2d_construct_data_inh_nnfft construct_data_inh_nnfft * \ingroup applications_mri2d * \{ */ /** * reconstruct */ static void reconstruct(char* filename,int N,int M,int iteration, int weight) { int j,k,l; /* some variables */ nnfft_plan my_plan; /* plan for the two dimensional nfft */ solver_plan_complex my_iplan; /* plan for the two dimensional infft */ FILE* fin; /* input file */ FILE* finh; FILE* ftime; FILE* fout_real; /* output file */ FILE* fout_imag; /* output file */ int my_N[3],my_n[3]; /* to init the nfft */ double t0, t1; double t,epsilon=0.0000003; /* epsilon is a the break criterium for the iteration */ unsigned infft_flags = CGNR | PRECOMPUTE_DAMP; /* flags for the infft*/ double time,min_time,max_time,min_inh,max_inh; double real,imag; double *w; double Ts; double W; int N3; int m=2; double sigma = 1.25; w = (double*)nfft_malloc(N*N*sizeof(double)); ftime=fopen("readout_time.dat","r"); finh=fopen("inh.dat","r"); min_time=INT_MAX; max_time=INT_MIN; for(j=0;jmax_time) max_time = time; } fclose(ftime); Ts=(min_time+max_time)/2.0; min_inh=INT_MAX; max_inh=INT_MIN; for(j=0;jmax_inh) max_inh = w[j]; } fclose(finh); N3=ceil((MAX(fabs(min_inh),fabs(max_inh))*(max_time-min_time)/2.0)*4); W=MAX(fabs(min_inh),fabs(max_inh))*2.0; fprintf(stderr,"3: %i %e %e %e %e %e %e\n",N3,W,min_inh,max_inh,min_time,max_time,Ts); /* initialise my_plan */ my_N[0]=N;my_n[0]=ceil(N*sigma); my_N[1]=N; my_n[1]=ceil(N*sigma); my_N[2]=N3; my_n[2]=ceil(N3*sigma); nnfft_init_guru(&my_plan, 3, N*N, M, my_N,my_n,m, PRE_PSI| PRE_PHI_HUT| MALLOC_X| MALLOC_V| MALLOC_F_HAT| MALLOC_F ); /* precompute lin psi if set */ if(my_plan.nnfft_flags & PRE_LIN_PSI) nnfft_precompute_lin_psi(&my_plan); /* set the flags for the infft*/ if (weight) infft_flags = infft_flags | PRECOMPUTE_WEIGHT; /* initialise my_iplan, advanced */ solver_init_advanced_complex(&my_iplan,(nfft_mv_plan_complex*)(&my_plan), infft_flags ); /* get the weights */ if(my_iplan.flags & PRECOMPUTE_WEIGHT) { fin=fopen("weights.dat","r"); for(j=0;j(double) N/2) my_iplan.w_hat[j*N+k]=0.0; else my_iplan.w_hat[j*N+k]=1.0; } } } /* open the input file */ fin=fopen(filename,"r"); ftime=fopen("readout_time.dat","r"); for(j=0;jN/2, A(k,l)=0; end end end % plot the two dimensional phantom figure(2*num_fig-1) imagesc(A, [0 1.2]); colormap(gray(256)); colorbar; title(caption); file_out =[file '.jpg']; print('-djpeg',file_out); % plot the N/2 row figure(2*num_fig) file_out = [file 'row' '.png']; plot(1:N,A(N/2,:)); axis([1 N 0 1.2]); title([caption ' - The ' int2str(N/2) 'th row']); print('-djpeg',file_out); nfft-3.3.2/applications/mri/mri3d/000077500000000000000000000000001300072027400167425ustar00rootroot00000000000000nfft-3.3.2/applications/mri/mri3d/Makefile.am000066400000000000000000000021431300072027400207760ustar00rootroot00000000000000AM_CPPFLAGS = -I$(top_srcdir)/include noinst_PROGRAMS = \ construct_data_2d1d \ construct_data_3d \ reconstruct_data_gridding \ reconstruct_data_2d1d \ reconstruct_data_3d construct_data_2d1d_SOURCES = construct_data_2d1d.c doxygen.h construct_data_2d1d_LDADD = $(top_builddir)/libnfft3.la @fftw3_LDFLAGS@ @fftw3_LIBS@ construct_data_3d_SOURCES = construct_data_3d.c construct_data_3d_LDADD = $(top_builddir)/libnfft3.la -lm reconstruct_data_gridding_SOURCES = reconstruct_data_gridding.c reconstruct_data_gridding_LDADD = $(top_builddir)/libnfft3.la @fftw3_LDFLAGS@ @fftw3_LIBS@ reconstruct_data_2d1d_SOURCES = reconstruct_data_2d1d.c reconstruct_data_2d1d_LDADD = $(top_builddir)/libnfft3.la @fftw3_LDFLAGS@ @fftw3_LIBS@ reconstruct_data_3d_SOURCES = reconstruct_data_3d.c reconstruct_data_3d_LDADD = $(top_builddir)/libnfft3.la -lm EXTRA_DIST = mri.m \ construct_knots_linogram.m \ construct_knots_radial_3d.m \ construct_knots_radial.m \ construct_knots_rose.m \ construct_knots_spiral.m \ construct_phantom.m \ precompute_weights_2d.m \ rms.m \ visualize_data.m \ README nfft-3.3.2/applications/mri/mri3d/README000066400000000000000000000010431300072027400176200ustar00rootroot00000000000000Based on the research paper: A note on the iterative MRI reconstruction from nonuniform k-space data by Tobias Knopp, Stefan Kunis and Daniel Potts Available from: http://www.tu-chemnitz.de/~potts see also: http://www.tu-chemnitz.de/~potts/projecte/projekt_mri.php http://www.tu-chemnitz.de/~potts/projecte/ijbi -------------------------------------------------------------------- Open MATLAB and run the script file mri.m. mri.m is an example for the usage of the programs. For questions mail us: tobias.knopp@informatik.uni-luebeck.de nfft-3.3.2/applications/mri/mri3d/construct_data_2d1d.c000066400000000000000000000065721300072027400227470ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include #include #ifdef HAVE_COMPLEX_H #include #endif #include "nfft3.h" /** * \defgroup applications_mri3d_construct_data_1d2d construct_data_1d2d * \ingroup applications_mri3d * \{ */ /** * construct makes an 2d-nfft for every slice */ static void construct(char * file, int N, int M, int Z, fftw_complex *mem) { int j,z; /* some variables */ double tmp; /* a placeholder */ nfft_plan my_plan; /* plan for the two dimensional nfft */ FILE* fp; /* initialise my_plan */ nfft_init_2d(&my_plan,N,N,M/Z); fp=fopen("knots.dat","r"); for(j=0;j #include #ifdef HAVE_COMPLEX_H #include #endif #include "nfft3.h" /** * \defgroup applications_mri3d_construct_data_3d construct_data_3d * \ingroup applications_mri3d * \{ */ static void construct(char * file, int N, int M, int Z) { int j,k,l; /* some variables */ double real; nfft_plan my_plan; /* plan for the three dimensional nfft */ FILE* fp,*fk; int my_N[3],my_n[3]; /* to init the nfft */ /* initialise my_plan */ //nfft_init_3d(&my_plan,Z,N,N,M); my_N[0]=Z; my_n[0]=ceil(Z*1.2); my_N[1]=N; my_n[1]=ceil(N*1.2); my_N[2]=N; my_n[2]=ceil(N*1.2); nfft_init_guru(&my_plan, 3, my_N, M, my_n, 6, PRE_PHI_HUT| PRE_PSI |MALLOC_X| MALLOC_F_HAT| MALLOC_F| FFTW_INIT| FFT_OUT_OF_PLACE, FFTW_MEASURE| FFTW_DESTROY_INPUT); fp=fopen("knots.dat","r"); for(j=0;j= 0 & y_ >= 0, phi=asin(y_/r); elseif x_ < 0 & y_ > 0, phi=asin(-y_/r)+pi; elseif x_ <= 0 & y_ <= 0, phi=asin(-y_/r)+pi; elseif x_ > 0 & y_ < 0, phi=asin(y_/r); end if(((r*cos(pi*A(l,6)/180+phi)+A(l,4))/A(l,2))^2+... ((r*sin(pi*A(l,6)/180+phi)+A(l,5))/A(l,3))^2+... ((z/(Z/2)-1)/A(l,3))^2 <= 1 ), if B(x,y,z) > 0.1 & l>2, B(x,y,z) = B(x,y,z) +A(l,1); else B(x,y,z) = A(l,1); end end end end end end % place the matrix B in the middle of the matrix C C=zeros(N,N,Z); C(N/2-N_/2+1:N/2+N_/2,N/2-N_/2+1:N/2+N_/2,:)=B; B=C; % rotate the matrix B for z=1:Z, B(:,:,z)=rot90(rot90(rot90((B(:,:,z))))); end output=zeros(Z,N*N); for z_=0:Z-1, output(z_+1,:)=reshape(B(:,:,z_+1),1,N*N); end save input_f.dat -ascii output nfft-3.3.2/applications/mri/mri3d/doxygen.h000066400000000000000000000015601300072027400205720ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \defgroup applications_mri3d 3D transforms * \ingroup applications_mri */ nfft-3.3.2/applications/mri/mri3d/mri.m000066400000000000000000000077621300072027400177230ustar00rootroot00000000000000% Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 % Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. % % This script file is an example of the usage N=48; % points per row / column Z=48; % number of slices % Construct the raw data of the phantom % and write it to input_f.dat % To use another example than the phantom % just put the reshape of your example into input_f.dat construct_phantom(N,Z); % Construct the knots in k-space and write them to knots.dat % Different knots like spiral,rose,radial,radial_3d or linogram can be chosen % The radial_3d knots just work with construct_data_3d and reconstruct_data_3d % Then the weights are generated in construct_knots_radial_3d % M is the number of knots M = construct_knots_spiral(N,Z); % First make N^2 1d-FFT, then Z 2d-NFFT on the constructed knots % and write the output to output_phantom_nfft.dat if ispc cmd='construct_data_2d1d.exe'; else cmd='./construct_data_2d1d'; end system([cmd ' output_phantom_nfft.dat '... int2str(N) ' ' int2str(M) ' ' int2str(Z)]); % Precompute the weights using voronoi cells % and write them to weights.dat precompute_weights_2d('output_phantom_nfft.dat',M,Z); % First make Z inverse 2d-NFFT, then N^2 inverse 1d-FFT % and write the output to output_real.dat and output_imag.dat % The usage is "./reconstruct_data_2d1d filename N M Z ITER WEIGHTS" % where ITER is the number of iteration and WEIGHTS is 1 % if the weights are used 0 else if ispc cmd='reconstruct_data_2d1d.exe'; else cmd='./reconstruct_data_2d1d'; end system([cmd ' output_phantom_nfft.dat ' ... int2str(N) ' ' int2str(M) ' ' int2str(Z) ' 3 1']); % Visualize the three dimensional phantom. Makes a pic of % every slice and one plot of the N/2 row of the 10th plane. visualize_data('pics_2+1d/pic', N, Z, 1, 'Inverse 2d1d-NFFT - 3. iteration - spiral knots'); % Compute the root mean square rms('pics_2+1d/rms.txt'); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % The same as above but reconstructed with gridding. % That means first an adjoint 2d-NFFT, then a 1d-FFT. % The ITER parameter is obsolent and just for compatibility if ispc cmd='reconstruct_data_gridding.exe'; else cmd='./reconstruct_data_gridding'; end system([cmd ' output_phantom_nfft.dat ' ... int2str(N) ' ' int2str(M) ' ' int2str(Z) ' 0 1']); visualize_data('pics_gridding/pic', N, Z, 2, 'Adjoint 2d1d-NFFT (Gridding) - spiral knots'); rms('pics_gridding/rms.txt'); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % The same as above but reconstructed with a 3d-nfft if ispc cmd='reconstruct_data_3d.exe'; else cmd='./reconstruct_data_3d'; end system([cmd ' output_phantom_nfft.dat ' ... int2str(N) ' ' int2str(M) ' ' int2str(Z) ' 1 1']); visualize_data('pics_3d/pic', N, Z, 3, 'Inverse 3d-NFFT - 1. iteration - spiral knots'); rms('pics_3d/rms.txt'); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % An example with the radial_3d knots % please uncomment to try %M = construct_knots_radial_3d(N,N*3/2); %system(['./construct_data_3d ' 'output_phantom_nfft.dat '... % int2str(N) ' ' int2str(M) ' ' int2str(Z)]); %system(['./reconstruct_data_3d ' 'output_phantom_nfft.dat ' ... % int2str(N) ' ' int2str(M) ' ' int2str(Z) ' 3 1']); %visualize_data('pics_3d/pic_', N, Z, 4, 'Inverse 3d-NFFT - 3. iteration - radial_3d knots'); %rms('pics_3d/rms.txt'); nfft-3.3.2/applications/mri/mri3d/precompute_weights_2d.m000066400000000000000000000036671300072027400234360ustar00rootroot00000000000000% Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 % Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. function [] = precompute_weights_2d ( file,M,Z ) input=load(file); kx = input(1:M/Z,1); ky = input(1:M/Z,2); kxy=[kx ky]; % compute the voronoi regions [V,C] = voronoin(kxy,{'QJ'}); % the surface of the knots is written to area area = []; % sum of all surfaces sum_area = 0; % the maximum distance two nearest neighbour have % to get the surface we store max_distance^2 max_distance=0; % compute the surface of the knots for j= 1:length(kxy) x = V(C{j},1); y = V(C{j},2); lxy = length(x); if(lxy==0) % a knot exists more than one time A=0; else A = abs(sum(0.5*(x([2:lxy 1])-x(:)).* ... (y([2:lxy 1]) + y(:)))); end area = [area A]; min_distance = min((2*(x-kxy(j,1))).^2+(2*(y-kxy(j,2))).^2); max_distance = max([max_distance min_distance]); end % if the surface of a knot is bigger than max_distance^2 % or isnan or isinf, then take max_distance^2 for j=1:length(area), if(isnan(area(j)) | isinf(area(j))| area(j)>max_distance), area(j)=max_distance; end sum_area = sum_area + area(j); end % norm the weights area = area / sum_area; % stack the weights for every slice out=[]; for z=0:Z-1, out=[out area]; end save weights.dat -ascii out nfft-3.3.2/applications/mri/mri3d/reconstruct_data_2d1d.c000066400000000000000000000141731300072027400232720ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include #include #ifdef HAVE_COMPLEX_H #include #endif #include "nfft3.h" /** * \defgroup applications_mri3d_reconstruct_data_1d2d reconstruct_data_1d2d * \ingroup applications_mri3d * \{ */ /** * reconstruct makes an inverse 2d-nfft for every slice */ static void reconstruct(char* filename,int N,int M,int Z,int iteration, int weight, fftw_complex *mem) { int j,k,l,z; /* some variables */ double real,imag; /* to read the real and imag part of a complex number */ nfft_plan my_plan; /* plan for the two dimensional nfft */ solver_plan_complex my_iplan; /* plan for the two dimensional infft */ FILE* fin; /* input file */ int my_N[2],my_n[2]; /* to init the nfft */ double tmp, epsilon=0.0000003;/* tmp to read the obsolent z from the input file epsilon is the break criterium for the iteration */ unsigned infft_flags = CGNR | PRECOMPUTE_DAMP; /* flags for the infft */ /* initialise my_plan */ my_N[0]=N;my_n[0]=ceil(N*1.2); my_N[1]=N; my_n[1]=ceil(N*1.2); nfft_init_guru(&my_plan, 2, my_N, M/Z, my_n, 6, PRE_PHI_HUT| PRE_PSI| MALLOC_X| MALLOC_F_HAT| MALLOC_F| FFTW_INIT| FFT_OUT_OF_PLACE, FFTW_MEASURE| FFTW_DESTROY_INPUT); /* precompute lin psi if set */ if(my_plan.flags & PRE_LIN_PSI) nfft_precompute_lin_psi(&my_plan); /* set the flags for the infft*/ if (weight) infft_flags = infft_flags | PRECOMPUTE_WEIGHT; /* initialise my_iplan, advanced */ solver_init_advanced_complex(&my_iplan,(nfft_mv_plan_complex*)(&my_plan), infft_flags ); /* get the weights */ if(my_iplan.flags & PRECOMPUTE_WEIGHT) { fin=fopen("weights.dat","r"); for(j=0;j(double) N/2) my_iplan.w_hat[j*N+k]=0.0; else my_iplan.w_hat[j*N+k]=1.0; } } } /* open the input file */ fin=fopen(filename,"r"); /* For every Layer*/ for(z=0;z #include #ifdef HAVE_COMPLEX_H #include #endif #include "nfft3.h" /** * \defgroup applications_mri3d_reconstruct_data_3d reconstruct_data_3d * \ingroup applications_mri3d * \{ */ /** * reconstruct makes an inverse 3d-nfft */ static void reconstruct(char* filename,int N,int M,int Z,int iteration, int weight) { int j,k,z,l; /* some variables */ double real,imag; /* to read the real and imag part of a complex number */ nfft_plan my_plan; /* plan for the two dimensional nfft */ solver_plan_complex my_iplan; /* plan for the two dimensional infft */ FILE* fin; /* input file */ FILE* fout_real; /* output file (real part) */ FILE* fout_imag; /* output file (imag part) */ int my_N[3],my_n[3]; /* to init the nfft */ double epsilon=0.0000003; /* tmp to read the obsolent z from 700.acs epsilon is a the break criterion for the iteration */ unsigned infft_flags = CGNR | PRECOMPUTE_DAMP; /* flags for the infft */ /* initialise my_plan, specific. we don't precompute psi */ my_N[0]=Z; my_n[0]=ceil(Z*1.2); my_N[1]=N; my_n[1]=ceil(N*1.2); my_N[2]=N; my_n[2]=ceil(N*1.2); nfft_init_guru(&my_plan, 3, my_N, M, my_n, 6, PRE_PHI_HUT| PRE_PSI |MALLOC_X| MALLOC_F_HAT| MALLOC_F| FFTW_INIT| FFT_OUT_OF_PLACE, FFTW_MEASURE| FFTW_DESTROY_INPUT); /* precompute lin psi */ if(my_plan.flags & PRE_LIN_PSI) nfft_precompute_lin_psi(&my_plan); if (weight) infft_flags = infft_flags | PRECOMPUTE_WEIGHT; /* initialise my_iplan, advanced */ solver_init_advanced_complex(&my_iplan,(nfft_mv_plan_complex*)(&my_plan), infft_flags ); /* get the weights */ if(my_iplan.flags & PRECOMPUTE_WEIGHT) { fin=fopen("weights.dat","r"); for(j=0;j(double) N/2) my_iplan.w_hat[z*N*N+j*N+k]=0.0; else my_iplan.w_hat[z*N*N+j*N+k]=1.0; } } } } /* open the input file */ fin=fopen(filename,"r"); /* open the output files */ fout_real=fopen("output_real.dat","w"); fout_imag=fopen("output_imag.dat","w"); /* read x,y,freal and fimag from the knots */ for(j=0;j #include #ifdef HAVE_COMPLEX_H #include #endif #include "nfft3.h" /** * \defgroup applications_mri3d_reconstruct_data_gridding reconstruct_data_gridding * \ingroup applications_mri3d * \{ */ /** * reconstruct makes an 2d-adjoint-nfft for every slice */ static void reconstruct(char* filename,int N,int M,int Z, int weight ,fftw_complex *mem) { int j,k,z; /* some variables */ double weights; /* store one weight temporary */ double tmp; /* tmp to read the obsolent z from the input file */ double real,imag; /* to read the real and imag part of a complex number */ nfft_plan my_plan; /* plan for the two dimensional nfft */ int my_N[2],my_n[2]; /* to init the nfft */ FILE* fin; /* input file */ FILE* fweight; /* input file for the weights */ /* initialise my_plan */ my_N[0]=N; my_n[0]=ceil(N*1.2); my_N[1]=N; my_n[1]=ceil(N*1.2); nfft_init_guru(&my_plan, 2, my_N, M/Z, my_n, 6, PRE_PHI_HUT| PRE_PSI| MALLOC_X| MALLOC_F_HAT| MALLOC_F| FFTW_INIT| FFT_OUT_OF_PLACE, FFTW_MEASURE| FFTW_DESTROY_INPUT); /* precompute lin psi if set */ if(my_plan.flags & PRE_LIN_PSI) nfft_precompute_lin_psi(&my_plan); fin=fopen(filename,"r"); for(z=0;z #include #include #define @NFFT_PRECISION_MACRO@ #include "nfft3mp.h" /** * \defgroup applications_polarFFT_linogramm linogram_fft_test * \ingroup applications_polarFFT * \{ */ NFFT_R GLOBAL_elapsed_time; /** Generates the points x with weights w * for the linogram grid with T slopes and R offsets. */ static int linogram_grid(int T, int rr, NFFT_R *x, NFFT_R *w) { int t, r; NFFT_R W = (NFFT_R) T * (((NFFT_R) rr / NFFT_K(2.0)) * ((NFFT_R) rr / NFFT_K(2.0)) + NFFT_K(1.0) / NFFT_K(4.0)); for (t = -T / 2; t < T / 2; t++) { for (r = -rr / 2; r < rr / 2; r++) { if (t < 0) { x[2 * ((t + T / 2) * rr + (r + rr / 2)) + 0] = (NFFT_R) (r) / (NFFT_R)(rr); x[2 * ((t + T / 2) * rr + (r + rr / 2)) + 1] = NFFT_K(4.0) * ((NFFT_R)(t) + (NFFT_R)(T) / NFFT_K(4.0)) / (NFFT_R)(T) * (NFFT_R)(r) / (NFFT_R)(rr); } else { x[2 * ((t + T / 2) * rr + (r + rr / 2)) + 0] = -NFFT_K(4.0) * ((NFFT_R)(t) - (NFFT_R)(T) / NFFT_K(4.0)) / (NFFT_R)(T) * (NFFT_R)(r) / (NFFT_R)(rr); x[2 * ((t + T / 2) * rr + (r + rr / 2)) + 1] = (NFFT_R) r / (NFFT_R)(rr); } if (r == 0) w[(t + T / 2) * rr + (r + rr / 2)] = NFFT_K(1.0) / NFFT_K(4.0) / W; else w[(t + T / 2) * rr + (r + rr / 2)] = NFFT_M(fabs)((NFFT_R) r) / W; } } return T * rr; /** return the number of knots */ } /** discrete pseudo-polar FFT */ static int linogram_dft(NFFT_C *f_hat, int NN, NFFT_C *f, int T, int rr, int m) { double t0, t1; int j, k; /**< index for nodes and freqencies */ NFFT(plan) my_nfft_plan; /**< plan for the nfft-2D */ NFFT_R *x, *w; /**< knots and associated weights */ int N[2], n[2]; int M = T * rr; /**< number of knots */ N[0] = NN; n[0] = 2 * N[0]; /**< oversampling factor sigma=2 */ N[1] = NN; n[1] = 2 * N[1]; /**< oversampling factor sigma=2 */ x = (NFFT_R *) NFFT(malloc)((size_t)(2 * T * rr) * (sizeof(NFFT_R))); if (x == NULL) return EXIT_FAILURE; w = (NFFT_R *) NFFT(malloc)((size_t)(T * rr) * (sizeof(NFFT_R))); if (w == NULL) return EXIT_FAILURE; /** init two dimensional NFFT plan */ NFFT(init_guru)(&my_nfft_plan, 2, N, M, n, m, PRE_PHI_HUT | PRE_PSI | MALLOC_X | MALLOC_F_HAT | MALLOC_F | FFTW_INIT | FFT_OUT_OF_PLACE, FFTW_MEASURE | FFTW_DESTROY_INPUT); /** init nodes from linogram grid*/ linogram_grid(T, rr, x, w); for (j = 0; j < my_nfft_plan.M_total; j++) { my_nfft_plan.x[2 * j + 0] = x[2 * j + 0]; my_nfft_plan.x[2 * j + 1] = x[2 * j + 1]; } /** init Fourier coefficients from given image */ for (k = 0; k < my_nfft_plan.N_total; k++) my_nfft_plan.f_hat[k] = f_hat[k]; /** NFFT-2D */ t0 = NFFT(clock_gettime_seconds)(); NFFT(trafo_direct)(&my_nfft_plan); t1 = NFFT(clock_gettime_seconds)(); GLOBAL_elapsed_time = (t1 - t0); /** copy result */ for (j = 0; j < my_nfft_plan.M_total; j++) f[j] = my_nfft_plan.f[j]; /** finalise the plans and free the variables */ NFFT(finalize)(&my_nfft_plan); NFFT(free)(x); NFFT(free)(w); return EXIT_SUCCESS; } /** NFFT-based pseudo-polar FFT */ static int linogram_fft(NFFT_C *f_hat, int NN, NFFT_C *f, int T, int rr, int m) { double t0, t1; int j, k; /**< index for nodes and freqencies */ NFFT(plan) my_nfft_plan; /**< plan for the nfft-2D */ NFFT_R *x, *w; /**< knots and associated weights */ int N[2], n[2]; int M = T * rr; /**< number of knots */ N[0] = NN; n[0] = 2 * N[0]; /**< oversampling factor sigma=2 */ N[1] = NN; n[1] = 2 * N[1]; /**< oversampling factor sigma=2 */ x = (NFFT_R *) NFFT(malloc)((size_t)(2 * T * rr) * (sizeof(NFFT_R))); if (x == NULL) return EXIT_FAILURE; w = (NFFT_R *) NFFT(malloc)((size_t)(T * rr) * (sizeof(NFFT_R))); if (w == NULL) return EXIT_FAILURE; /** init two dimensional NFFT plan */ NFFT(init_guru)(&my_nfft_plan, 2, N, M, n, m, PRE_PHI_HUT | PRE_PSI | MALLOC_X | MALLOC_F_HAT | MALLOC_F | FFTW_INIT | FFT_OUT_OF_PLACE, FFTW_MEASURE | FFTW_DESTROY_INPUT); /** init nodes from linogram grid*/ linogram_grid(T, rr, x, w); for (j = 0; j < my_nfft_plan.M_total; j++) { my_nfft_plan.x[2 * j + 0] = x[2 * j + 0]; my_nfft_plan.x[2 * j + 1] = x[2 * j + 1]; } /** precompute psi, the entries of the matrix B */ if (my_nfft_plan.flags & PRE_LIN_PSI) NFFT(precompute_lin_psi)(&my_nfft_plan); if (my_nfft_plan.flags & PRE_PSI) NFFT(precompute_psi)(&my_nfft_plan); if (my_nfft_plan.flags & PRE_FULL_PSI) NFFT(precompute_full_psi)(&my_nfft_plan); /** init Fourier coefficients from given image */ for (k = 0; k < my_nfft_plan.N_total; k++) my_nfft_plan.f_hat[k] = f_hat[k]; /** NFFT-2D */ t0 = NFFT(clock_gettime_seconds)(); NFFT(trafo)(&my_nfft_plan); t1 = NFFT(clock_gettime_seconds)(); GLOBAL_elapsed_time = (t1 - t0); /** copy result */ for (j = 0; j < my_nfft_plan.M_total; j++) f[j] = my_nfft_plan.f[j]; /** finalise the plans and free the variables */ NFFT(finalize)(&my_nfft_plan); NFFT(free)(x); NFFT(free)(w); return EXIT_SUCCESS; } /** NFFT-based inverse pseudo-polar FFT */ static int inverse_linogram_fft(NFFT_C *f, int T, int rr, NFFT_C *f_hat, int NN, int max_i, int m) { double t0, t1; int j, k; /**< index for nodes and freqencies */ NFFT(plan) my_nfft_plan; /**< plan for the nfft-2D */ SOLVER(plan_complex) my_infft_plan; /**< plan for the inverse nfft */ NFFT_R *x, *w; /**< knots and associated weights */ int l; /**< index for iterations */ int N[2], n[2]; int M = T * rr; /**< number of knots */ N[0] = NN; n[0] = 2 * N[0]; /**< oversampling factor sigma=2 */ N[1] = NN; n[1] = 2 * N[1]; /**< oversampling factor sigma=2 */ x = (NFFT_R *) NFFT(malloc)((size_t)(2 * T * rr) * (sizeof(NFFT_R))); if (x == NULL) return EXIT_FAILURE; w = (NFFT_R *) NFFT(malloc)((size_t)(T * rr) * (sizeof(NFFT_R))); if (w == NULL) return EXIT_FAILURE; /** init two dimensional NFFT plan */ NFFT(init_guru)(&my_nfft_plan, 2, N, M, n, m, PRE_PHI_HUT | PRE_PSI | MALLOC_X | MALLOC_F_HAT | MALLOC_F | FFTW_INIT | FFT_OUT_OF_PLACE, FFTW_MEASURE | FFTW_DESTROY_INPUT); /** init two dimensional infft plan */ SOLVER(init_advanced_complex)(&my_infft_plan, (NFFT(mv_plan_complex)*) (&my_nfft_plan), CGNR | PRECOMPUTE_WEIGHT); /** init nodes, given samples and weights */ linogram_grid(T, rr, x, w); for (j = 0; j < my_nfft_plan.M_total; j++) { my_nfft_plan.x[2 * j + 0] = x[2 * j + 0]; my_nfft_plan.x[2 * j + 1] = x[2 * j + 1]; my_infft_plan.y[j] = f[j]; my_infft_plan.w[j] = w[j]; } /** precompute psi, the entries of the matrix B */ if (my_nfft_plan.flags & PRE_LIN_PSI) NFFT(precompute_lin_psi)(&my_nfft_plan); if (my_nfft_plan.flags & PRE_PSI) NFFT(precompute_psi)(&my_nfft_plan); if (my_nfft_plan.flags & PRE_FULL_PSI) NFFT(precompute_full_psi)(&my_nfft_plan); /** initialise damping factors */ if (my_infft_plan.flags & PRECOMPUTE_DAMP) for (j = 0; j < my_nfft_plan.N[0]; j++) for (k = 0; k < my_nfft_plan.N[1]; k++) { my_infft_plan.w_hat[j * my_nfft_plan.N[1] + k] = ( NFFT_M(sqrt)( NFFT_M(pow)((NFFT_R)(j - my_nfft_plan.N[0] / 2), NFFT_K(2.0)) + NFFT_M(pow)((NFFT_R)(k - my_nfft_plan.N[1] / 2), NFFT_K(2.0))) > (NFFT_R)(my_nfft_plan.N[0] / 2) ? 0 : 1); } /** initialise some guess f_hat_0 */ for (k = 0; k < my_nfft_plan.N_total; k++) my_infft_plan.f_hat_iter[k] = NFFT_K(0.0) + _Complex_I * NFFT_K(0.0); t0 = NFFT(clock_gettime_seconds)(); /** solve the system */ SOLVER(before_loop_complex)(&my_infft_plan); if (max_i < 1) { l = 1; for (k = 0; k < my_nfft_plan.N_total; k++) my_infft_plan.f_hat_iter[k] = my_infft_plan.p_hat_iter[k]; } else { for (l = 1; l <= max_i; l++) { SOLVER(loop_one_step_complex)(&my_infft_plan); } } t1 = NFFT(clock_gettime_seconds)(); GLOBAL_elapsed_time = (t1 - t0); /** copy result */ for (k = 0; k < my_nfft_plan.N_total; k++) f_hat[k] = my_infft_plan.f_hat_iter[k]; /** finalise the plans and free the variables */ SOLVER(finalize_complex)(&my_infft_plan); NFFT(finalize)(&my_nfft_plan); NFFT(free)(x); NFFT(free)(w); return EXIT_SUCCESS; } /** Comparison of the FFTW, linogram FFT, and inverse linogram FFT */ static int comparison_fft(FILE *fp, int N, int T, int rr) { double t0, t1; FFTW(plan) my_fftw_plan; NFFT_C *f_hat, *f; int m, k; NFFT_R t_fft, t_dft_linogram; f_hat = (NFFT_C *) NFFT(malloc)(sizeof(NFFT_C) * (size_t)(N * N)); f = (NFFT_C *) NFFT(malloc)(sizeof(NFFT_C) * (size_t)((T * rr / 4) * 5)); my_fftw_plan = FFTW(plan_dft_2d)(N, N, f_hat, f, FFTW_BACKWARD, FFTW_MEASURE); for (k = 0; k < N * N; k++) f_hat[k] = NFFT(drand48)() + _Complex_I * NFFT(drand48)(); t0 = NFFT(clock_gettime_seconds)(); for (m = 0; m < 65536 / N; m++) { FFTW(execute)(my_fftw_plan); /* touch */ f_hat[2] = NFFT_K(2.0) * f_hat[0]; } t1 = NFFT(clock_gettime_seconds)(); GLOBAL_elapsed_time = (t1 - t0); t_fft = (NFFT_R)(N) * GLOBAL_elapsed_time / NFFT_K(65536.0); if (N < 256) { linogram_dft(f_hat, N, f, T, rr, m); t_dft_linogram = GLOBAL_elapsed_time; } for (m = 3; m <= 9; m += 3) { if ((m == 3) && (N < 256)) fprintf(fp, "%d\t&\t&\t%1.1" NFFT__FES__ "&\t%1.1" NFFT__FES__ "&\t%d\t", N, t_fft, t_dft_linogram, m); else if (m == 3) fprintf(fp, "%d\t&\t&\t%1.1" NFFT__FES__ "&\t &\t%d\t", N, t_fft, m); else fprintf(fp, " \t&\t&\t &\t &\t%d\t", m); printf("N=%d\tt_fft=%1.1" NFFT__FES__ "\tt_dft_linogram=%1.1" NFFT__FES__ "\tm=%d\t", N, t_fft, t_dft_linogram, m); linogram_fft(f_hat, N, f, T, rr, m); fprintf(fp, "%1.1" NFFT__FES__ "&\t", GLOBAL_elapsed_time); printf("t_linogram=%1.1" NFFT__FES__ "\t", GLOBAL_elapsed_time); inverse_linogram_fft(f, T, rr, f_hat, N, m + 3, m); if (m == 9) fprintf(fp, "%1.1" NFFT__FES__ "\\\\\\hline\n", GLOBAL_elapsed_time); else fprintf(fp, "%1.1" NFFT__FES__ "\\\\\n", GLOBAL_elapsed_time); printf("t_ilinogram=%1.1" NFFT__FES__ "\n", GLOBAL_elapsed_time); } fflush(fp); NFFT(free)(f); NFFT(free)(f_hat); return EXIT_SUCCESS; } /** test program for various parameters */ int main(int argc, char **argv) { int N; /**< linogram FFT size NxN */ int T, rr; /**< number of directions/offsets */ int M; /**< number of knots of linogram grid */ NFFT_R *x, *w; /**< knots and associated weights */ NFFT_C *f_hat, *f, *f_direct, *f_tilde; int k; int max_i; /**< number of iterations */ int m; NFFT_R temp1, temp2, E_max = NFFT_K(0.0); FILE *fp1, *fp2; char filename[30]; int logN; if (argc != 4) { printf("linogram_fft_test N T R \n"); printf("\n"); printf("N linogram FFT of size NxN \n"); printf("T number of slopes \n"); printf("R number of offsets \n"); /** Hence, comparison of the FFTW, linogram FFT, and inverse linogram FFT */ printf("\nHence, comparison FFTW, linogram FFT and inverse linogram FFT\n"); fp1 = fopen("linogram_comparison_fft.dat", "w"); if (fp1 == NULL) return (-1); for (logN = 4; logN <= 8; logN++) comparison_fft(fp1, (int)(1U << logN), 3 * (int)(1U << logN), 3 * (int)(1U << (logN - 1))); fclose(fp1); return EXIT_FAILURE; } N = atoi(argv[1]); T = atoi(argv[2]); rr = atoi(argv[3]); printf("N=%d, linogram grid with T=%d, R=%d => ", N, T, rr); x = (NFFT_R *) NFFT(malloc)((size_t)(5 * T * rr / 2) * (sizeof(NFFT_R))); w = (NFFT_R *) NFFT(malloc)((size_t)(5 * T * rr / 4) * (sizeof(NFFT_R))); f_hat = (NFFT_C *) NFFT(malloc)(sizeof(NFFT_C) * (size_t)(N * N)); f = (NFFT_C *) NFFT(malloc)(sizeof(NFFT_C) * (size_t)(5 * T * rr / 4)); /* 4/pi*log(1+sqrt(2)) = 1.122... < 1.25 */ f_direct = (NFFT_C *) NFFT(malloc)(sizeof(NFFT_C) * (size_t)(5 * T * rr / 4)); f_tilde = (NFFT_C *) NFFT(malloc)(sizeof(NFFT_C) * (size_t)(N * N)); /** generate knots of linogram grid */ M = linogram_grid(T, rr, x, w); printf("M=%d.\n", M); /** load data */ fp1 = fopen("input_data_r.dat", "r"); fp2 = fopen("input_data_i.dat", "r"); if ((fp1 == NULL) || (fp2 == NULL)) return EXIT_FAILURE; for (k = 0; k < N * N; k++) { fscanf(fp1, NFFT__FR__ " ", &temp1); fscanf(fp2, NFFT__FR__ " ", &temp2); f_hat[k] = temp1 + _Complex_I * temp2; } fclose(fp1); fclose(fp2); /** direct linogram FFT */ linogram_dft(f_hat, N, f_direct, T, rr, 1); // linogram_fft(f_hat,N,f_direct,T,R,12); /** Test of the linogram FFT with different m */ printf("\nTest of the linogram FFT: \n"); fp1 = fopen("linogram_fft_error.dat", "w+"); for (m = 1; m <= 12; m++) { /** fast linogram FFT */ linogram_fft(f_hat, N, f, T, rr, m); /** error of fast linogram FFT */ E_max = NFFT(error_l_infty_complex)(f_direct, f, M); //E_max=NFFT(error_l_2_complex)(f_direct,f,M); printf("m=%2d: E_max = %" NFFT__FES__ "\n", m, E_max); fprintf(fp1, "%" NFFT__FES__ "\n", E_max); } fclose(fp1); /** Test of the inverse linogram FFT for different m in dependece of the iteration number*/ for (m = 3; m <= 9; m += 3) { printf("\nTest of the inverse linogram FFT for m=%d: \n", m); sprintf(filename, "linogram_ifft_error%d.dat", m); fp1 = fopen(filename, "w+"); for (max_i = 0; max_i <= 20; max_i += 2) { /** inverse linogram FFT */ inverse_linogram_fft(f_direct, T, rr, f_tilde, N, max_i, m); /** compute maximum error */ E_max = NFFT(error_l_infty_complex)(f_hat, f_tilde, N * N); printf("%3d iterations: E_max = %" NFFT__FES__ "\n", max_i, E_max); fprintf(fp1, "%" NFFT__FES__ "\n", E_max); } fclose(fp1); } /** free the variables */ NFFT(free)(x); NFFT(free)(w); NFFT(free)(f_hat); NFFT(free)(f); NFFT(free)(f_direct); NFFT(free)(f_tilde); return EXIT_SUCCESS; } /* \} */ nfft-3.3.2/applications/polarFFT/mpolar_fft_test.c.in000066400000000000000000000367651300072027400225740ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file polarFFT/mpolar_fft_test.c * \brief NFFT-based polar FFT and inverse on modified polar grid. * * Computes the NFFT-based polar FFT and its inverse * on a modified polar grid for various parameters. * \author Markus Fenn * \date 2006 */ #include #include #include #define @NFFT_PRECISION_MACRO@ #include "nfft3mp.h" /** * \defgroup applications_polarFFT_mpolar mpolar_fft_test * \ingroup applications_polarFFT * \{ */ NFFT_R GLOBAL_elapsed_time; /** Generates the points \f$x_{t,j}\f$ with weights \f$w_{t,j}\f$ * for the modified polar grid with \f$T\f$ angles and \f$R\f$ offsets. * * We add more concentric circles to the polar grid * and exclude those nodes not located in the unit square, i.e., * \f[ * x_{t,j} := r_j\left(\cos\theta_t, \sin\theta_t\right)^{\top}\,,\qquad * (j,t)^{\top}\in I_{\sqrt{2}R}\times I_T\,. * \f] * with \f$r_j\f$ and \f$\theta_t\f$ as for the polar grid. * The number of nodes for the modified polar grid can be estimated as * \f$M \approx \frac{4}{\pi}\log(1+\sqrt{2}) T R\f$. */ static int mpolar_grid(int T, int S, NFFT_R *x, NFFT_R *w) { int t, r; NFFT_R W; int R2 = 2 * (int)(NFFT_M(lrint)(NFFT_M(ceil)(NFFT_M(sqrt)(NFFT_K(2.0)) * (NFFT_R)(S) / NFFT_K(2.0)))); NFFT_R xx, yy; int M = 0; for (t = -T / 2; t < T / 2; t++) { for (r = -R2 / 2; r < R2 / 2; r++) { xx = (NFFT_R) (r) / (NFFT_R)(S) * NFFT_M(cos)(NFFT_KPI * (NFFT_R)(t) / (NFFT_R)(T)); yy = (NFFT_R) (r) / (NFFT_R)(S) * NFFT_M(sin)(NFFT_KPI * (NFFT_R)(t) / (NFFT_R)(T)); if (((-NFFT_K(0.5) - NFFT_K(1.0) / (NFFT_R) S) <= xx) & (xx <= (NFFT_K(0.5) + NFFT_K(1.0) / (NFFT_R) S)) & ((-NFFT_K(0.5) - NFFT_K(1.0) / (NFFT_R) S) <= yy) & (yy <= (NFFT_K(0.5) + NFFT_K(1.0) / (NFFT_R) S))) { x[2 * M + 0] = xx; x[2 * M + 1] = yy; if (r == 0) w[M] = NFFT_K(1.0) / NFFT_K(4.0); else w[M] = NFFT_M(fabs)((NFFT_R) r); M++; /** count the knots */ } } } /** normalize the weights */ W = NFFT_K(0.0); for (t = 0; t < M; t++) W += w[t]; for (t = 0; t < M; t++) w[t] /= W; return M; /** return the number of knots */ } /** discrete mpolar FFT */ static int mpolar_dft(NFFT_C *f_hat, int NN, NFFT_C *f, int T, int S, int m) { double t0, t1; int j, k; /**< index for nodes and freqencies */ NFFT(plan) my_nfft_plan; /**< plan for the nfft-2D */ NFFT_R *x, *w; /**< knots and associated weights */ int N[2], n[2]; int M; /**< number of knots */ N[0] = NN; n[0] = 2 * N[0]; /**< oversampling factor sigma=2 */ N[1] = NN; n[1] = 2 * N[1]; /**< oversampling factor sigma=2 */ x = (NFFT_R *) NFFT(malloc)((size_t)(5 * (T / 2) * S) * (sizeof(NFFT_R))); if (x == NULL) return EXIT_FAILURE; w = (NFFT_R *) NFFT(malloc)((size_t)(5 * (T * S) / 4) * (sizeof(NFFT_R))); if (w == NULL) return EXIT_FAILURE; /** init two dimensional NFFT plan */ M = mpolar_grid(T, S, x, w); NFFT(init_guru)(&my_nfft_plan, 2, N, M, n, m, PRE_PHI_HUT | PRE_PSI | MALLOC_X | MALLOC_F_HAT | MALLOC_F | FFTW_INIT | FFT_OUT_OF_PLACE, FFTW_MEASURE | FFTW_DESTROY_INPUT); /** init nodes from mpolar grid*/ for (j = 0; j < my_nfft_plan.M_total; j++) { my_nfft_plan.x[2 * j + 0] = x[2 * j + 0]; my_nfft_plan.x[2 * j + 1] = x[2 * j + 1]; } /** init Fourier coefficients from given image */ for (k = 0; k < my_nfft_plan.N_total; k++) my_nfft_plan.f_hat[k] = f_hat[k]; t0 = NFFT(clock_gettime_seconds)(); /** NDFT-2D */ NFFT(trafo_direct)(&my_nfft_plan); t1 = NFFT(clock_gettime_seconds)(); GLOBAL_elapsed_time = (t1 - t0); /** copy result */ for (j = 0; j < my_nfft_plan.M_total; j++) f[j] = my_nfft_plan.f[j]; /** finalise the plans and free the variables */ NFFT(finalize)(&my_nfft_plan); NFFT(free)(x); NFFT(free)(w); return EXIT_SUCCESS; } /** NFFT-based mpolar FFT */ static int mpolar_fft(NFFT_C *f_hat, int NN, NFFT_C *f, int T, int S, int m) { double t0, t1; int j, k; /**< index for nodes and freqencies */ NFFT(plan) my_nfft_plan; /**< plan for the nfft-2D */ NFFT_R *x, *w; /**< knots and associated weights */ int N[2], n[2]; int M; /**< number of knots */ N[0] = NN; n[0] = 2 * N[0]; /**< oversampling factor sigma=2 */ N[1] = NN; n[1] = 2 * N[1]; /**< oversampling factor sigma=2 */ x = (NFFT_R *) NFFT(malloc)((size_t)(5 * T * S / 2) * (sizeof(NFFT_R))); if (x == NULL) return EXIT_FAILURE; w = (NFFT_R *) NFFT(malloc)((size_t)(5 * T * S / 4) * (sizeof(NFFT_R))); if (w == NULL) return EXIT_FAILURE; /** init two dimensional NFFT plan */ M = mpolar_grid(T, S, x, w); NFFT(init_guru)(&my_nfft_plan, 2, N, M, n, m, PRE_PHI_HUT | PRE_PSI | MALLOC_X | MALLOC_F_HAT | MALLOC_F | FFTW_INIT | FFT_OUT_OF_PLACE, FFTW_MEASURE | FFTW_DESTROY_INPUT); /** init nodes from mpolar grid*/ for (j = 0; j < my_nfft_plan.M_total; j++) { my_nfft_plan.x[2 * j + 0] = x[2 * j + 0]; my_nfft_plan.x[2 * j + 1] = x[2 * j + 1]; } /** precompute psi, the entries of the matrix B */ if (my_nfft_plan.flags & PRE_LIN_PSI) NFFT(precompute_lin_psi)(&my_nfft_plan); if (my_nfft_plan.flags & PRE_PSI) NFFT(precompute_psi)(&my_nfft_plan); if (my_nfft_plan.flags & PRE_FULL_PSI) NFFT(precompute_full_psi)(&my_nfft_plan); /** init Fourier coefficients from given image */ for (k = 0; k < my_nfft_plan.N_total; k++) my_nfft_plan.f_hat[k] = f_hat[k]; t0 = NFFT(clock_gettime_seconds)(); /** NFFT-2D */ NFFT(trafo)(&my_nfft_plan); t1 = NFFT(clock_gettime_seconds)(); GLOBAL_elapsed_time = (t1 - t0); /** copy result */ for (j = 0; j < my_nfft_plan.M_total; j++) f[j] = my_nfft_plan.f[j]; /** finalise the plans and free the variables */ NFFT(finalize)(&my_nfft_plan); NFFT(free)(x); NFFT(free)(w); return EXIT_SUCCESS; } /** inverse NFFT-based mpolar FFT */ static int inverse_mpolar_fft(NFFT_C *f, int T, int S, NFFT_C *f_hat, int NN, int max_i, int m) { double t0, t1; int j, k; /**< index for nodes and freqencies */ NFFT(plan) my_nfft_plan; /**< plan for the nfft-2D */ SOLVER(plan_complex) my_infft_plan; /**< plan for the inverse nfft */ NFFT_R *x, *w; /**< knots and associated weights */ int l; /**< index for iterations */ int N[2], n[2]; int M; /**< number of knots */ N[0] = NN; n[0] = 2 * N[0]; /**< oversampling factor sigma=2 */ N[1] = NN; n[1] = 2 * N[1]; /**< oversampling factor sigma=2 */ x = (NFFT_R *) NFFT(malloc)((size_t)(5 * T * S / 2) * (sizeof(NFFT_R))); if (x == NULL) return EXIT_FAILURE; w = (NFFT_R *) NFFT(malloc)((size_t)(5 * T * S / 4) * (sizeof(NFFT_R))); if (w == NULL) return EXIT_FAILURE; /** init two dimensional NFFT plan */ M = mpolar_grid(T, S, x, w); NFFT(init_guru)(&my_nfft_plan, 2, N, M, n, m, PRE_PHI_HUT | PRE_PSI | MALLOC_X | MALLOC_F_HAT | MALLOC_F | FFTW_INIT | FFT_OUT_OF_PLACE, FFTW_MEASURE | FFTW_DESTROY_INPUT); /** init two dimensional infft plan */ SOLVER(init_advanced_complex)(&my_infft_plan, (NFFT(mv_plan_complex)*) (&my_nfft_plan), CGNR | PRECOMPUTE_WEIGHT); /** init nodes, given samples and weights */ for (j = 0; j < my_nfft_plan.M_total; j++) { my_nfft_plan.x[2 * j + 0] = x[2 * j + 0]; my_nfft_plan.x[2 * j + 1] = x[2 * j + 1]; my_infft_plan.y[j] = f[j]; my_infft_plan.w[j] = w[j]; } /** precompute psi, the entries of the matrix B */ if (my_nfft_plan.flags & PRE_LIN_PSI) NFFT(precompute_lin_psi)(&my_nfft_plan); if (my_nfft_plan.flags & PRE_PSI) NFFT(precompute_psi)(&my_nfft_plan); if (my_nfft_plan.flags & PRE_FULL_PSI) NFFT(precompute_full_psi)(&my_nfft_plan); /** initialise damping factors */ if (my_infft_plan.flags & PRECOMPUTE_DAMP) for (j = 0; j < my_nfft_plan.N[0]; j++) for (k = 0; k < my_nfft_plan.N[1]; k++) { my_infft_plan.w_hat[j * my_nfft_plan.N[1] + k] = ( NFFT_M(sqrt)( NFFT_M(pow)((NFFT_R)(j - my_nfft_plan.N[0] / 2), NFFT_K(2.0)) + NFFT_M(pow)((NFFT_R)(k - my_nfft_plan.N[1] / 2), NFFT_K(2.0))) > (NFFT_R)(my_nfft_plan.N[0] / 2) ? NFFT_K(0.0) : NFFT_K(1.0)); } /** initialise some guess f_hat_0 */ for (k = 0; k < my_nfft_plan.N_total; k++) my_infft_plan.f_hat_iter[k] = NFFT_K(0.0) + _Complex_I * NFFT_K(0.0); t0 = NFFT(clock_gettime_seconds)(); /** solve the system */ SOLVER(before_loop_complex)(&my_infft_plan); if (max_i < 1) { l = 1; for (k = 0; k < my_nfft_plan.N_total; k++) my_infft_plan.f_hat_iter[k] = my_infft_plan.p_hat_iter[k]; } else { for (l = 1; l <= max_i; l++) { SOLVER(loop_one_step_complex)(&my_infft_plan); } } t1 = NFFT(clock_gettime_seconds)(); GLOBAL_elapsed_time = (t1 - t0); /** copy result */ for (k = 0; k < my_nfft_plan.N_total; k++) f_hat[k] = my_infft_plan.f_hat_iter[k]; /** finalise the plans and free the variables */ SOLVER(finalize_complex)(&my_infft_plan); NFFT(finalize)(&my_nfft_plan); NFFT(free)(x); NFFT(free)(w); return EXIT_SUCCESS; } /** Comparison of the FFTW, mpolar FFT, and inverse mpolar FFT */ static int comparison_fft(FILE *fp, int N, int T, int S) { double t0, t1; FFTW(plan) my_fftw_plan; NFFT_C *f_hat, *f; int m, k; NFFT_R t_fft, t_dft_mpolar; f_hat = (NFFT_C *) NFFT(malloc)(sizeof(NFFT_C) * (size_t)(N * N)); f = (NFFT_C *) NFFT(malloc)(sizeof(NFFT_C) * (size_t)((T * S / 4) * 5)); my_fftw_plan = FFTW(plan_dft_2d)(N, N, f_hat, f, FFTW_BACKWARD, FFTW_MEASURE); for (k = 0; k < N * N; k++) f_hat[k] = NFFT(drand48)() + _Complex_I * NFFT(drand48)(); t0 = NFFT(clock_gettime_seconds)(); for (m = 0; m < 65536 / N; m++) { FFTW(execute)(my_fftw_plan); /* touch */ f_hat[2] = NFFT_K(2.0) * f_hat[0]; } t1 = NFFT(clock_gettime_seconds)(); GLOBAL_elapsed_time = (t1 - t0); t_fft = (NFFT_R)(N) * GLOBAL_elapsed_time / NFFT_K(65536.0); if (N < 256) { mpolar_dft(f_hat, N, f, T, S, 1); t_dft_mpolar = GLOBAL_elapsed_time; } for (m = 3; m <= 9; m += 3) { if ((m == 3) && (N < 256)) fprintf(fp, "%d\t&\t&\t%1.1" NFFT__FES__ "&\t%1.1" NFFT__FES__ "&\t%d\t", N, t_fft, t_dft_mpolar, m); else if (m == 3) fprintf(fp, "%d\t&\t&\t%1.1" NFFT__FES__ "&\t &\t%d\t", N, t_fft, m); else fprintf(fp, " \t&\t&\t &\t &\t%d\t", m); printf("N=%d\tt_fft=%1.1" NFFT__FES__ "\tt_dft_mpolar=%1.1" NFFT__FES__ "\tm=%d\t", N, t_fft, t_dft_mpolar, m); mpolar_fft(f_hat, N, f, T, S, m); fprintf(fp, "%1.1" NFFT__FES__ "&\t", GLOBAL_elapsed_time); printf("t_mpolar=%1.1" NFFT__FES__ "\t", GLOBAL_elapsed_time); inverse_mpolar_fft(f, T, S, f_hat, N, 2 * m, m); if (m == 9) fprintf(fp, "%1.1" NFFT__FES__ "\\\\\\hline\n", GLOBAL_elapsed_time); else fprintf(fp, "%1.1" NFFT__FES__ "\\\\\n", GLOBAL_elapsed_time); printf("t_impolar=%1.1" NFFT__FES__ "\n", GLOBAL_elapsed_time); } fflush(fp); NFFT(free)(f); NFFT(free)(f_hat); return EXIT_SUCCESS; } /** test program for various parameters */ int main(int argc, char **argv) { int N; /**< mpolar FFT size NxN */ int T, S; /**< number of directions/offsets */ int M; /**< number of knots of mpolar grid */ NFFT_R *x, *w; /**< knots and associated weights */ NFFT_C *f_hat, *f, *f_direct, *f_tilde; int k; int max_i; /**< number of iterations */ int m; NFFT_R temp1, temp2, E_max = NFFT_K(0.0); FILE *fp1, *fp2; char filename[30]; int logN; if (argc != 4) { printf("mpolar_fft_test N T R \n"); printf("\n"); printf("N mpolar FFT of size NxN \n"); printf("T number of slopes \n"); printf("R number of offsets \n"); /** Hence, comparison of the FFTW, mpolar FFT, and inverse mpolar FFT */ printf("\nHence, comparison FFTW, mpolar FFT and inverse mpolar FFT\n"); fp1 = fopen("mpolar_comparison_fft.dat", "w"); if (fp1 == NULL) return (-1); for (logN = 4; logN <= 8; logN++) comparison_fft(fp1, (int)(1U << logN), 3 * (int)(1U << logN), 3 * (int)(1U << (logN - 1))); fclose(fp1); exit(EXIT_FAILURE); } N = atoi(argv[1]); T = atoi(argv[2]); S = atoi(argv[3]); printf("N=%d, modified polar grid with T=%d, R=%d => ", N, T, S); x = (NFFT_R *) NFFT(malloc)((size_t)(5 * T * S / 2) * (sizeof(NFFT_R))); w = (NFFT_R *) NFFT(malloc)((size_t)(5 * T * S / 4) * (sizeof(NFFT_R))); f_hat = (NFFT_C *) NFFT(malloc)(sizeof(NFFT_C) * (size_t)(N * N)); f = (NFFT_C *) NFFT(malloc)(sizeof(NFFT_C) * (size_t)(1.25 * T * S)); /* 4/pi*log(1+sqrt(2)) = 1.122... < 1.25 */ f_direct = (NFFT_C *) NFFT(malloc)(sizeof(NFFT_C) * (size_t)(1.25 * T * S)); f_tilde = (NFFT_C *) NFFT(malloc)(sizeof(NFFT_C) * (size_t)(N * N)); /** generate knots of mpolar grid */ M = mpolar_grid(T, S, x, w); printf("M=%d.\n", M); /** load data */ fp1 = fopen("input_data_r.dat", "r"); fp2 = fopen("input_data_i.dat", "r"); if ((fp1 == NULL) || (fp2 == NULL)) return (-1); for (k = 0; k < N * N; k++) { fscanf(fp1, NFFT__FR__ " ", &temp1); fscanf(fp2, NFFT__FR__ " ", &temp2); f_hat[k] = temp1 + _Complex_I * temp2; } fclose(fp1); fclose(fp2); /** direct mpolar FFT */ mpolar_dft(f_hat, N, f_direct, T, S, 1); // mpolar_fft(f_hat,N,f_direct,T,R,12); /** Test of the mpolar FFT with different m */ printf("\nTest of the mpolar FFT: \n"); fp1 = fopen("mpolar_fft_error.dat", "w+"); for (m = 1; m <= 12; m++) { /** fast mpolar FFT */ mpolar_fft(f_hat, N, f, T, S, m); /** compute error of fast mpolar FFT */ E_max = NFFT(error_l_infty_complex)(f_direct, f, M); printf("m=%2d: E_max = %" NFFT__FES__ "\n", m, E_max); fprintf(fp1, "%" NFFT__FES__ "\n", E_max); } fclose(fp1); /** Test of the inverse mpolar FFT for different m in dependece of the iteration number*/ for (m = 3; m <= 9; m += 3) { printf("\nTest of the inverse mpolar FFT for m=%d: \n", m); sprintf(filename, "mpolar_ifft_error%d.dat", m); fp1 = fopen(filename, "w+"); for (max_i = 0; max_i <= 20; max_i += 2) { /** inverse mpolar FFT */ inverse_mpolar_fft(f_direct, T, S, f_tilde, N, max_i, m); /** compute maximum relativ error */ E_max = NFFT(error_l_infty_complex)(f_hat, f_tilde, N * N); printf("%3d iterations: E_max = %" NFFT__FES__ "\n", max_i, E_max); fprintf(fp1, "%" NFFT__FES__ "\n", E_max); } fclose(fp1); } /** free the variables */ NFFT(free)(x); NFFT(free)(w); NFFT(free)(f_hat); NFFT(free)(f); NFFT(free)(f_direct); NFFT(free)(f_tilde); return EXIT_SUCCESS; } /* \} */ nfft-3.3.2/applications/polarFFT/phantom.m000066400000000000000000000036661300072027400204510ustar00rootroot00000000000000% Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 % Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. function I=phantom(N) % phantom(N) % generates the (modified) Shepp-Logan phantom of P. Toft % as an NxN matrix. % % Reference: Peter Toft: "The Radon Transform - Theory and Implementation", Ph.D. thesis. % Department of Mathematical Modelling, Technical University of Denmark, June 1996. 326 pages. % Author: Markus Fenn, 2005 I = zeros(N,N); k = linspace(-1,1,N); [x,y] = meshgrid(k); I = I + 1.0 * ( (x/0.69).^2+(y/0.92).^2 <= 1 ); I = I - 0.8 * ( (x/0.6624).^2+((y+0.0184)/0.874).^2 <= 1 ); I = I - 0.2 * ( ( (cos(-18/360*2*pi)*(x-0.22)+sin(-18/360*2*pi)*y)/0.11).^2+... ( (sin(-18/360*2*pi)*(x-0.22)-cos(-18/360*2*pi)*y)/0.31).^2 <= 1 ); I = I - 0.2 * ( ( (cos( 18/360*2*pi)*(x+0.22)+sin( 18/360*2*pi)*y)/0.16).^2+... ( (sin( 18/360*2*pi)*(x+0.22)-cos( 18/360*2*pi)*y)/0.41).^2 <= 1 ); I = I + 0.1 * ( (x/0.21).^2+((y-0.35)/0.25).^2 <= 1 ); I = I + 0.1 * ( (x/0.046).^2+((y-0.1)/0.046).^2 <= 1 ); I = I + 0.1 * ( (x/0.046).^2+((y+0.1)/0.046).^2 <= 1 ); I = I + 0.1 * ( ((x+0.08)/0.046).^2+((y+0.605)/0.023).^2 <= 1 ); I = I + 0.1 * ( (x/0.023).^2+((y+0.606)/0.023).^2 <= 1 ); I = I + 0.1 * ( ((x-0.06)/0.023).^2+((y+0.605)/0.046).^2 <= 1 ); I=flipud(I); nfft-3.3.2/applications/polarFFT/polar_fft_test.c.in000066400000000000000000000323031300072027400223770ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file polarFFT/polar_fft_test.c * \brief NFFT-based polar FFT and inverse. * * Computes the NFFT-based polar FFT and its inverse for various parameters. * \author Markus Fenn * \date 2006 */ #include #include #include #define @NFFT_PRECISION_MACRO@ #include "nfft3mp.h" /** * \defgroup applications_polarFFT_polar polar_fft_test * \ingroup applications_polarFFT * \{ */ /** Generates the points \f$x_{t,j}\f$ with weights \f$w_{t,j}\f$ * for the polar grid with \f$T\f$ angles and \f$R\f$ offsets. * * The nodes of the polar grid lie on concentric circles around the origin. * They are given for \f$(j,t)^{\top}\in I_R\times I_T\f$ by * a signed radius \f$r_j := \frac{j}{R} \in [-\frac{1}{2},\frac{1}{2})\f$ and * an angle \f$\theta_t := \frac{\pi t}{T} \in [-\frac{\pi}{2},\frac{\pi}{2})\f$ * as * \f[ * x_{t,j} := r_j\left(\cos\theta_t, \sin\theta_t\right)^{\top}\,. * \f] * The total number of nodes is \f$M=TR\f$, * whereas the origin is included multiple times. * * Weights are introduced to compensate for local sampling density variations. * For every point in the sampling set, we associate a small surrounding area. * In case of the polar grid, we choose small ring segments. * The area of such a ring segment around \f$x_{t,j}\f$ (\f$j \ne 0\f$) is * \f[ * w_{t,j} * = \frac{\pi}{2TR^2}\left(\left(|j|+\frac{1}{2}\right)^2- * \left(|j|-\frac{1}{2}\right)^2\right) * = \frac{\pi |j| }{TR^2}\, . * \f] * The area of the small circle of radius \f$\frac{1}{2R}\f$ around the origin is * \f$\frac{\pi}{4R^2}\f$. * Divided by the multiplicity of the origin in the sampling set, we get * \f$w_{t,0} := \frac{\pi}{4TR^2}\f$. * Thus, the sum of all weights is \f$\frac{\pi}{4}(1+\frac{1}{R^2})\f$ and * we divide by this value for normalization. */ static int polar_grid(int T, int S, NFFT_R *x, NFFT_R *w) { int t, r; NFFT_R W = (NFFT_R) T * (((NFFT_R) S / NFFT_K(2.0)) * ((NFFT_R) S / NFFT_K(2.0)) + NFFT_K(1.0) / NFFT_K(4.0)); for (t = -T / 2; t < T / 2; t++) { for (r = -S / 2; r < S / 2; r++) { x[2 * ((t + T / 2) * S + (r + S / 2)) + 0] = (NFFT_R) (r) / (NFFT_R)(S) * NFFT_M(cos)(NFFT_KPI * (NFFT_R)(t) / (NFFT_R)(T)); x[2 * ((t + T / 2) * S + (r + S / 2)) + 1] = (NFFT_R) (r) / (NFFT_R)(S) * NFFT_M(sin)(NFFT_KPI * (NFFT_R)(t) / (NFFT_R)(T)); if (r == 0) w[(t + T / 2) * S + (r + S / 2)] = NFFT_K(1.0) / NFFT_K(4.0) / W; else w[(t + T / 2) * S + (r + S / 2)] = NFFT_M(fabs)((NFFT_R) r) / W; } } return T * S; /** return the number of knots */ } /** discrete polar FFT */ static int polar_dft(NFFT_C *f_hat, int NN, NFFT_C *f, int T, int S, int m) { int j, k; /**< index for nodes and frequencies */ NFFT(plan) my_nfft_plan; /**< plan for the nfft-2D */ NFFT_R *x, *w; /**< knots and associated weights */ int N[2], n[2]; int M = T * S; /**< number of knots */ N[0] = NN; n[0] = 2 * N[0]; /**< oversampling factor sigma=2 */ N[1] = NN; n[1] = 2 * N[1]; /**< oversampling factor sigma=2 */ x = (NFFT_R *) NFFT(malloc)((size_t)(2 * T * S) * (sizeof(NFFT_R))); if (x == NULL) return EXIT_FAILURE; w = (NFFT_R *) NFFT(malloc)((size_t)(T * S) * (sizeof(NFFT_R))); if (w == NULL) return EXIT_FAILURE; /** init two dimensional NFFT plan */ NFFT(init_guru)(&my_nfft_plan, 2, N, M, n, m, PRE_PHI_HUT | PRE_PSI | MALLOC_X | MALLOC_F_HAT | MALLOC_F | FFTW_INIT | FFT_OUT_OF_PLACE, FFTW_MEASURE | FFTW_DESTROY_INPUT); /** init nodes from polar grid*/ polar_grid(T, S, x, w); for (j = 0; j < my_nfft_plan.M_total; j++) { my_nfft_plan.x[2 * j + 0] = x[2 * j + 0]; my_nfft_plan.x[2 * j + 1] = x[2 * j + 1]; } /** init Fourier coefficients from given image */ for (k = 0; k < my_nfft_plan.N_total; k++) my_nfft_plan.f_hat[k] = f_hat[k]; /** NDFT-2D */ NFFT(trafo_direct)(&my_nfft_plan); /** copy result */ for (j = 0; j < my_nfft_plan.M_total; j++) f[j] = my_nfft_plan.f[j]; /** finalise the plans and free the variables */ NFFT(finalize)(&my_nfft_plan); NFFT(free)(x); NFFT(free)(w); return EXIT_SUCCESS; } /** NFFT-based polar FFT */ static int polar_fft(NFFT_C *f_hat, int NN, NFFT_C *f, int T, int S, int m) { int j, k; /**< index for nodes and freqencies */ NFFT(plan) my_nfft_plan; /**< plan for the nfft-2D */ NFFT_R *x, *w; /**< knots and associated weights */ int N[2], n[2]; int M = T * S; /**< number of knots */ N[0] = NN; n[0] = 2 * N[0]; /**< oversampling factor sigma=2 */ N[1] = NN; n[1] = 2 * N[1]; /**< oversampling factor sigma=2 */ x = (NFFT_R *) NFFT(malloc)((size_t)(2 * T * S) * (sizeof(NFFT_R))); if (x == NULL) return EXIT_FAILURE; w = (NFFT_R *) NFFT(malloc)((size_t)(T * S) * (sizeof(NFFT_R))); if (w == NULL) return EXIT_FAILURE; /** init two dimensional NFFT plan */ NFFT(init_guru)(&my_nfft_plan, 2, N, M, n, m, PRE_PHI_HUT | PRE_PSI | MALLOC_X | MALLOC_F_HAT | MALLOC_F | FFTW_INIT | FFT_OUT_OF_PLACE, FFTW_MEASURE | FFTW_DESTROY_INPUT); /** init nodes from polar grid*/ polar_grid(T, S, x, w); for (j = 0; j < my_nfft_plan.M_total; j++) { my_nfft_plan.x[2 * j + 0] = x[2 * j + 0]; my_nfft_plan.x[2 * j + 1] = x[2 * j + 1]; } /** precompute psi, the entries of the matrix B */ if (my_nfft_plan.flags & PRE_LIN_PSI) NFFT(precompute_lin_psi)(&my_nfft_plan); if (my_nfft_plan.flags & PRE_PSI) NFFT(precompute_psi)(&my_nfft_plan); if (my_nfft_plan.flags & PRE_FULL_PSI) NFFT(precompute_full_psi)(&my_nfft_plan); /** init Fourier coefficients from given image */ for (k = 0; k < my_nfft_plan.N_total; k++) my_nfft_plan.f_hat[k] = f_hat[k]; /** NFFT-2D */ NFFT(trafo)(&my_nfft_plan); /** copy result */ for (j = 0; j < my_nfft_plan.M_total; j++) f[j] = my_nfft_plan.f[j]; /** finalise the plans and free the variables */ NFFT(finalize)(&my_nfft_plan); NFFT(free)(x); NFFT(free)(w); return EXIT_SUCCESS; } /** inverse NFFT-based polar FFT */ static int inverse_polar_fft(NFFT_C *f, int T, int S, NFFT_C *f_hat, int NN, int max_i, int m) { int j, k; /**< index for nodes and freqencies */ NFFT(plan) my_nfft_plan; /**< plan for the nfft-2D */ SOLVER(plan_complex) my_infft_plan; /**< plan for the inverse nfft */ NFFT_R *x, *w; /**< knots and associated weights */ int l; /**< index for iterations */ int N[2], n[2]; int M = T * S; /**< number of knots */ N[0] = NN; n[0] = 2 * N[0]; /**< oversampling factor sigma=2 */ N[1] = NN; n[1] = 2 * N[1]; /**< oversampling factor sigma=2 */ x = (NFFT_R *) NFFT(malloc)((size_t)(2 * T * S) * (sizeof(NFFT_R))); if (x == NULL) return EXIT_FAILURE; w = (NFFT_R *) NFFT(malloc)((size_t)(T * S) * (sizeof(NFFT_R))); if (w == NULL) return EXIT_FAILURE; /** init two dimensional NFFT plan */ NFFT(init_guru)(&my_nfft_plan, 2, N, M, n, m, PRE_PHI_HUT | PRE_PSI | MALLOC_X | MALLOC_F_HAT | MALLOC_F | FFTW_INIT | FFT_OUT_OF_PLACE, FFTW_MEASURE | FFTW_DESTROY_INPUT); /** init two dimensional infft plan */ SOLVER(init_advanced_complex)(&my_infft_plan, (NFFT(mv_plan_complex)*) (&my_nfft_plan), CGNR | PRECOMPUTE_WEIGHT); /** init nodes, given samples and weights */ polar_grid(T, S, x, w); for (j = 0; j < my_nfft_plan.M_total; j++) { my_nfft_plan.x[2 * j + 0] = x[2 * j + 0]; my_nfft_plan.x[2 * j + 1] = x[2 * j + 1]; my_infft_plan.y[j] = f[j]; my_infft_plan.w[j] = w[j]; } /** precompute psi, the entries of the matrix B */ if (my_nfft_plan.flags & PRE_LIN_PSI) NFFT(precompute_lin_psi)(&my_nfft_plan); if (my_nfft_plan.flags & PRE_PSI) NFFT(precompute_psi)(&my_nfft_plan); if (my_nfft_plan.flags & PRE_FULL_PSI) NFFT(precompute_full_psi)(&my_nfft_plan); /** initialise damping factors */ if (my_infft_plan.flags & PRECOMPUTE_DAMP) for (j = 0; j < my_nfft_plan.N[0]; j++) for (k = 0; k < my_nfft_plan.N[1]; k++) { my_infft_plan.w_hat[j * my_nfft_plan.N[1] + k] = ( NFFT_M(sqrt)( NFFT_M(pow)((NFFT_R) (j - my_nfft_plan.N[0] / 2), NFFT_K(2.0)) + NFFT_M(pow)((NFFT_R) (k - my_nfft_plan.N[1] / 2), NFFT_K(2.0))) > ((NFFT_R) (my_nfft_plan.N[0] / 2)) ? 0 : 1); } /** initialise some guess f_hat_0 */ for (k = 0; k < my_nfft_plan.N_total; k++) my_infft_plan.f_hat_iter[k] = NFFT_K(0.0) + _Complex_I * NFFT_K(0.0); /** solve the system */ SOLVER(before_loop_complex)(&my_infft_plan); if (max_i < 1) { l = 1; for (k = 0; k < my_nfft_plan.N_total; k++) my_infft_plan.f_hat_iter[k] = my_infft_plan.p_hat_iter[k]; } else { for (l = 1; l <= max_i; l++) { SOLVER(loop_one_step_complex)(&my_infft_plan); } } /** copy result */ for (k = 0; k < my_nfft_plan.N_total; k++) f_hat[k] = my_infft_plan.f_hat_iter[k]; /** finalise the plans and free the variables */ SOLVER(finalize_complex)(&my_infft_plan); NFFT(finalize)(&my_nfft_plan); NFFT(free)(x); NFFT(free)(w); return EXIT_SUCCESS; } /** test program for various parameters */ int main(int argc, char **argv) { int N; /**< mpolar FFT size NxN */ int T, S; /**< number of directions/offsets */ int M; /**< number of knots of mpolar grid */ NFFT_R *x, *w; /**< knots and associated weights */ NFFT_C *f_hat, *f, *f_direct, *f_tilde; int k; int max_i; /**< number of iterations */ int m = 1; NFFT_R temp1, temp2, E_max = NFFT_K(0.0); FILE *fp1, *fp2; char filename[30]; if (argc != 4) { printf("polar_fft_test N T R \n"); printf("\n"); printf("N polar FFT of size NxN \n"); printf("T number of slopes \n"); printf("R number of offsets \n"); exit(EXIT_FAILURE); } N = atoi(argv[1]); T = atoi(argv[2]); S = atoi(argv[3]); printf("N=%d, polar grid with T=%d, R=%d => ", N, T, S); x = (NFFT_R *) NFFT(malloc)((size_t)(2 * 5 * (T / 2) * (S / 2)) * (sizeof(NFFT_R))); w = (NFFT_R *) NFFT(malloc)((size_t)(5 * (T / 2) * (S / 2)) * (sizeof(NFFT_R))); f_hat = (NFFT_C *) NFFT(malloc)(sizeof(NFFT_C) * (size_t)(N * N)); f = (NFFT_C *) NFFT(malloc)(sizeof(NFFT_C) * (size_t)(T * S)); f_direct = (NFFT_C *) NFFT(malloc)(sizeof(NFFT_C) * (size_t)(T * S)); f_tilde = (NFFT_C *) NFFT(malloc)(sizeof(NFFT_C) * (size_t)(N * N)); /** generate knots of mpolar grid */ M = polar_grid(T, S, x, w); printf("M=%d.\n", M); /** load data */ fp1 = fopen("input_data_r.dat", "r"); fp2 = fopen("input_data_i.dat", "r"); if (fp1 == NULL) return (-1); for (k = 0; k < N * N; k++) { fscanf(fp1, NFFT__FR__ " ", &temp1); fscanf(fp2, NFFT__FR__ " ", &temp2); f_hat[k] = temp1 + _Complex_I * temp2; } fclose(fp1); fclose(fp2); /** direct polar FFT */ polar_dft(f_hat, N, f_direct, T, S, m); // polar_fft(f_hat,N,f_direct,T,R,12); /** Test of the polar FFT with different m */ printf("\nTest of the polar FFT: \n"); fp1 = fopen("polar_fft_error.dat", "w+"); for (m = 1; m <= 12; m++) { /** fast polar FFT */ polar_fft(f_hat, N, f, T, S, m); /** compute error of fast polar FFT */ E_max = NFFT(error_l_infty_complex)(f_direct, f, M); printf("m=%2d: E_max = %" NFFT__FES__ "\n", m, E_max); fprintf(fp1, "%" NFFT__FES__ "\n", E_max); } fclose(fp1); /** Test of the inverse polar FFT for different m in dependece of the iteration number*/ for (m = 3; m <= 9; m += 3) { printf("\nTest of the inverse polar FFT for m=%d: \n", m); sprintf(filename, "polar_ifft_error%d.dat", m); fp1 = fopen(filename, "w+"); for (max_i = 0; max_i <= 100; max_i += 10) { /** inverse polar FFT */ inverse_polar_fft(f_direct, T, S, f_tilde, N, max_i, m); /** compute maximum relative error */ /* E_max=0.0; for(k=0;kE_max) E_max=temp; } */ E_max = NFFT(error_l_infty_complex)(f_hat, f_tilde, N * N); printf("%3d iterations: E_max = %" NFFT__FES__ "\n", max_i, E_max); fprintf(fp1, "%" NFFT__FES__ "\n", E_max); } fclose(fp1); } /** free the variables */ NFFT(free)(x); NFFT(free)(w); NFFT(free)(f_hat); NFFT(free)(f); NFFT(free)(f_direct); NFFT(free)(f_tilde); return EXIT_SUCCESS; } /* \} */ nfft-3.3.2/applications/quadratureS2/000077500000000000000000000000001300072027400175175ustar00rootroot00000000000000nfft-3.3.2/applications/quadratureS2/Makefile.am000066400000000000000000000004711300072027400215550ustar00rootroot00000000000000AM_CPPFLAGS = -I$(top_srcdir)/include noinst_PROGRAMS = quadratureS2 quadratureS2_SOURCES = quadratureS2.c doxygen.h quadratureS2_LDADD = $(top_builddir)/libnfft3.la @fftw3_LDFLAGS@ @fftw3_LIBS@ EXTRA_DIST = quadratureS2.m writeTestcase.m writeWeights.m readTestcase.m lgwt.m plotGrid.m example.in example.out nfft-3.3.2/applications/quadratureS2/doxygen.h000066400000000000000000000016321300072027400213470ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \defgroup applications_quadratureS2 Fast evaluation of quadrature formulae on the sphere * \ingroup applications */ nfft-3.3.2/applications/quadratureS2/example.in000066400000000000000000000240651300072027400215110ustar00rootroot00000000000000testcases=3 nfsft=1 nfft=1 cutoff=3 fpt=1 threshold=1.000000e+03 testmode=0 gridtype=0 testfunction=1 repetitions=1 mode=0 bandwidths=2 16 16 32 32 0.024148302868547931454568100662 0.055459529373987133393786308488 0.085036148317179163780288320140 0.111883847193403884734408393342 0.135136368468525447372741155050 0.154045761076810394651914748465 0.168004102156449897087497902248 0.176562705366992644950840940510 0.179446470356206533303122796497 0.176562705366992644950840940510 0.168004102156449897087497902248 0.154045761076810394651914748465 0.135136368468525447372741155050 0.111883847193403884734408393342 0.085036148317179163780288320140 0.055459529373987133393786308488 0.024148302868547931454568100662 0.021867872517185239084058778758 0.050195855139357897778396022659 0.078691039281386376824656281315 0.107223872365252256844136979907 0.135770824783899402010689527742 0.164324411574724438267480763898 0.192881461704887263719498946557 0.221440333046589832299844147201 0.250000000000000000000000000000 0.278559666953410167700155852799 0.307118538295112764036076669072 0.335675588425275617243670467360 0.364229175216100653500461703516 0.392776127634747729278075212278 0.421308960718613623175343718685 0.449804144860642129977179592970 0.478132127482814750507600365381 0.006606227847587484679203750915 0.015321701512934696523537958512 0.023915548101749450893294124398 0.032300358632328871055783281463 0.040401541331669621470723541279 0.048147742818711682100119020333 0.055470846631663503489839683880 0.062306482530317411350218037569 0.068594572818656829316097400806 0.074279854843954107312953283326 0.079312364794886736074630562143 0.083647876067038787195606630576 0.087248287618844302948595270664 0.090081958660638547509158513549 0.092123986643316849165508131136 0.093356426065596062602303106814 0.093768446160209989459488610919 0.093356426065596062602303106814 0.092123986643316849165508131136 0.090081958660638547509158513549 0.087248287618844302948595270664 0.083647876067038787195606630576 0.079312364794886736074630562143 0.074279854843954107312953283326 0.068594572818656829316097400806 0.062306482530317411350218037569 0.055470846631663503489839683880 0.048147742818711682100119020333 0.040401541331669621470723541279 0.032300358632328871055783281463 0.023915548101749450893294124398 0.015321701512934696523537958512 0.006606227847587484679203750915 0.011424646629589122262538047892 0.026224329716335245676894771805 0.041111409496705275667949308627 0.056018231215834990432966833396 0.070932535986010208928220777125 0.085850455629256680611938179482 0.100770388669267227377268625332 0.115691552534641750593635833866 0.130613518882987722502520000489 0.145536032750858829176721087606 0.160458932010607013829428524332 0.175382107696440303623575118763 0.190305482843150408633903225564 0.205229000420828450179655533248 0.220152616025452413373031390620 0.235076293166748051532977115130 0.250000000000000000000000000000 0.264923706833251948467022884870 0.279847383974547614382544225009 0.294770999579171577575920082381 0.309694517156849591366096774436 0.324617892303559696376424881237 0.339541067989393041681722706926 0.354463967249141254090005759281 0.369386481117012333008631230769 0.384308447465358304917515397392 0.399229611330732814256094798111 0.414149544370743361021425243962 0.429067464013989818827354838504 0.443981768784165065078184397862 0.458888590503294724332050691373 0.473775670283664795956468651639 0.488575353370410914166654947621 nfsft=1 nfft=1 cutoff=6 fpt=1 threshold=1.000000e+03 testmode=0 gridtype=0 testfunction=1 repetitions=1 mode=0 bandwidths=2 16 16 32 32 0.024148302868547931454568100662 0.055459529373987133393786308488 0.085036148317179163780288320140 0.111883847193403884734408393342 0.135136368468525447372741155050 0.154045761076810394651914748465 0.168004102156449897087497902248 0.176562705366992644950840940510 0.179446470356206533303122796497 0.176562705366992644950840940510 0.168004102156449897087497902248 0.154045761076810394651914748465 0.135136368468525447372741155050 0.111883847193403884734408393342 0.085036148317179163780288320140 0.055459529373987133393786308488 0.024148302868547931454568100662 0.021867872517185239084058778758 0.050195855139357897778396022659 0.078691039281386376824656281315 0.107223872365252256844136979907 0.135770824783899402010689527742 0.164324411574724438267480763898 0.192881461704887263719498946557 0.221440333046589832299844147201 0.250000000000000000000000000000 0.278559666953410167700155852799 0.307118538295112764036076669072 0.335675588425275617243670467360 0.364229175216100653500461703516 0.392776127634747729278075212278 0.421308960718613623175343718685 0.449804144860642129977179592970 0.478132127482814750507600365381 0.006606227847587484679203750915 0.015321701512934696523537958512 0.023915548101749450893294124398 0.032300358632328871055783281463 0.040401541331669621470723541279 0.048147742818711682100119020333 0.055470846631663503489839683880 0.062306482530317411350218037569 0.068594572818656829316097400806 0.074279854843954107312953283326 0.079312364794886736074630562143 0.083647876067038787195606630576 0.087248287618844302948595270664 0.090081958660638547509158513549 0.092123986643316849165508131136 0.093356426065596062602303106814 0.093768446160209989459488610919 0.093356426065596062602303106814 0.092123986643316849165508131136 0.090081958660638547509158513549 0.087248287618844302948595270664 0.083647876067038787195606630576 0.079312364794886736074630562143 0.074279854843954107312953283326 0.068594572818656829316097400806 0.062306482530317411350218037569 0.055470846631663503489839683880 0.048147742818711682100119020333 0.040401541331669621470723541279 0.032300358632328871055783281463 0.023915548101749450893294124398 0.015321701512934696523537958512 0.006606227847587484679203750915 0.011424646629589122262538047892 0.026224329716335245676894771805 0.041111409496705275667949308627 0.056018231215834990432966833396 0.070932535986010208928220777125 0.085850455629256680611938179482 0.100770388669267227377268625332 0.115691552534641750593635833866 0.130613518882987722502520000489 0.145536032750858829176721087606 0.160458932010607013829428524332 0.175382107696440303623575118763 0.190305482843150408633903225564 0.205229000420828450179655533248 0.220152616025452413373031390620 0.235076293166748051532977115130 0.250000000000000000000000000000 0.264923706833251948467022884870 0.279847383974547614382544225009 0.294770999579171577575920082381 0.309694517156849591366096774436 0.324617892303559696376424881237 0.339541067989393041681722706926 0.354463967249141254090005759281 0.369386481117012333008631230769 0.384308447465358304917515397392 0.399229611330732814256094798111 0.414149544370743361021425243962 0.429067464013989818827354838504 0.443981768784165065078184397862 0.458888590503294724332050691373 0.473775670283664795956468651639 0.488575353370410914166654947621 nfsft=0 testmode=0 gridtype=0 testfunction=1 repetitions=1 mode=0 bandwidths=2 16 16 32 32 0.024148302868547931454568100662 0.055459529373987133393786308488 0.085036148317179163780288320140 0.111883847193403884734408393342 0.135136368468525447372741155050 0.154045761076810394651914748465 0.168004102156449897087497902248 0.176562705366992644950840940510 0.179446470356206533303122796497 0.176562705366992644950840940510 0.168004102156449897087497902248 0.154045761076810394651914748465 0.135136368468525447372741155050 0.111883847193403884734408393342 0.085036148317179163780288320140 0.055459529373987133393786308488 0.024148302868547931454568100662 0.021867872517185239084058778758 0.050195855139357897778396022659 0.078691039281386376824656281315 0.107223872365252256844136979907 0.135770824783899402010689527742 0.164324411574724438267480763898 0.192881461704887263719498946557 0.221440333046589832299844147201 0.250000000000000000000000000000 0.278559666953410167700155852799 0.307118538295112764036076669072 0.335675588425275617243670467360 0.364229175216100653500461703516 0.392776127634747729278075212278 0.421308960718613623175343718685 0.449804144860642129977179592970 0.478132127482814750507600365381 0.006606227847587484679203750915 0.015321701512934696523537958512 0.023915548101749450893294124398 0.032300358632328871055783281463 0.040401541331669621470723541279 0.048147742818711682100119020333 0.055470846631663503489839683880 0.062306482530317411350218037569 0.068594572818656829316097400806 0.074279854843954107312953283326 0.079312364794886736074630562143 0.083647876067038787195606630576 0.087248287618844302948595270664 0.090081958660638547509158513549 0.092123986643316849165508131136 0.093356426065596062602303106814 0.093768446160209989459488610919 0.093356426065596062602303106814 0.092123986643316849165508131136 0.090081958660638547509158513549 0.087248287618844302948595270664 0.083647876067038787195606630576 0.079312364794886736074630562143 0.074279854843954107312953283326 0.068594572818656829316097400806 0.062306482530317411350218037569 0.055470846631663503489839683880 0.048147742818711682100119020333 0.040401541331669621470723541279 0.032300358632328871055783281463 0.023915548101749450893294124398 0.015321701512934696523537958512 0.006606227847587484679203750915 0.011424646629589122262538047892 0.026224329716335245676894771805 0.041111409496705275667949308627 0.056018231215834990432966833396 0.070932535986010208928220777125 0.085850455629256680611938179482 0.100770388669267227377268625332 0.115691552534641750593635833866 0.130613518882987722502520000489 0.145536032750858829176721087606 0.160458932010607013829428524332 0.175382107696440303623575118763 0.190305482843150408633903225564 0.205229000420828450179655533248 0.220152616025452413373031390620 0.235076293166748051532977115130 0.250000000000000000000000000000 0.264923706833251948467022884870 0.279847383974547614382544225009 0.294770999579171577575920082381 0.309694517156849591366096774436 0.324617892303559696376424881237 0.339541067989393041681722706926 0.354463967249141254090005759281 0.369386481117012333008631230769 0.384308447465358304917515397392 0.399229611330732814256094798111 0.414149544370743361021425243962 0.429067464013989818827354838504 0.443981768784165065078184397862 0.458888590503294724332050691373 0.473775670283664795956468651639 0.488575353370410914166654947621 nfft-3.3.2/applications/quadratureS2/example.out000066400000000000000000000005601300072027400217040ustar00rootroot000000000000003 1 1 3 1 1000.000000 0 0 1 1 0 2 16 16 32 32 +6.984776e-04 +3.886121e-06 +4.494552e-06 +2.990931e-03 +6.012098e-06 +4.316038e-06 1 1 6 1 1000.000000 0 0 1 1 0 2 16 16 32 32 +9.052888e-04 +3.140451e-12 +3.298942e-12 +3.696837e-03 +5.486733e-12 +5.527605e-12 0 0 0 1 1 0 2 16 16 32 32 +5.884322e-03 +3.245259e-15 +1.976205e-15 +5.845654e-02 +8.561233e-15 +3.745339e-15 nfft-3.3.2/applications/quadratureS2/lgwt.m000066400000000000000000000041051300072027400206520ustar00rootroot00000000000000function [x,w]=lgwt(N,a,b) %LGWT - Legendre Gauss Quadrature % % This script is for computing definite integrals using Legendre-Gauss % Quadrature. Computes the Legendre-Gauss nodes and weights on an interval % [a,b] with truncation order N % % Suppose you have a continuous function f(x) which is defined on [a,b] % which you can evaluate at any x in [a,b]. Simply evaluate it at all of % the values contained in the x vector to obtain a vector f. Then compute % the definite integral using sum(f.*w); % % Written by Greg von Winckel - 02/25/2004 % Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 % Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. % N=N-1; N1=N+1; N2=N+2; xu=linspace(-1,1,N1)'; % Initial guess y=cos((2*(0:N)'+1)*pi/(2*N+2))+(0.27/N1)*sin(pi*xu*N/N2); % Legendre-Gauss Vandermonde Matrix L=zeros(N1,N2); % Derivative of LGVM Lp=zeros(N1,N2); % Compute the zeros of the N+1 Legendre Polynomial % using the recursion relation and the Newton-Raphson method y0=2; % Iterate until new points are uniformly within epsilon of old points while max(abs(y-y0))>eps L(:,1)=1; Lp(:,1)=0; L(:,2)=y; Lp(:,2)=1; for k=2:N1 L(:,k+1)=( (2*k-1)*y.*L(:,k)-(k-1)*L(:,k-1) )/k; end Lp=(N2)*( L(:,N1)-y.*L(:,N2) )./(1-y.^2); y0=y; y=y0-L(:,N2)./Lp; end % Linear map from[-1,1] to [a,b] x=(a*(1-y)+b*(1+y))/2; % Compute the weights w=(b-a)./((1-y.^2).*Lp.^2)*(N2/N1)^2; nfft-3.3.2/applications/quadratureS2/plotGrid.m000066400000000000000000000057441300072027400214730ustar00rootroot00000000000000function plotGrid(gridType,p) %plotGrid - Plot spherical quadrature grids % % plotGrid(gridtype) plots a quadrature grid. The parameter gridType specifies % the point set to plot and can take the following values: % 0: Gauss-Legendre quadrature grid, % 1: Clenshaw-Curtis qudrature grid, % 2: HEALPix point set, % 3: Equidistribution point set. % % Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 % Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. % if (gridType == 0) [theta,w] = lgwt(p(1)+1,-1,1); theta = acos(theta); phi = 2*pi*(0:(2*p(1)+1))./(2*p(1)+2); [Y,X] = meshgrid(theta,phi); gridName = 'Gauss-Legendre'; temp = repmat(w,[1,length(phi)])'; [Y(:),X(:),temp(:)] size(Y(:)) elseif (gridType == 1) theta = pi*(0:2*p(1))./(2*p(1)); phi = 2*pi*(0:(2*p(1)+1))./(2*p(1)+2); [X,Y] = meshgrid(phi,theta); gridName = 'Clenshaw-Curtis'; elseif (gridType == 2) if log2(p(1)) ~= fix(log2(p(1))) error('NS has to be an INTEGER power of 2') end % initialization of the parameters Y=zeros(12*p(1)^2,1); X=zeros(12*p(1)^2,1); ncoo=0; % North pole for ii=1:p(1)-1 for hh=0:4*ii-1 ncoo=ncoo+1; Y(ncoo)=1-ii^2/(3*p(1)^2); X(ncoo)=2*pi/(4*ii)*(hh+0.5); end end ncoo1=ncoo; % Equator for ii=p(1):3*p(1) for hh=0:4*p(1)-1 ncoo=ncoo+1; Y(ncoo)=2/(3*p(1))*(2*p(1)-ii); X(ncoo)=2*pi/(4*p(1))*(hh+codd(ii)); end end % add the south pole X(ncoo+1:end)=X(ncoo1:-1:1); Y(ncoo+1:end)=-Y(ncoo1:-1:1); Y=acos(Y); gridName = 'HEALPix'; elseif (gridType == 3) X = zeros(2+4*(floor((p(1)+1)/2))*floor(p(1)/2),1); Y = zeros(2+4*(floor((p(1)+1)/2))*floor(p(1)/2),1); X(1) = 0.0; Y(1) = 0.0; d = 2; for k = 1:p(1)-1 thetai = (k*pi)/p(1); if (k<=(p(1)/2)) gammai = 4*k; else gammai = 4*(p(1)-k); end for n = 1:gammai Y(d) = thetai; X(d) = ((n-0.5)*((2.0*pi)/gammai)); d = d+1; end end Y(d) = pi; X(d) = 0.0; size(X) gridName = 'Equidistribution Example 7.1.11'; else error('Wrong grid type!'); end figure; plot(X,Y,'ko'); axis equal; axis([-0.1 2*pi+0.1 -0.1 pi+0.1]); xlabel('Phi'); ylabel('Theta'); title(gridName); return; function coeff=codd(k); if fix(k/2)*2 == k, coeff=0.5;, else, coeff=0;, end return nfft-3.3.2/applications/quadratureS2/quadratureS2.c000066400000000000000000001114751300072027400222560ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \defgroup applications_quadratureS2_test quadratureS2_test * \ingroup applications_quadratureS2 * \{ */ #include "config.h" /* Include standard C headers. */ #include #include #include #include #include #ifdef HAVE_COMPLEX_H #include #endif /* Include NFFT 3 utilities headers. */ /* Include NFFT 3 library header. */ #include "nfft3.h" #include "infft.h" /** Enumeration for parameter values */ enum boolean {NO = 0, YES = 1}; /** Enumeration for test modes */ enum testtype {ERROR = 0, TIMING = 1}; /** Enumeration for quadrature grid types */ enum gridtype {GRID_GAUSS_LEGENDRE = 0, GRID_CLENSHAW_CURTIS = 1, GRID_HEALPIX = 2, GRID_EQUIDISTRIBUTION = 3, GRID_EQUIDISTRIBUTION_UNIFORM = 4}; /** Enumeration for test functions */ enum functiontype {FUNCTION_RANDOM_BANDLIMITED = 0, FUNCTION_F1 = 1, FUNCTION_F2 = 2, FUNCTION_F3 = 3, FUNCTION_F4 = 4, FUNCTION_F5 = 5, FUNCTION_F6 = 6}; /** TODO Add comment here */ enum modes {USE_GRID = 0, RANDOM = 1}; /** * The main program. * * \param argc The number of arguments * \param argv An array containing the arguments as C-strings * * \return Exit code */ int main (int argc, char **argv) { int tc; /**< The index variable for testcases */ int tc_max; /**< The number of testcases */ int *NQ; /**< The array containing the cut-off degrees * \f$N\f$ */ int NQ_max; /**< The maximum cut-off degree \f$N\f$ for the* current testcase */ int *SQ; /**< The array containing the grid size parameters */ int SQ_max; /**< The maximum grid size parameter */ int *RQ; /**< The array containing the grid size parameters */ int iNQ; /**< Index variable for cut-off degrees */ int iNQ_max; /**< The maximum number of cut-off degrees */ int testfunction; /**< The testfunction */ int N; /**< The test function's bandwidth */ int use_nfsft; /**< Whether to use the NFSFT algorithm or not */ int use_nfft; /**< Whether to use the NFFT algorithm or not */ int use_fpt; /**< Whether to use the FPT algorithm or not */ int cutoff; /**< The current NFFT cut-off parameter */ double threshold; /**< The current NFSFT threshold parameter */ int gridtype; /**< The type of quadrature grid to be used */ int repetitions; /**< The number of repetitions to be performed */ int mode; /**< The number of repetitions to be performed */ double *w; /**< The quadrature weights */ double *x_grid; /**< The quadrature nodes */ double *x_compare; /**< The quadrature nodes */ double _Complex *f_grid; /**< The reference function values */ double _Complex *f_compare; /**< The function values */ double _Complex *f; /**< The function values */ double _Complex *f_hat_gen; /**< The reference spherical Fourier * coefficients */ double _Complex *f_hat; /**< The spherical Fourier coefficients */ nfsft_plan plan_adjoint; /**< The NFSFT plan */ nfsft_plan plan; /**< The NFSFT plan */ nfsft_plan plan_gen; /**< The NFSFT plan */ double t_avg; /**< The average computation time needed */ double err_infty_avg; /**< The average error \f$E_\infty\f$ */ double err_2_avg; /**< The average error \f$E_2\f$ */ int i; /**< A loop variable */ int k; /**< A loop variable */ int n; /**< A loop variable */ int d; /**< A loop variable */ int m_theta; /**< The current number of different * colatitudinal angles (for grids) */ int m_phi; /**< The current number of different * longitudinal angles (for grids). */ int m_total; /**< The total number nodes. */ double *theta; /**< An array for saving the angles theta of a * grid */ double *phi; /**< An array for saving the angles phi of a * grid */ fftw_plan fplan; /**< An FFTW plan for computing Clenshaw-Curtis quadrature weights */ //int nside; /**< The size parameter for the HEALPix grid */ int d2; int M; double theta_s; double x1,x2,x3,temp; int m_compare; nfsft_plan *plan_adjoint_ptr; nfsft_plan *plan_ptr; double *w_temp; int testmode; ticks t0, t1; /* Read the number of testcases. */ fscanf(stdin,"testcases=%d\n",&tc_max); fprintf(stdout,"%d\n",tc_max); /* Process each testcase. */ for (tc = 0; tc < tc_max; tc++) { /* Check if the fast transform shall be used. */ fscanf(stdin,"nfsft=%d\n",&use_nfsft); fprintf(stdout,"%d\n",use_nfsft); if (use_nfsft != NO) { /* Check if the NFFT shall be used. */ fscanf(stdin,"nfft=%d\n",&use_nfft); fprintf(stdout,"%d\n",use_nfsft); if (use_nfft != NO) { /* Read the cut-off parameter. */ fscanf(stdin,"cutoff=%d\n",&cutoff); fprintf(stdout,"%d\n",cutoff); } else { /* TODO remove this */ /* Initialize unused variable with dummy value. */ cutoff = 1; } /* Check if the fast polynomial transform shall be used. */ fscanf(stdin,"fpt=%d\n",&use_fpt); fprintf(stdout,"%d\n",use_fpt); if (use_fpt != NO) { /* Read the NFSFT threshold parameter. */ fscanf(stdin,"threshold=%lf\n",&threshold); fprintf(stdout,"%lf\n",threshold); } else { /* TODO remove this */ /* Initialize unused variable with dummy value. */ threshold = 1000.0; } } else { /* TODO remove this */ /* Set dummy values. */ use_nfft = NO; use_fpt = NO; cutoff = 3; threshold = 1000.0; } /* Read the testmode type. */ fscanf(stdin,"testmode=%d\n",&testmode); fprintf(stdout,"%d\n",testmode); if (testmode == ERROR) { /* Read the quadrature grid type. */ fscanf(stdin,"gridtype=%d\n",&gridtype); fprintf(stdout,"%d\n",gridtype); /* Read the test function. */ fscanf(stdin,"testfunction=%d\n",&testfunction); fprintf(stdout,"%d\n",testfunction); /* Check if random bandlimited function has been chosen. */ if (testfunction == FUNCTION_RANDOM_BANDLIMITED) { /* Read the bandwidht. */ fscanf(stdin,"bandlimit=%d\n",&N); fprintf(stdout,"%d\n",N); } else { N = 1; } /* Read the number of repetitions. */ fscanf(stdin,"repetitions=%d\n",&repetitions); fprintf(stdout,"%d\n",repetitions); fscanf(stdin,"mode=%d\n",&mode); fprintf(stdout,"%d\n",mode); if (mode == RANDOM) { /* Read the bandwidht. */ fscanf(stdin,"points=%d\n",&m_compare); fprintf(stdout,"%d\n",m_compare); x_compare = (double*) nfft_malloc(2*m_compare*sizeof(double)); d = 0; while (d < m_compare) { x1 = 2.0*(((double)rand())/RAND_MAX) - 1.0; x2 = 2.0*(((double)rand())/RAND_MAX) - 1.0; x3 = 2.0*(((double)rand())/RAND_MAX) - 1.0; temp = sqrt(x1*x1+x2*x2+x3*x3); if (temp <= 1) { x_compare[2*d+1] = acos(x3); if (x_compare[2*d+1] == 0 || x_compare[2*d+1] == KPI) { x_compare[2*d] = 0.0; } else { x_compare[2*d] = atan2(x2/sin(x_compare[2*d+1]),x1/sin(x_compare[2*d+1])); } x_compare[2*d] *= 1.0/(2.0*KPI); x_compare[2*d+1] *= 1.0/(2.0*KPI); d++; } } f_compare = (double _Complex*) nfft_malloc(m_compare*sizeof(double _Complex)); f = (double _Complex*) nfft_malloc(m_compare*sizeof(double _Complex)); } } /* Initialize maximum cut-off degree and grid size parameter. */ NQ_max = 0; SQ_max = 0; /* Read the number of cut-off degrees. */ fscanf(stdin,"bandwidths=%d\n",&iNQ_max); fprintf(stdout,"%d\n",iNQ_max); /* Allocate memory for the cut-off degrees and grid size parameters. */ NQ = (int*) nfft_malloc(iNQ_max*sizeof(int)); SQ = (int*) nfft_malloc(iNQ_max*sizeof(int)); if (testmode == TIMING) { RQ = (int*) nfft_malloc(iNQ_max*sizeof(int)); } /* Read the cut-off degrees and grid size parameters. */ for (iNQ = 0; iNQ < iNQ_max; iNQ++) { if (testmode == TIMING) { /* Read cut-off degree and grid size parameter. */ fscanf(stdin,"%d %d %d\n",&NQ[iNQ],&SQ[iNQ],&RQ[iNQ]); fprintf(stdout,"%d %d %d\n",NQ[iNQ],SQ[iNQ],RQ[iNQ]); NQ_max = MAX(NQ_max,NQ[iNQ]); SQ_max = MAX(SQ_max,SQ[iNQ]); } else { /* Read cut-off degree and grid size parameter. */ fscanf(stdin,"%d %d\n",&NQ[iNQ],&SQ[iNQ]); fprintf(stdout,"%d %d\n",NQ[iNQ],SQ[iNQ]); NQ_max = MAX(NQ_max,NQ[iNQ]); SQ_max = MAX(SQ_max,SQ[iNQ]); } } /* Do precomputation. */ //fprintf(stderr,"NFSFT Precomputation\n"); //fflush(stderr); nfsft_precompute(NQ_max, threshold, ((use_nfsft==NO)?(NFSFT_NO_FAST_ALGORITHM):(0U)), 0U); if (testmode == TIMING) { /* Allocate data structures. */ f_hat = (double _Complex*) nfft_malloc(NFSFT_F_HAT_SIZE(NQ_max)*sizeof(double _Complex)); f = (double _Complex*) nfft_malloc(SQ_max*sizeof(double _Complex)); x_grid = (double*) nfft_malloc(2*SQ_max*sizeof(double)); for (d = 0; d < SQ_max; d++) { f[d] = (((double)rand())/RAND_MAX)-0.5 + _Complex_I*((((double)rand())/RAND_MAX)-0.5); x_grid[2*d] = (((double)rand())/RAND_MAX) - 0.5; x_grid[2*d+1] = (((double)rand())/RAND_MAX) * 0.5; } } //fprintf(stderr,"Entering loop\n"); //fflush(stderr); /* Process all cut-off bandwidths. */ for (iNQ = 0; iNQ < iNQ_max; iNQ++) { if (testmode == TIMING) { nfsft_init_guru(&plan,NQ[iNQ],SQ[iNQ], NFSFT_NORMALIZED | ((use_nfft!=NO)?(0U):(NFSFT_USE_NDFT)) | ((use_fpt!=NO)?(0U):(NFSFT_USE_DPT)), PRE_PHI_HUT | PRE_PSI | FFTW_INIT | FFTW_MEASURE | FFT_OUT_OF_PLACE, cutoff); plan.f_hat = f_hat; plan.x = x_grid; plan.f = f; nfsft_precompute_x(&plan); t_avg = 0.0; for (i = 0; i < RQ[iNQ]; i++) { t0 = getticks(); if (use_nfsft != NO) { /* Execute the adjoint NFSFT transformation. */ nfsft_adjoint(&plan); } else { /* Execute the adjoint direct NDSFT transformation. */ nfsft_adjoint_direct(&plan); } t1 = getticks(); t_avg += nfft_elapsed_seconds(t1,t0); } t_avg = t_avg/((double)RQ[iNQ]); nfsft_finalize(&plan); fprintf(stdout,"%+le\n", t_avg); fprintf(stderr,"%d: %4d %4d %+le\n", tc, NQ[iNQ], SQ[iNQ], t_avg); } else { /* Determine the maximum number of nodes. */ switch (gridtype) { case GRID_GAUSS_LEGENDRE: /* Calculate grid dimensions. */ m_theta = SQ[iNQ] + 1; m_phi = 2*SQ[iNQ] + 2; m_total = m_theta*m_phi; break; case GRID_CLENSHAW_CURTIS: /* Calculate grid dimensions. */ m_theta = 2*SQ[iNQ] + 1; m_phi = 2*SQ[iNQ] + 2; m_total = m_theta*m_phi; break; case GRID_HEALPIX: m_theta = 1; m_phi = 12*SQ[iNQ]*SQ[iNQ]; m_total = m_theta * m_phi; //fprintf("HEALPix: SQ = %d, m_theta = %d, m_phi= %d, m"); break; case GRID_EQUIDISTRIBUTION: case GRID_EQUIDISTRIBUTION_UNIFORM: m_theta = 2; //fprintf(stderr,"ed: m_theta = %d\n",m_theta); for (k = 1; k < SQ[iNQ]; k++) { m_theta += (int)floor((2*KPI)/acos((cos(KPI/(double)SQ[iNQ])- cos(k*KPI/(double)SQ[iNQ])*cos(k*KPI/(double)SQ[iNQ]))/ (sin(k*KPI/(double)SQ[iNQ])*sin(k*KPI/(double)SQ[iNQ])))); //fprintf(stderr,"ed: m_theta = %d\n",m_theta); } //fprintf(stderr,"ed: m_theta final = %d\n",m_theta); m_phi = 1; m_total = m_theta * m_phi; break; } /* Allocate memory for data structures. */ w = (double*) nfft_malloc(m_theta*sizeof(double)); x_grid = (double*) nfft_malloc(2*m_total*sizeof(double)); //fprintf(stderr,"NQ = %d\n",NQ[iNQ]); //fflush(stderr); switch (gridtype) { case GRID_GAUSS_LEGENDRE: //fprintf(stderr,"Generating grid for NQ = %d, SQ = %d\n",NQ[iNQ],SQ[iNQ]); //fflush(stderr); /* Read quadrature weights. */ for (k = 0; k < m_theta; k++) { fscanf(stdin,"%le\n",&w[k]); w[k] *= (2.0*KPI)/((double)m_phi); } //fprintf(stderr,"Allocating theta and phi\n"); //fflush(stderr); /* Allocate memory to store the grid's angles. */ theta = (double*) nfft_malloc(m_theta*sizeof(double)); phi = (double*) nfft_malloc(m_phi*sizeof(double)); //if (theta == NULL || phi == NULL) //{ //fprintf(stderr,"Couldn't allocate theta and phi\n"); //fflush(stderr); //} /* Read angles theta. */ for (k = 0; k < m_theta; k++) { fscanf(stdin,"%le\n",&theta[k]); } /* Generate the grid angles phi. */ for (n = 0; n < m_phi; n++) { phi[n] = n/((double)m_phi); phi[n] -= ((phi[n]>=0.5)?(1.0):(0.0)); } //fprintf(stderr,"Generating grid nodes\n"); //fflush(stderr); /* Generate the grid's nodes. */ d = 0; for (k = 0; k < m_theta; k++) { for (n = 0; n < m_phi; n++) { x_grid[2*d] = phi[n]; x_grid[2*d+1] = theta[k]; d++; } } //fprintf(stderr,"Freeing theta and phi\n"); //fflush(stderr); /* Free the arrays for the grid's angles. */ nfft_free(theta); nfft_free(phi); break; case GRID_CLENSHAW_CURTIS: /* Allocate memory to store the grid's angles. */ theta = (double*) nfft_malloc(m_theta*sizeof(double)); phi = (double*) nfft_malloc(m_phi*sizeof(double)); /* Generate the grid angles theta. */ for (k = 0; k < m_theta; k++) { theta[k] = k/((double)2*(m_theta-1)); } /* Generate the grid angles phi. */ for (n = 0; n < m_phi; n++) { phi[n] = n/((double)m_phi); phi[n] -= ((phi[n]>=0.5)?(1.0):(0.0)); } /* Generate quadrature weights. */ fplan = fftw_plan_r2r_1d(SQ[iNQ]+1, w, w, FFTW_REDFT00, 0U); for (k = 0; k < SQ[iNQ]+1; k++) { w[k] = -2.0/(4*k*k-1); } fftw_execute(fplan); w[0] *= 0.5; for (k = 0; k < SQ[iNQ]+1; k++) { w[k] *= (2.0*KPI)/((double)(m_theta-1)*m_phi); w[m_theta-1-k] = w[k]; } fftw_destroy_plan(fplan); /* Generate the grid's nodes. */ d = 0; for (k = 0; k < m_theta; k++) { for (n = 0; n < m_phi; n++) { x_grid[2*d] = phi[n]; x_grid[2*d+1] = theta[k]; d++; } } /* Free the arrays for the grid's angles. */ nfft_free(theta); nfft_free(phi); break; case GRID_HEALPIX: d = 0; for (k = 1; k <= SQ[iNQ]-1; k++) { for (n = 0; n <= 4*k-1; n++) { x_grid[2*d+1] = 1 - (k*k)/((double)(3.0*SQ[iNQ]*SQ[iNQ])); x_grid[2*d] = ((n+0.5)/(4*k)); x_grid[2*d] -= (x_grid[2*d]>=0.5)?(1.0):(0.0); d++; } } d2 = d-1; for (k = SQ[iNQ]; k <= 3*SQ[iNQ]; k++) { for (n = 0; n <= 4*SQ[iNQ]-1; n++) { x_grid[2*d+1] = 2.0/(3*SQ[iNQ])*(2*SQ[iNQ]-k); x_grid[2*d] = (n+((k%2==0)?(0.5):(0.0)))/(4*SQ[iNQ]); x_grid[2*d] -= (x_grid[2*d]>=0.5)?(1.0):(0.0); d++; } } for (k = 1; k <= SQ[iNQ]-1; k++) { for (n = 0; n <= 4*k-1; n++) { x_grid[2*d+1] = -x_grid[2*d2+1]; x_grid[2*d] = x_grid[2*d2]; d++; d2--; } } for (d = 0; d < m_total; d++) { x_grid[2*d+1] = acos(x_grid[2*d+1])/(2.0*KPI); } w[0] = (4.0*KPI)/(m_total); break; case GRID_EQUIDISTRIBUTION: case GRID_EQUIDISTRIBUTION_UNIFORM: /* TODO Compute the weights. */ if (gridtype == GRID_EQUIDISTRIBUTION) { w_temp = (double*) nfft_malloc((SQ[iNQ]+1)*sizeof(double)); fplan = fftw_plan_r2r_1d(SQ[iNQ]/2+1, w_temp, w_temp, FFTW_REDFT00, 0U); for (k = 0; k < SQ[iNQ]/2+1; k++) { w_temp[k] = -2.0/(4*k*k-1); } fftw_execute(fplan); w_temp[0] *= 0.5; for (k = 0; k < SQ[iNQ]/2+1; k++) { w_temp[k] *= (2.0*KPI)/((double)(SQ[iNQ])); w_temp[SQ[iNQ]-k] = w_temp[k]; } fftw_destroy_plan(fplan); } d = 0; x_grid[2*d] = -0.5; x_grid[2*d+1] = 0.0; if (gridtype == GRID_EQUIDISTRIBUTION) { w[d] = w_temp[0]; } else { w[d] = (4.0*KPI)/(m_total); } d = 1; x_grid[2*d] = -0.5; x_grid[2*d+1] = 0.5; if (gridtype == GRID_EQUIDISTRIBUTION) { w[d] = w_temp[SQ[iNQ]]; } else { w[d] = (4.0*KPI)/(m_total); } d = 2; for (k = 1; k < SQ[iNQ]; k++) { theta_s = (double)k*KPI/(double)SQ[iNQ]; M = (int)floor((2.0*KPI)/acos((cos(KPI/(double)SQ[iNQ])- cos(theta_s)*cos(theta_s))/(sin(theta_s)*sin(theta_s)))); for (n = 0; n < M; n++) { x_grid[2*d] = (n + 0.5)/M; x_grid[2*d] -= (x_grid[2*d]>=0.5)?(1.0):(0.0); x_grid[2*d+1] = theta_s/(2.0*KPI); if (gridtype == GRID_EQUIDISTRIBUTION) { w[d] = w_temp[k]/((double)(M)); } else { w[d] = (4.0*KPI)/(m_total); } d++; } } if (gridtype == GRID_EQUIDISTRIBUTION) { nfft_free(w_temp); } break; default: break; } /* Allocate memory for grid values. */ f_grid = (double _Complex*) nfft_malloc(m_total*sizeof(double _Complex)); if (mode == RANDOM) { } else { m_compare = m_total; f_compare = (double _Complex*) nfft_malloc(m_compare*sizeof(double _Complex)); x_compare = x_grid; f = f_grid; } //fprintf(stderr,"Generating test function\n"); //fflush(stderr); switch (testfunction) { case FUNCTION_RANDOM_BANDLIMITED: f_hat_gen = (double _Complex*) nfft_malloc(NFSFT_F_HAT_SIZE(N)*sizeof(double _Complex)); //fprintf(stderr,"Generating random test function\n"); //fflush(stderr); /* Generate random function samples by sampling a bandlimited * function. */ nfsft_init_guru(&plan_gen,N,m_total, NFSFT_NORMALIZED | ((use_nfft!=NO)?(0U):(NFSFT_USE_NDFT)) | ((use_fpt!=NO)?(0U):(NFSFT_USE_DPT)), ((N>512)?(0U):(PRE_PHI_HUT | PRE_PSI)) | FFTW_INIT | FFT_OUT_OF_PLACE, cutoff); plan_gen.f_hat = f_hat_gen; plan_gen.x = x_grid; plan_gen.f = f_grid; nfsft_precompute_x(&plan_gen); for (k = 0; k < plan_gen.N_total; k++) { f_hat_gen[k] = 0.0; } for (k = 0; k <= N; k++) { for (n = -k; n <= k; n++) { f_hat_gen[NFSFT_INDEX(k,n,&plan_gen)] = (((double)rand())/RAND_MAX)-0.5 + _Complex_I*((((double)rand())/RAND_MAX)-0.5); } } if (use_nfsft != NO) { /* Execute the NFSFT transformation. */ nfsft_trafo(&plan_gen); } else { /* Execute the direct NDSFT transformation. */ nfsft_trafo_direct(&plan_gen); } nfsft_finalize(&plan_gen); if (mode == RANDOM) { nfsft_init_guru(&plan_gen,N,m_compare, NFSFT_NORMALIZED | ((use_nfft!=NO)?(0U):(NFSFT_USE_NDFT)) | ((use_fpt!=NO)?(0U):(NFSFT_USE_DPT)), ((N>512)?(0U):(PRE_PHI_HUT | PRE_PSI)) | FFTW_INIT | FFT_OUT_OF_PLACE, cutoff); plan_gen.f_hat = f_hat_gen; plan_gen.x = x_compare; plan_gen.f = f_compare; nfsft_precompute_x(&plan_gen); if (use_nfsft != NO) { /* Execute the NFSFT transformation. */ nfsft_trafo(&plan_gen); } else { /* Execute the direct NDSFT transformation. */ nfsft_trafo_direct(&plan_gen); } nfsft_finalize(&plan_gen); } else { memcpy(f_compare,f_grid,m_total*sizeof(double _Complex)); } nfft_free(f_hat_gen); break; case FUNCTION_F1: for (d = 0; d < m_total; d++) { x1 = sin(x_grid[2*d+1]*2.0*KPI)*cos(x_grid[2*d]*2.0*KPI); x2 = sin(x_grid[2*d+1]*2.0*KPI)*sin(x_grid[2*d]*2.0*KPI); x3 = cos(x_grid[2*d+1]*2.0*KPI); f_grid[d] = x1*x2*x3; } if (mode == RANDOM) { for (d = 0; d < m_compare; d++) { x1 = sin(x_compare[2*d+1]*2.0*KPI)*cos(x_compare[2*d]*2.0*KPI); x2 = sin(x_compare[2*d+1]*2.0*KPI)*sin(x_compare[2*d]*2.0*KPI); x3 = cos(x_compare[2*d+1]*2.0*KPI); f_compare[d] = x1*x2*x3; } } else { memcpy(f_compare,f_grid,m_total*sizeof(double _Complex)); } break; case FUNCTION_F2: for (d = 0; d < m_total; d++) { x1 = sin(x_grid[2*d+1]*2.0*KPI)*cos(x_grid[2*d]*2.0*KPI); x2 = sin(x_grid[2*d+1]*2.0*KPI)*sin(x_grid[2*d]*2.0*KPI); x3 = cos(x_grid[2*d+1]*2.0*KPI); f_grid[d] = 0.1*exp(x1+x2+x3); } if (mode == RANDOM) { for (d = 0; d < m_compare; d++) { x1 = sin(x_compare[2*d+1]*2.0*KPI)*cos(x_compare[2*d]*2.0*KPI); x2 = sin(x_compare[2*d+1]*2.0*KPI)*sin(x_compare[2*d]*2.0*KPI); x3 = cos(x_compare[2*d+1]*2.0*KPI); f_compare[d] = 0.1*exp(x1+x2+x3); } } else { memcpy(f_compare,f_grid,m_total*sizeof(double _Complex)); } break; case FUNCTION_F3: for (d = 0; d < m_total; d++) { x1 = sin(x_grid[2*d+1]*2.0*KPI)*cos(x_grid[2*d]*2.0*KPI); x2 = sin(x_grid[2*d+1]*2.0*KPI)*sin(x_grid[2*d]*2.0*KPI); x3 = cos(x_grid[2*d+1]*2.0*KPI); temp = sqrt(x1*x1)+sqrt(x2*x2)+sqrt(x3*x3); f_grid[d] = 0.1*temp; } if (mode == RANDOM) { for (d = 0; d < m_compare; d++) { x1 = sin(x_compare[2*d+1]*2.0*KPI)*cos(x_compare[2*d]*2.0*KPI); x2 = sin(x_compare[2*d+1]*2.0*KPI)*sin(x_compare[2*d]*2.0*KPI); x3 = cos(x_compare[2*d+1]*2.0*KPI); temp = sqrt(x1*x1)+sqrt(x2*x2)+sqrt(x3*x3); f_compare[d] = 0.1*temp; } } else { memcpy(f_compare,f_grid,m_total*sizeof(double _Complex)); } break; case FUNCTION_F4: for (d = 0; d < m_total; d++) { x1 = sin(x_grid[2*d+1]*2.0*KPI)*cos(x_grid[2*d]*2.0*KPI); x2 = sin(x_grid[2*d+1]*2.0*KPI)*sin(x_grid[2*d]*2.0*KPI); x3 = cos(x_grid[2*d+1]*2.0*KPI); temp = sqrt(x1*x1)+sqrt(x2*x2)+sqrt(x3*x3); f_grid[d] = 1.0/(temp); } if (mode == RANDOM) { for (d = 0; d < m_compare; d++) { x1 = sin(x_compare[2*d+1]*2.0*KPI)*cos(x_compare[2*d]*2.0*KPI); x2 = sin(x_compare[2*d+1]*2.0*KPI)*sin(x_compare[2*d]*2.0*KPI); x3 = cos(x_compare[2*d+1]*2.0*KPI); temp = sqrt(x1*x1)+sqrt(x2*x2)+sqrt(x3*x3); f_compare[d] = 1.0/(temp); } } else { memcpy(f_compare,f_grid,m_total*sizeof(double _Complex)); } break; case FUNCTION_F5: for (d = 0; d < m_total; d++) { x1 = sin(x_grid[2*d+1]*2.0*KPI)*cos(x_grid[2*d]*2.0*KPI); x2 = sin(x_grid[2*d+1]*2.0*KPI)*sin(x_grid[2*d]*2.0*KPI); x3 = cos(x_grid[2*d+1]*2.0*KPI); temp = sqrt(x1*x1)+sqrt(x2*x2)+sqrt(x3*x3); f_grid[d] = 0.1*sin(1+temp)*sin(1+temp); } if (mode == RANDOM) { for (d = 0; d < m_compare; d++) { x1 = sin(x_compare[2*d+1]*2.0*KPI)*cos(x_compare[2*d]*2.0*KPI); x2 = sin(x_compare[2*d+1]*2.0*KPI)*sin(x_compare[2*d]*2.0*KPI); x3 = cos(x_compare[2*d+1]*2.0*KPI); temp = sqrt(x1*x1)+sqrt(x2*x2)+sqrt(x3*x3); f_compare[d] = 0.1*sin(1+temp)*sin(1+temp); } } else { memcpy(f_compare,f_grid,m_total*sizeof(double _Complex)); } break; case FUNCTION_F6: for (d = 0; d < m_total; d++) { if (x_grid[2*d+1] <= 0.25) { f_grid[d] = 1.0; } else { f_grid[d] = 1.0/(sqrt(1+3*cos(2.0*KPI*x_grid[2*d+1])*cos(2.0*KPI*x_grid[2*d+1]))); } } if (mode == RANDOM) { for (d = 0; d < m_compare; d++) { if (x_compare[2*d+1] <= 0.25) { f_compare[d] = 1.0; } else { f_compare[d] = 1.0/(sqrt(1+3*cos(2.0*KPI*x_compare[2*d+1])*cos(2.0*KPI*x_compare[2*d+1]))); } } } else { memcpy(f_compare,f_grid,m_total*sizeof(double _Complex)); } break; default: //fprintf(stderr,"Generating one function\n"); //fflush(stderr); for (d = 0; d < m_total; d++) { f_grid[d] = 1.0; } if (mode == RANDOM) { for (d = 0; d < m_compare; d++) { f_compare[d] = 1.0; } } else { memcpy(f_compare,f_grid,m_total*sizeof(double _Complex)); } break; } //fprintf(stderr,"Initializing trafo\n"); //fflush(stderr); /* Init transform plan. */ nfsft_init_guru(&plan_adjoint,NQ[iNQ],m_total, NFSFT_NORMALIZED | ((use_nfft!=NO)?(0U):(NFSFT_USE_NDFT)) | ((use_fpt!=NO)?(0U):(NFSFT_USE_DPT)), ((NQ[iNQ]>512)?(0U):(PRE_PHI_HUT | PRE_PSI)) | FFTW_INIT | FFT_OUT_OF_PLACE, cutoff); plan_adjoint_ptr = &plan_adjoint; if (mode == RANDOM) { nfsft_init_guru(&plan,NQ[iNQ],m_compare, NFSFT_NORMALIZED | ((use_nfft!=NO)?(0U):(NFSFT_USE_NDFT)) | ((use_fpt!=NO)?(0U):(NFSFT_USE_DPT)), ((NQ[iNQ]>512)?(0U):(PRE_PHI_HUT | PRE_PSI)) | FFTW_INIT | FFT_OUT_OF_PLACE, cutoff); plan_ptr = &plan; } else { plan_ptr = &plan_adjoint; } f_hat = (double _Complex*) nfft_malloc(NFSFT_F_HAT_SIZE(NQ[iNQ])*sizeof(double _Complex)); plan_adjoint_ptr->f_hat = f_hat; plan_adjoint_ptr->x = x_grid; plan_adjoint_ptr->f = f_grid; plan_ptr->f_hat = f_hat; plan_ptr->x = x_compare; plan_ptr->f = f; //fprintf(stderr,"Precomputing for x\n"); //fflush(stderr); nfsft_precompute_x(plan_adjoint_ptr); if (plan_adjoint_ptr != plan_ptr) { nfsft_precompute_x(plan_ptr); } /* Initialize cumulative time variable. */ t_avg = 0.0; err_infty_avg = 0.0; err_2_avg = 0.0; /* Cycle through all runs. */ for (i = 0; i < 1/*repetitions*/; i++) { //fprintf(stderr,"Copying original values\n"); //fflush(stderr); /* Copy exact funtion values to working array. */ //memcpy(f,f_grid,m_total*sizeof(double _Complex)); /* Initialize time measurement. */ t0 = getticks(); //fprintf(stderr,"Multiplying with quadrature weights\n"); //fflush(stderr); /* Multiplication with the quadrature weights. */ /*fprintf(stderr,"\n");*/ d = 0; for (k = 0; k < m_theta; k++) { for (n = 0; n < m_phi; n++) { /*fprintf(stderr,"f_ref[%d] = %le + I*%le,\t f[%d] = %le + I*%le, \t w[%d] = %le\n", d,creal(f_ref[d]),cimag(f_ref[d]),d,creal(f[d]),cimag(f[d]),k, w[k]);*/ f_grid[d] *= w[k]; d++; } } t1 = getticks(); t_avg += nfft_elapsed_seconds(t1,t0); nfft_free(w); t0 = getticks(); /*fprintf(stderr,"\n"); d = 0; for (d = 0; d < grid_total; d++) { fprintf(stderr,"f[%d] = %le + I*%le, theta[%d] = %le, phi[%d] = %le\n", d,creal(f[d]),cimag(f[d]),d,x[2*d+1],d,x[2*d]); }*/ //fprintf(stderr,"Executing adjoint\n"); //fflush(stderr); /* Check if the fast NFSFT algorithm shall be tested. */ if (use_nfsft != NO) { /* Execute the adjoint NFSFT transformation. */ nfsft_adjoint(plan_adjoint_ptr); } else { /* Execute the adjoint direct NDSFT transformation. */ nfsft_adjoint_direct(plan_adjoint_ptr); } /* Multiplication with the Fourier-Legendre coefficients. */ /*for (k = 0; k <= m[im]; k++) { for (n = -k; n <= k; n++) { fprintf(stderr,"f_hat[%d,%d] = %le\t + I*%le\n",k,n, creal(f_hat[NFSFT_INDEX(k,n,&plan_adjoint)]), cimag(f_hat[NFSFT_INDEX(k,n,&plan_adjoint)])); } }*/ //fprintf(stderr,"Executing trafo\n"); //fflush(stderr); if (use_nfsft != NO) { /* Execute the NFSFT transformation. */ nfsft_trafo(plan_ptr); } else { /* Execute the direct NDSFT transformation. */ nfsft_trafo_direct(plan_ptr); } t1 = getticks(); t_avg += nfft_elapsed_seconds(t1,t0); //fprintf(stderr,"Finalizing\n"); //fflush(stderr); /* Finalize the NFSFT plans */ nfsft_finalize(plan_adjoint_ptr); if (plan_ptr != plan_adjoint_ptr) { nfsft_finalize(plan_ptr); } /* Free data arrays. */ nfft_free(f_hat); nfft_free(x_grid); err_infty_avg += X(error_l_infty_complex)(f, f_compare, m_compare); err_2_avg += X(error_l_2_complex)(f, f_compare, m_compare); nfft_free(f_grid); if (mode == RANDOM) { } else { nfft_free(f_compare); } /*for (d = 0; d < m_total; d++) { fprintf(stderr,"f_ref[%d] = %le + I*%le,\t f[%d] = %le + I*%le\n", d,creal(f_ref[d]),cimag(f_ref[d]),d,creal(f[d]),cimag(f[d])); }*/ } //fprintf(stderr,"Calculating the error\n"); //fflush(stderr); /* Calculate average time needed. */ t_avg = t_avg/((double)repetitions); /* Calculate the average error. */ err_infty_avg = err_infty_avg/((double)repetitions); /* Calculate the average error. */ err_2_avg = err_2_avg/((double)repetitions); /* Print out the error measurements. */ fprintf(stdout,"%+le %+le %+le\n", t_avg, err_infty_avg, err_2_avg); fprintf(stderr,"%d: %4d %4d %+le %+le %+le\n", tc, NQ[iNQ], SQ[iNQ], t_avg, err_infty_avg, err_2_avg); } } /* for (im = 0; im < im_max; im++) - Process all cut-off * bandwidths.*/ fprintf(stderr,"\n"); /* Delete precomputed data. */ nfsft_forget(); /* Free memory for cut-off bandwidths and grid size parameters. */ nfft_free(NQ); nfft_free(SQ); if (testmode == TIMING) { nfft_free(RQ); } if (mode == RANDOM) { nfft_free(x_compare); nfft_free(f_compare); nfft_free(f); } if (testmode == TIMING) { /* Allocate data structures. */ nfft_free(f_hat); nfft_free(f); nfft_free(x_grid); } } /* for (tc = 0; tc < tc_max; tc++) - Process each testcase. */ /* Return exit code for successful run. */ return EXIT_SUCCESS; } /* \} */ nfft-3.3.2/applications/quadratureS2/quadratureS2.m000066400000000000000000000141261300072027400222630ustar00rootroot00000000000000function quadratureS2() %QUADRATURES2 % % Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 % Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. % % The name of the input file infilename = 'data.in'; % The name of the output file outfilename = 'data.out'; % The name of the program if ispc programname='quadratureS2.exe'; else programname='./quadratureS2'; end % Display the menu. selection = menu('quadratureS2 - Fast evaluation of quadrature formulae on the sphere',... 'Generate Figure 6.1 (a)','Generate Figure 6.1 (b)','Generate Figure 6.2 (a)',... 'Generate Figure 6.2 (b)') % Open input data file. file = fopen(infilename,'w'); if (selection == 1) % Set the grid type. % 0 = Gauss-Legendre gridtype = 0; % Set the number of repetitions. repetitions = 1; % Set the size parameters. S1 = 16:16:1024; %S1 = 16:16:128; S2 = [16,32,64,128,256,512,1024]; %S2 = [16,32,64,128]; % Set the bandwidhts. N1 = S1; N2 = S2; % Write the number of testcases. fprintf(file,'testcases=3\n'); % Write the testcases. writeTestcase(file,1,1,3,1,1000,0,gridtype,[1],repetitions,[0],[N1;S1]); writeTestcase(file,1,1,6,1,1000,0,gridtype,[1],repetitions,[0],[N1;S1]); writeTestcase(file,0,0,0,0,1000,0,gridtype,[1],repetitions,[0],[N2;S2]); elseif (selection == 2) % Set the grid type. % 0 = Gauss-Legendre gridtype=0; % Set the number of repetitions. repetitions=1; % Set the bandwidhts. N=16:16:1024; % Set the size parameters. S=1024*ones(size(N)); % Write the number of testcases. fprintf(file,'testcases=4\n'); % Write the testcases. writeTestcase(file,1,1,6,1,1000,0,gridtype,[3],repetitions,[0],[N;S]); writeTestcase(file,1,1,6,1,1000,0,gridtype,[4],repetitions,[0],[N;S]); writeTestcase(file,1,1,6,1,1000,0,gridtype,[5],repetitions,[0],[N;S]); writeTestcase(file,1,1,6,1,1000,0,gridtype,[6],repetitions,[0],[N;S]); elseif (selection == 3) % Set the number of repetitions. repetitions=1; % Set the size parameters. S1 = 16:16:1024; S2 = [1,2,4,8,16,32,64,128,256,512]; %S1 = 16:16:256; %S2 = [1,2,4,8,16,32,64,128]; % Set the bandwidhts. N1 = 128*ones(1,length(S1)); N2 = 128*ones(1,length(S2)); % Write the number of testcases. fprintf(file,'testcases=4\n'); % Write the testcases. writeTestcase(file,1,1,6,1,1000,0,0,[0,128],repetitions,[0],[N1;S1]); writeTestcase(file,1,1,6,1,1000,0,1,[0,128],repetitions,[0],[N1;S1]); writeTestcase(file,1,1,6,1,1000,0,2,[0,128],repetitions,[0],[N2;S2]); writeTestcase(file,1,1,6,1,1000,0,3,[0,128],repetitions,[0],[N1;S1]); elseif (selection == 4) % Set the grid type. % 1 = Clenshaw-Curtis gridtype=1; % Set the number of repetitions. repetitions=1; % Set the bandwidhts. N=16:16:1024; %N=16:16:128; % Set the number of nodes. Q=N.*N; % Set the number of repetitions R=ceil(7500./(N.^(1.5))); %horzcat(100:-10:20,20*ones(1,length(N)-length(100:-10:20))); % Set the bandwidhts. N2=[1,2,4,8,16,32,64,128,256,512,1024]; %N2=[16,32,64,128]; % Set the number of nodes. Q2=N2.*N2; % Set the number of repetitions R2=ceil(7500./(N2.^(2))); %horzcat(100:-10:20,20*ones(1,length(N)-length(100:-10:20))); % Write the number of testcases. fprintf(file,'testcases=2\n'); % Write the testcases. writeTestcase(file,1,1,6,1,1000,1,gridtype,[0,128],repetitions,[0],[N;Q;R]); writeTestcase(file,0,1,6,1,1000,1,gridtype,[0,128],repetitions,[0],[N2;Q2;R2]); else error('Wrong selection!'); end fclose(file); fprintf('Program in execution. Please be patient! This may take a while!\n'); system(sprintf('%s < %s > %s',programname,infilename,outfilename)); file = fopen(outfilename,'r'); T = readTestcase(file); fclose(file); figure('Color',[1 1 1],'InvertHardcopy','off','PaperSize',[20.98 29.68]); axes('FontSize',16); if (selection == 1) %if (false) x = T{1}.parameters(:,1); semilogy(x,T{1}.data(:,3),'-.','LineWidth',2,'Color',[0,0,0]); hold on semilogy(x,T{2}.data(:,3),'--','LineWidth',2,'Color',[0,0,0]); x2 = T{3}.parameters(:,1); semilogy(x2,T{3}.data(:,3),'-','LineWidth',2,'Color',[0,0,0]); semilogy(x2,T{3}.data(:,3),'.','MarkerSize',2,'Color',[0,0,0]); axis([x(1) x(end) 1e-16 1e-5]) xlabel('S=M'); ylabel('E_{\infty}','Rotation',0); elseif (selection == 2) x = T{1}.parameters(:,1); semilogy(x,T{1}.data(:,3),'-.','LineWidth',2,'Color',[0,0,0]); hold on semilogy(x,T{2}.data(:,3),':','LineWidth',2,'Color',[0,0,0]); semilogy(x,T{3}.data(:,3),'--','LineWidth',2,'Color',[0,0,0]); semilogy(x,T{4}.data(:,3),'-','LineWidth',2,'Color',[0,0,0]); axis([x(1) x(end) 1e-12 1e-0]) xlabel('M'); ylabel('E_{\infty}','Rotation',0); elseif (selection == 3) x = T{1}.parameters(:,2); semilogy(x,T{1}.data(:,3),'-','LineWidth',2,'Color',[0,0,0]); hold on semilogy(x,T{2}.data(:,3),'--','LineWidth',2,'Color',[0,0,0]); semilogy(x,T{3}.data(:,3),':','LineWidth',2,'Color',[0,0,0]); semilogy(x,T{3}.data(:,3),'.','MarkerSize',2,'Color',[0,0,0]); semilogy(x,T{4}.data(:,3),'-.','LineWidth',2,'Color',[0,0,0]); axis([x(1) x(end) 1e-12 1e+0]) xlabel('S'); ylabel('E_{\infty}','Rotation',0); elseif (selection == 4) x = T{1}.parameters(:,1); x2 = T{2}.parameters(:,1); semilogy(x,T{1}.data(:,1),'--','LineWidth',2,'Color',[0,0,0]); hold on semilogy(x2,T{2}.data(:,1),'-','LineWidth',2,'Color',[0,0,0]); semilogy(x2,T{2}.data(:,1),'.','MarkerSize',2,'Color',[0,0,0]); axis([x(1) x(end) 1e-4 1e+6]) xlabel('M'); ylabel('T','Rotation',0); end nfft-3.3.2/applications/quadratureS2/readTestcase.m000066400000000000000000000074631300072027400223160ustar00rootroot00000000000000function T = readTestcase(file) %READTESTCASE - Read quadratureS2.c testcase results from file % % Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 % Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. % % Read the number of testcases. tc_max = fscanf(file,'%d',1); % Create empty cell array for the testcases. T = cell(tc_max,1); % Cycle through all testcases. for i = 1:tc_max % Create structure. t = struct('USENFSFT',[0],'USENFFT',[0],'CUTOFF',[0],'USEFPT',[0],... 'THRESHOLD',[0],'testmode',[0],'gridtype',{0},'testfunction',[0],... 'bandlimit',[0],'repetitions',[0],'mode',{0},'points',[0],... 'parameters',[0],'data',[0]); % Read NFSFT usage flag. v = fscanf(file,'%d',1); if (v >= 1) % Set NFSFT usage flag in the structure. t.USENFSFT = [true]; % Read NFFT usage flag. v = fscanf(file,'%d',1); if (v >= 1) % Set NFSFT usage flag in the structure. t.USENFFFT = [true]; % Read the NFFT cut-off parameter. v = fscanf(file,'%d',1); t.CUTOFF = [v]; else % Set NFSFT usage flag in the structure. t.USENFFFT = [false]; end % Read FPT usage flag. v = fscanf(file,'%d',1); if (v >= 1) % Set NFSFT usage flag in the structure. t.USEFPT = [true]; % Read the FPT threshold. v = fscanf(file,'%lf',1); t.THRESHOLD = [v]; else % Set NFSFT usage flag in the structure. t.USEFPT = [false]; end else % Set NFSFT usage flag in the structure. t.USENFSFT = [false]; end % Read the test mode. v = fscanf(file,'%d',1); t.testmode = [v]; if (v == 0) % Read the grid type. v = fscanf(file,'%d',1); t.gridtype = [v]; % Read the testfunction. v = fscanf(file,'%d',1); t.testfunction = [v]; if (v == 0) % Read the badnlimit. v = fscanf(file,'%d',1); t.bandlimit = [v]; end % Read the number of repetitions. v = fscanf(file,'%d',1); t.repetitions = [v]; % Read the mode. v = fscanf(file,'%d',1); t.mode = [v]; if (v == 1) % Read the points. v = fscanf(file,'%d',1); t.points = [v]; end end % Read the number of bandwidths. v = fscanf(file,'%d',1); if (t.testmode == 0) % Create empty array for parameters. p = zeros(2,v); % Create empty array for parameters. data = zeros(3,v); % Read parameters. p = fscanf(file,'%d',[2,v]); % Transpose matrix to get dimensions right. t.parameters = p'; % Read parameters. data = fscanf(file,'%lf',[3,v]); % Transpose matrix to get dimensions right. t.data = data'; else % Create empty array for parameters. p = zeros(3,v); % Create empty array for parameters. data = zeros(1,v); % Read parameters. p = fscanf(file,'%d',[3,v]); % Transpose matrix to get dimensions right. t.parameters = p'; % Read parameters. data = fscanf(file,'%lf',[1,v]); % Transpose matrix to get dimensions right. t.data = data'; end % Assign testcase structure to field in cell array. T{i} = t; end % End of the function return; nfft-3.3.2/applications/quadratureS2/writeTestcase.m000066400000000000000000000044321300072027400225260ustar00rootroot00000000000000function writeTestcase(file,usenfsft,usenfft,cutoff,usefpt,threshold,... testmode,gridtype,testfunction,repetitions,mode,bandwidths) %WRITETESTCASE - Write qudratureS2 testcases % % Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 % Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. % % Write usenfsft fprintf(file,'nfsft=%d\n',usenfsft); if (usenfsft == 1) % Write usenfft fprintf(file,'nfft=%d\n',usenfft); if (usenfft == 1) % Write NFFT cut-off parameter fprintf(file,'cutoff=%d\n',cutoff); end % Write use FPT fprintf(file,'fpt=%d\n',usefpt); if (usefpt == 1) % Write NFSFT threshold fprintf(file,'threshold=%e\n',threshold); end end fprintf(file,'testmode=%d\n',testmode); if (testmode == 0) % Write grid type fprintf(file,'gridtype=%d\n',gridtype); % Write grid type fprintf(file,'testfunction=%d\n',testfunction(1)); if (testfunction(1) == 0) fprintf(file,'bandlimit=%d\n',testfunction(2)); end % Write number of repetitions fprintf(file,'repetitions=%d\n',repetitions); % Write mode fprintf(file,'mode=%d\n',mode(1)); if (mode(1) == 1) % Write points fprintf(file,'points=%d\n',mode(2)); end end % Write number of bandwidths fprintf(file,'bandwidths=%d\n',size(bandwidths,2)); if (testmode == 0) % Write bandwidths fprintf(file,'%d %d\n',bandwidths); else % Write bandwidths fprintf(file,'%d %d %d\n',bandwidths); end % Check if we need to provide also quadrature weights. This is the case if % the Gauss-Legendre quadrature grid is used. if (gridtype==0) writeWeights(file,bandwidths(2,:)); end nfft-3.3.2/applications/quadratureS2/writeWeights.m000066400000000000000000000022421300072027400223620ustar00rootroot00000000000000function writeWeights(file,m) %WRITEWEIGHTS % % Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS % FOR A PARTICULAR PURPOSE. See the GNU General Public License for more % details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 % Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. % for k = m % Generate Gauss-Legendre nodes in co-latitudinal direction. [theta,w] = lgwt(k+1,-1,1); theta = (1/(2*pi))*acos(theta); % Write data to file. fprintf(file,'\n'); fprintf(file,'\n'); fprintf(file,'%.30f\n',w); fprintf(file,'\n'); fprintf(file,'%.30f\n',theta); end nfft-3.3.2/applications/radon/000077500000000000000000000000001300072027400162405ustar00rootroot00000000000000nfft-3.3.2/applications/radon/Makefile.am000066400000000000000000000005611300072027400202760ustar00rootroot00000000000000AM_CPPFLAGS = -I$(top_srcdir)/include noinst_PROGRAMS = radon inverse_radon radon_SOURCES = radon.c radon_LDADD = $(top_builddir)/libnfft3@PREC_SUFFIX@.la @fftw3_LDFLAGS@ @fftw3_LIBS@ inverse_radon_SOURCES = inverse_radon.c inverse_radon_LDADD = $(top_builddir)/libnfft3@PREC_SUFFIX@.la @fftw3_LDFLAGS@ @fftw3_LIBS@ EXTRA_DIST = phantom.m radon.m ridgelet.m README nfft-3.3.2/applications/radon/README000066400000000000000000000022651300072027400171250ustar00rootroot00000000000000radon - Fast discrete NFFT-based Radon transform This folder includes simple C programs (radon.c, inverse_radon.c) for the computation of a fast discrete NFFT-based Radon transform and its inverse. Use the Matlab script file radon.m for a simple demonstration. The Matlab script file ridgelet.m contains an example of denoising by hard thresholding the discrete ridgelet coefficients of a noisy image. The discrete ridgelet transform is based on the fast discrete NFFT-based Radon transform. References: [1] M. Fenn. Fast Fourier Transform at Nonequispaced Nodes and Applications, PhD Thesis, University of Mannheim, 2005. [2] J. Ma and M. Fenn. Combined complex ridgelet shrinkage and total variation minimization. SIAM J. Sci. Comput. 28, 984-1000, 2006. [3] D. Potts, and G. Steidl, G. A new linogram algorithm for computerized tomography. IMA J. Numer. Anal. 21, 769-782, 2001 [4] D. Potts, and G. Steidl, New Fourier reconstruction algorithms for computerized tomography. in: Proceedings of SPIE: Wavelet Applications in Signal and Image Processing VIII,A. Aldroubi,A.F. Laine, M.A. Unser (Eds.), Vol.:4119, pages 13-23, 2000 nfft-3.3.2/applications/radon/inverse_radon.c.in000066400000000000000000000220501300072027400216460ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file inverse_radon.c * \brief NFFT-based discrete inverse Radon transform. * * Computes the inverse of the discrete Radon transform * \f[ * R_{\theta_t} f\left(\frac{s}{R}\right) * = \sum_{r \in I_R} w_r \; \sum_{k \in I_N^2} f_{k} * \mathrm{e}^{-2\pi\mathrm{I} k \; (\frac{r}{R}\theta_t)} * \, \mathrm{e}^{2\pi\mathrm{i} r s / R} * \qquad(t \in I_T, s \in I_R). * \f] * given at the points \f$\frac{r}{R}\theta_t\f$ of the polar or linogram grid * and where \f$w_r\f$ are the weights of the Dirichlet- or Fejer-kernel * by 1D-FFTs and the 2D-iNFFT. * \author Markus Fenn * \date 2005 */ #include #include #include #include #include #define @NFFT_PRECISION_MACRO@ #include "nfft3mp.h" /** define weights of kernel function for discrete Radon transform */ /*#define KERNEL(r) 1.0 */ #define KERNEL(r) (NFFT_K(1.0)-NFFT_M(fabs)((NFFT_R)(r))/((NFFT_R)S/2)) /** generates the points x with weights w * for the polar grid with T angles and R offsets */ static int polar_grid(int T, int S, NFFT_R *x, NFFT_R *w) { int t, r; NFFT_R W = (NFFT_R) T * (((NFFT_R) S / NFFT_K(2.0)) * ((NFFT_R) S / NFFT_K(2.0)) + NFFT_K(1.0) / NFFT_K(4.0)); for (t = -T / 2; t < T / 2; t++) { for (r = -S / 2; r < S / 2; r++) { x[2 * ((t + T / 2) * S + (r + S / 2)) + 0] = (NFFT_R) r / (NFFT_R)(S) * NFFT_M(cos)(NFFT_KPI * (NFFT_R)(t) / (NFFT_R)(T)); x[2 * ((t + T / 2) * S + (r + S / 2)) + 1] = (NFFT_R) r / (NFFT_R)(S) * NFFT_M(sin)(NFFT_KPI * (NFFT_R)(t) / (NFFT_R)(T)); if (r == 0) w[(t + T / 2) * S + (r + S / 2)] = NFFT_K(1.0) / NFFT_K(4.0) / W; else w[(t + T / 2) * S + (r + S / 2)] = NFFT_M(fabs)((NFFT_R) r) / W; } } return 0; } /** generates the points x with weights w * for the linogram grid with T slopes and R offsets */ static int linogram_grid(int T, int S, NFFT_R *x, NFFT_R *w) { int t, r; NFFT_R W = (NFFT_R) T * (((NFFT_R) S / NFFT_K(2.0)) * ((NFFT_R) S / NFFT_K(2.0)) + NFFT_K(1.0) / NFFT_K(4.0)); for (t = -T / 2; t < T / 2; t++) { for (r = -S / 2; r < S / 2; r++) { if (t < 0) { x[2 * ((t + T / 2) * S + (r + S / 2)) + 0] = (NFFT_R) r / (NFFT_R)(S); x[2 * ((t + T / 2) * S + (r + S / 2)) + 1] = NFFT_K(4.0) * ((NFFT_R)(t) + (NFFT_R)(T) / NFFT_K(4.0)) / (NFFT_R)(T) * (NFFT_R)(r) / (NFFT_R)(S); } else { x[2 * ((t + T / 2) * S + (r + S / 2)) + 0] = -NFFT_K(4.0) * ((NFFT_R)(t) - (NFFT_R)(T) / NFFT_K(4.0)) / (NFFT_R)(T) * (NFFT_R)(r) / (NFFT_R)(S); x[2 * ((t + T / 2) * S + (r + S / 2)) + 1] = (NFFT_R) r / (NFFT_R)(S); } if (r == 0) w[(t + T / 2) * S + (r + S / 2)] = NFFT_K(1.0) / NFFT_K(4.0) / W; else w[(t + T / 2) * S + (r + S / 2)] = NFFT_M(fabs)((NFFT_R) r) / W; } } return 0; } /** computes the inverse discrete Radon transform of Rf * on the grid given by gridfcn() with T angles and R offsets * by a NFFT-based CG-type algorithm */ static int inverse_radon_trafo(int (*gridfcn)(), int T, int S, NFFT_R *Rf, int NN, NFFT_R *f, int max_i) { int j, k; /**< index for nodes and freqencies */ NFFT(plan) my_nfft_plan; /**< plan for the nfft-2D */ SOLVER(plan_complex) my_infft_plan; /**< plan for the inverse nfft */ NFFT_C *fft; /**< variable for the fftw-1Ds */ FFTW(plan) my_fftw_plan; /**< plan for the fftw-1Ds */ int t, r; /**< index for directions and offsets */ NFFT_R *x, *w; /**< knots and associated weights */ int l; /**< index for iterations */ int N[2], n[2]; int M = T * S; N[0] = NN; n[0] = 2 * N[0]; N[1] = NN; n[1] = 2 * N[1]; fft = (NFFT_C *) NFFT(malloc)((size_t)(S) * sizeof(NFFT_C)); my_fftw_plan = FFTW(plan_dft_1d)(S, fft, fft, FFTW_FORWARD, FFTW_MEASURE); x = (NFFT_R *) NFFT(malloc)((size_t)(2 * T * S) * (sizeof(NFFT_R))); if (x == NULL) return EXIT_FAILURE; w = (NFFT_R *) NFFT(malloc)((size_t)(T * S) * (sizeof(NFFT_R))); if (w == NULL) return EXIT_FAILURE; /** init two dimensional NFFT plan */ NFFT(init_guru)(&my_nfft_plan, 2, N, M, n, 4, PRE_PHI_HUT | PRE_PSI | MALLOC_X | MALLOC_F_HAT | MALLOC_F | FFTW_INIT | FFT_OUT_OF_PLACE, FFTW_MEASURE | FFTW_DESTROY_INPUT); /** init two dimensional infft plan */ SOLVER(init_advanced_complex)(&my_infft_plan, (NFFT(mv_plan_complex)*) (&my_nfft_plan), CGNR | PRECOMPUTE_WEIGHT); /** init nodes and weights of grid*/ gridfcn(T, S, x, w); for (j = 0; j < my_nfft_plan.M_total; j++) { my_nfft_plan.x[2 * j + 0] = x[2 * j + 0]; my_nfft_plan.x[2 * j + 1] = x[2 * j + 1]; if (j % S) my_infft_plan.w[j] = w[j]; else my_infft_plan.w[j] = NFFT_K(0.0); } /** precompute psi, the entries of the matrix B */ if (my_nfft_plan.flags & PRE_LIN_PSI) NFFT(precompute_lin_psi)(&my_nfft_plan); if (my_nfft_plan.flags & PRE_PSI) NFFT(precompute_psi)(&my_nfft_plan); if (my_nfft_plan.flags & PRE_FULL_PSI) NFFT(precompute_full_psi)(&my_nfft_plan); /** compute 1D-ffts and init given samples and weights */ for (t = 0; t < T; t++) { /* for(r=0; r #include #include #include #include #define @NFFT_PRECISION_MACRO@ #include "nfft3mp.h" /** define weights of kernel function for discrete Radon transform */ /*#define KERNEL(r) 1.0 */ #define KERNEL(r) (NFFT_K(1.0)-NFFT_M(fabs)((NFFT_R)(r))/((NFFT_R)S/2)) /** generates the points x with weights w * for the polar grid with T angles and R offsets */ static int polar_grid(int T, int S, NFFT_R *x, NFFT_R *w) { int t, r; NFFT_R W = (NFFT_R) T * (((NFFT_R) S / NFFT_K(2.0)) * ((NFFT_R) S / NFFT_K(2.0)) + NFFT_K(1.0) / NFFT_K(4.0)); for (t = -T / 2; t < T / 2; t++) { for (r = -S / 2; r < S / 2; r++) { x[2 * ((t + T / 2) * S + (r + S / 2)) + 0] = (NFFT_R) r / (NFFT_R)(S) * NFFT_M(cos)(NFFT_KPI * (NFFT_R)(t) / (NFFT_R)(T)); x[2 * ((t + T / 2) * S + (r + S / 2)) + 1] = (NFFT_R) r / (NFFT_R)(S) * NFFT_M(sin)(NFFT_KPI * (NFFT_R)(t) / (NFFT_R)(T)); if (r == 0) w[(t + T / 2) * S + (r + S / 2)] = NFFT_K(1.0) / NFFT_K(4.0) / W; else w[(t + T / 2) * S + (r + S / 2)] = NFFT_M(fabs)((NFFT_R) r) / W; } } return 0; } /** generates the points x with weights w * for the linogram grid with T slopes and R offsets */ static int linogram_grid(int T, int S, NFFT_R *x, NFFT_R *w) { int t, r; NFFT_R W = (NFFT_R) T * (((NFFT_R) S / NFFT_K(2.0)) * ((NFFT_R) S / NFFT_K(2.0)) + NFFT_K(1.0) / NFFT_K(4.0)); for (t = -T / 2; t < T / 2; t++) { for (r = -S / 2; r < S / 2; r++) { if (t < 0) { x[2 * ((t + T / 2) * S + (r + S / 2)) + 0] = (NFFT_R) r / (NFFT_R)(S); x[2 * ((t + T / 2) * S + (r + S / 2)) + 1] = NFFT_K(4.0) * ((NFFT_R)(t) + (NFFT_R)(T) / NFFT_K(4.0)) / (NFFT_R)(T) * (NFFT_R)(r) / (NFFT_R)(S); } else { x[2 * ((t + T / 2) * S + (r + S / 2)) + 0] = -NFFT_K(4.0) * ((NFFT_R)(t) - (NFFT_R)(T) / NFFT_K(4.0)) / (NFFT_R)(T) * (NFFT_R)(r) / (NFFT_R)(S); x[2 * ((t + T / 2) * S + (r + S / 2)) + 1] = (NFFT_R) r / (NFFT_R)(S); } if (r == 0) w[(t + T / 2) * S + (r + S / 2)] = NFFT_K(1.0) / NFFT_K(4.0) / W; else w[(t + T / 2) * S + (r + S / 2)] = NFFT_M(fabs)((NFFT_R) r) / W; } } return 0; } /** computes the NFFT-based discrete Radon transform of f * on the grid given by gridfcn() with T angles and R offsets */ static int Radon_trafo(int (*gridfcn)(), int T, int S, NFFT_R *f, int NN, NFFT_R *Rf) { int j, k; /**< index for nodes and freqencies */ NFFT(plan) my_nfft_plan; /**< plan for the nfft-2D */ NFFT_C *fft; /**< variable for the fftw-1Ds */ FFTW(plan) my_fftw_plan; /**< plan for the fftw-1Ds */ int t, r; /**< index for directions and offsets */ NFFT_R *x, *w; /**< knots and associated weights */ int N[2], n[2]; int M = T * S; N[0] = NN; n[0] = 2 * N[0]; N[1] = NN; n[1] = 2 * N[1]; fft = (NFFT_C *) NFFT(malloc)((size_t)(S) * sizeof(NFFT_C)); my_fftw_plan = FFTW(plan_dft_1d)(S, fft, fft, FFTW_BACKWARD, FFTW_MEASURE); x = (NFFT_R *) NFFT(malloc)((size_t)(2 * T * S) * (sizeof(NFFT_R))); if (x == NULL) return EXIT_FAILURE; w = (NFFT_R *) NFFT(malloc)((size_t)(T * S) * (sizeof(NFFT_R))); if (w == NULL) return EXIT_FAILURE; /** init two dimensional NFFT plan */ NFFT(init_guru)(&my_nfft_plan, 2, N, M, n, 4, PRE_PHI_HUT | PRE_PSI | MALLOC_X | MALLOC_F_HAT | MALLOC_F | FFTW_INIT | FFT_OUT_OF_PLACE, FFTW_MEASURE | FFTW_DESTROY_INPUT); /** init nodes from grid*/ gridfcn(T, S, x, w); for (j = 0; j < my_nfft_plan.M_total; j++) { my_nfft_plan.x[2 * j + 0] = x[2 * j + 0]; my_nfft_plan.x[2 * j + 1] = x[2 * j + 1]; } /** precompute psi, the entries of the matrix B */ if (my_nfft_plan.flags & PRE_LIN_PSI) NFFT(precompute_lin_psi)(&my_nfft_plan); if (my_nfft_plan.flags & PRE_PSI) NFFT(precompute_psi)(&my_nfft_plan); if (my_nfft_plan.flags & PRE_FULL_PSI) NFFT(precompute_full_psi)(&my_nfft_plan); /** init Fourier coefficients from given image */ for (k = 0; k < my_nfft_plan.N_total; k++) my_nfft_plan.f_hat[k] = f[k] + _Complex_I * NFFT_K(0.0); /** NFFT-2D */ NFFT(trafo)(&my_nfft_plan); /** FFTW-1Ds */ for (t = 0; t < T; t++) { fft[0] = NFFT_K(0.0); for (r = -S / 2 + 1; r < S / 2; r++) fft[r + S / 2] = KERNEL(r) * my_nfft_plan.f[t * S + (r + S / 2)]; NFFT(fftshift_complex_int)(fft, 1, &S); FFTW(execute)(my_fftw_plan); NFFT(fftshift_complex_int)(fft, 1, &S); for (r = 0; r < S; r++) Rf[t * S + r] = NFFT_M(creal)(fft[r]) / (NFFT_R)(S); /* for(r=0; r threshold); end temp = IWT_TI(TItable,qmf); Rf2d(:,k)=temp'; end %write result to file fp = fopen('sinogram_data.bin','wb+'); fwrite(fp,Rf2d,'double'); fclose(fp); %compute inverse Radon transform by C-program if ispc cmd='inverse_radon.exe'; else cmd='./inverse_radon'; end system(sprintf('%s %s %d %d %d %d',cmd,grid,N,T,R,it)); %read result fp = fopen('output_data.bin','rb+'); iRf2d = fread(fp,[N,N],'double')'; fclose(fp); figure(3); imagesc(iRf2d); colormap(gray); axis image title(sprintf('reconstructed image (SNR=%g)',20*log10( norm(f - mean(f(:)),'fro') / norm(f-iRf2d,'fro') ))); %end: ridgelet.m nfft-3.3.2/bootstrap.sh000077500000000000000000000032421300072027400150240ustar00rootroot00000000000000#!/bin/bash # # Copyright (c) 2003, 2006 Matteo Frigo # Copyright (c) 2003, 2006 Massachusetts Institute of Technology # Copyright (c) 2007 Jens Keiner # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., 51 # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ################################################################################ # NOTE: If you just want to build NFFT3, do not use this file. Just follow the # installation instructions as described in the tutorial found under # doc/tutorial. # # This file is based on the bootstrap.sh script from FFTW 3.1.2 by # M. Frigo and S. G. Johnson ################################################################################ # alias to allow for systems having glibtoolize alias libtoolize=$(type -p glibtoolize libtoolize | head -1) touch ChangeLog echo "PLEASE IGNORE WARNINGS AND ERRORS" # paranoia: sometimes autoconf doesn't get things right the first time rm -rf autom4te.cache libtoolize autoreconf --verbose --install --force autoreconf --verbose --install --force autoreconf --verbose --install --force rm -f config.cache nfft-3.3.2/configure.ac000066400000000000000000000600501300072027400147360ustar00rootroot00000000000000# Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., 51 # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ################################################################################ # Process this file with autoconf to produce a configure script. ################################################################################ m4_define([nfft_version_major], [3]) m4_define([nfft_version_minor], [3]) m4_define([nfft_version_patch], [2]) m4_define([nfft_version_type], [alpha]) m4_append([NFFT_VERSION], m4_expand([nfft_version_major.nfft_version_minor.nfft_version_patch])) m4_append([NFFT_VERSION], m4_expand([nfft_version_type])) ... # autoconf initialization AC_INIT([NFFT],[NFFT_VERSION],[mail@nfft.org]) # copyright notice AC_COPYRIGHT([2003, 2015, Jens Keiner, Stefan Kunis, Daniel Potts]) AC_DEFINE_UNQUOTED([NFFT_VERSION_MAJOR], [nfft_version_major], [Major version number.]) AC_DEFINE_UNQUOTED([NFFT_VERSION_MINOR], [nfft_version_minor], [Minor version number.]) AC_DEFINE_UNQUOTED([NFFT_VERSION_PATCH], [nfft_version_patch], [Patch version number.]) AC_DEFINE_UNQUOTED([NFFT_VERSION_TYPE], [nfft_version_type], [Release type.]) # m4 macros go here AC_CONFIG_MACRO_DIR([m4]) # where to put auxilliary files AC_CONFIG_AUX_DIR([config]) # how to recognize the source directory AC_CONFIG_SRCDIR([include/nfft3.h]) # header to create AC_CONFIG_HEADERS([include/config.h:include/config.h.in]) # canonical host system type string AC_CANONICAL_HOST # number of CPUs #AX_COUNT_CPUS #AC_DEFINE_UNQUOTED(NFFT_NUM_CORES,$cpu_count,[Define to number of cores.]) # substitute abs_srcdir in generated Makefiles. AC_SUBST([abs_srcdir]) if test "x${host_os}" = "xmingw32" -o "x${host_os}" = "xmingw64"; then AC_DEFINE_UNQUOTED([ABS_SRCDIR], ["`pwd -W`/$srcdir"], [Absolute path to source directory.]) else AC_DEFINE_UNQUOTED([ABS_SRCDIR], ["`pwd`/$srcdir"], [Absolute path to source directory.]) fi AC_SUBST([abs_top_srcdir]) AC_SUBST([top_builddir]) AC_SUBST([abs_top_builddir]) # minimum required libtool version LT_PREREQ([2.4.2]) # libtool initialization LT_INIT([win32-dll]) # substitute LIBTOOL_DEPS variable in generated Makefiles AC_SUBST([LIBTOOL_DEPS]) # version information for shared library SHARED_VERSION_INFO="2:0:0" # substitute SHARED_VERSION_INFO in generated Makefiles AC_SUBST(SHARED_VERSION_INFO) # check for make AC_PROG_MAKE_SET # automake initialization AM_INIT_AUTOMAKE(1.10) # doxygen ${PACKAGE_STRING} DX_DOT_FEATURE(ON) DX_HTML_FEATURE(ON) DX_CHM_FEATURE(OFF) DX_CHI_FEATURE(OFF) DX_MAN_FEATURE(OFF) DX_RTF_FEATURE(OFF) DX_XML_FEATURE(OFF) DX_PDF_FEATURE(OFF) DX_PS_FEATURE(OFF) DX_INIT_DOXYGEN([NFFT], [doxygen/doxygen.Doxyfile], [doc]) ################################################################################ # options for customizing the build process ################################################################################ # maintainer mode option AM_MAINTAINER_MODE # Precision. AC_ARG_ENABLE(single, [AS_HELP_STRING([--enable-single],[compile NFFT in single precision])], ok=$enableval, ok=no) AC_ARG_ENABLE(float, [AS_HELP_STRING([--enable-float],[synonym for --enable-single])], ok=$enableval) if test "$ok" = "yes"; then AC_DEFINE(NFFT_SINGLE,1,[Define to compile in single precision.]) PRECISION=s else PRECISION=d fi AC_ARG_ENABLE(long-double, [AS_HELP_STRING([--enable-long-double],[compile NFFT in long-double precision])], ok=$enableval, ok=no) if test "$ok" = "yes"; then if test "$PRECISION" = "s"; then AC_MSG_ERROR([--enable-single/--enable-long-double conflict]) fi AC_DEFINE(NFFT_LDOUBLE,1,[Define to compile in long-double precision.]) PRECISION=l fi AC_SUBST(PRECISION) # Library suffix case "$PRECISION" in s) PREC_SUFFIX=f;; d) PREC_SUFFIX=;; l) PREC_SUFFIX=l;; esac AC_SUBST(PREC_SUFFIX) # Library suffix case "$PRECISION" in s) NFFT_PRECISION_MACRO=NFFT_PRECISION_SINGLE;; d) NFFT_PRECISION_MACRO=NFFT_PRECISION_DOUBLE;; l) NFFT_PRECISION_MACRO=NFFT_PRECISION_LONG_DOUBLE;; esac AC_SUBST(NFFT_PRECISION_MACRO) AM_CONDITIONAL(HAVE_NON_DOUBLE_PRECISION, test "x$PRECISION" != "xd" ) # enable or disable parts of NFFT # whether we need the fpt module need_fpt="no" # build all modules by default in maintainer mode or if option is given AC_ARG_ENABLE(all, [AC_HELP_STRING([--enable-all],[build all modules])], ok=$enableval, ok=$USE_MAINTAINER_MODE) nfft_module_default=$ok # option for example programs nfft_examples_default="yes" AC_ARG_ENABLE(examples, [AC_HELP_STRING([--enable-examples], [enable example programs])], enable_examples=$enableval, enable_examples=$nfft_examples_default) AM_CONDITIONAL(HAVE_EXAMPLES, test "x$enable_examples" = "xyes" ) # option for application programs nfft_applications_default="yes" AC_ARG_ENABLE(applications, [AC_HELP_STRING([--enable-applications], [enable application programs])], enable_applications=$enableval, enable_applications=$nfft_applications_default) AM_CONDITIONAL(HAVE_APPLICATIONS, test "x$enable_applications" = "xyes" ) # options for modules AX_NFFT_MODULE([nfct],[NFCT],[nonequispaced fast cosine transform],["yes"]) AX_NFFT_MODULE([nfst],[NFST],[nonequispaced fast sine transform],["yes"]) AX_NFFT_MODULE([nfsft],[NFSFT],[nonequispaced fast spherical Fourier transform],["no"], [need_fpt="yes"]) AX_NFFT_MODULE([nfsoft],[NFSOFT],[nonequispaced fast SO(3) Fourier transform],["no"], [need_fpt="yes"]) AX_NFFT_MODULE([nnfft],[NNFFT],[nonequispaced fast Fourier transform -- ]# [nonequispaced in both domains],["no"]) AX_NFFT_MODULE([nsfft],[NSFFT],[nonequispaced sparse fast Fourier transform],["no"]) AX_NFFT_MODULE([mri],[MRI],[magnet resonance imaging],["no"]) AX_NFFT_MODULE([fpt],[FPT],[fast polynomial transform],["no"],[],[], [test "x$ok" = "xyes" -o "x$need_fpt" = "xyes"]) # multithreaded code #AC_ARG_ENABLE(openmp, [AC_HELP_STRING([--enable-openmp], # [enable OpenMP multithreaded code])], [enable_threads=$enableval; AC_DEFINE(ENABLE_OPENMP, 1, ["Define to enable OpenMP code."])], enable_threads=no) AC_ARG_ENABLE(openmp, [AC_HELP_STRING([--enable-openmp], [enable OpenMP multithreaded code])], enable_threads=$enableval, enable_threads=no) AM_CONDITIONAL(HAVE_THREADS, test "x$enable_threads" = "xyes" ) # debug mode AC_ARG_ENABLE(debug, [AC_HELP_STRING([--enable-debug], [compile with extra runtime checks for debugging])], enable_debug=$enableval, enable_debug=no) if test "x$enable_debug" = "xyes"; then AC_DEFINE(NFFT_DEBUG,1,[Define to enable extra debugging code.]) fi # runtime time measurements AC_ARG_ENABLE(measure-time, [AC_HELP_STRING([--enable-measure-time], [measure time during execution])], ok=$enableval, ok=no) if test "x$ok" = "xyes"; then AC_DEFINE(MEASURE_TIME,1,[Define to enable runtime time measurements.]) fi # runtime time measurements for FFTW part AC_ARG_ENABLE(measure-time-fftw, [AC_HELP_STRING([--enable-measure-time-fftw], [measure time of FFTW transforms during execution])], ok=$enableval, ok=no) if test "x$ok" = "xyes"; then AC_DEFINE(MEASURE_TIME_FFTW,1,[Define to enable time measurements for FFTW] [transforms.]) fi AC_ARG_ENABLE(mips_zbus_timer, [AC_HELP_STRING([--enable-mips-zbus-timer], [use MIPS ZBus cycle-counter])], have_mips_zbus_timer=$enableval, have_mips_zbus_timer=no) if test "$have_mips_zbus_timer" = "yes"; then AC_DEFINE(HAVE_MIPS_ZBUS_TIMER,1, [Define to enable use of MIPS ZBus cycle-counter.]) fi # select window function AC_ARG_WITH(window, [AC_HELP_STRING([--with-window=ARG],[choose window function (ARG can be one of: kaiserbessel (default), gaussian, bspline, sinc, dirac)])], window=$withval, window="kaiserbessel") AC_MSG_CHECKING([window function]) case "$window" in kaiserbessel) AC_DEFINE(KAISER_BESSEL,1,[Define to enable Kaiser-Bessel window function.]);; gaussian) AC_DEFINE(GAUSSIAN,1,[Define to enable Gaussian window function.]);; bspline) AC_DEFINE(B_SPLINE,1,[Define to enable B-spline window function.]);; sinc) AC_DEFINE(SINC_POWER,1,[Define to enable sinc power window function.]);; delta) AC_DEFINE(DIRAC_DELTA,1,[Define to enable Dirac delta window function.]);; *) AC_MSG_ERROR([Unknown window function "$window".]);; esac AC_MSG_RESULT([$window]) AC_ARG_ENABLE(exhaustive-unit-tests, [AS_HELP_STRING([--enable-exhaustive-unit-tests],[enable exhaustive unit tests])], ok=$enableval, ok=no) if test "$ok" = "yes"; then AC_DEFINE(NFFT_EXHAUSTIVE_UNIT_TESTS,1,[Define to enable exhaustive unit tests.]) fi ################################################################################ # compiler characteristis ################################################################################ # select programming language AC_LANG(C) # compiler vendor AX_COMPILER_VENDOR # check for C99 compliant mode (possibly with GNU extensions) AC_PROG_CC_C99 # per-target flags AM_PROG_CC_C_O # enable "const" keyword AC_C_CONST # enable "restrict" keyword AC_C_RESTRICT # enable "inline" keyword AC_C_INLINE # reset CC variable (the C99 option is added back below) CC="$ac_save_CC" ################################################################################ # program checks ################################################################################ # C preprocessor AC_PROG_CPP_WERROR # assembler AM_PROG_AS # BSD-compatible install AC_PROG_INSTALL # mkdir AC_PROG_MKDIR_P # whether ln -s works AC_PROG_LN_S ################################################################################ # 3rd party libraries ################################################################################ # Check for fftw3. AX_LIB_FFTW3 if test "x$ax_lib_fftw3" = "xno"; then AC_MSG_ERROR([You don't seem to have the FFTW 3 library installed. You can ]# [download it from http://www.fftw.org. If you have installed FFTW 3, ]# [make sure that this configure script can find it. See ./configure ]# [--help for more information.]) fi if test "x$enable_threads" = "xyes" -a "x$ax_lib_fftw3_threads" = "xno"; then AC_MSG_ERROR([You don't seem to have the threaded FFTW 3 library installed.]) fi AX_OPENMP AM_CONDITIONAL(HAVE_OPENMP, test "x$ax_cv_[]_AC_LANG_ABBREV[]_openmp" != "xunknown" ) AC_SUBST(OPENMP_CFLAGS) if test "x$enable_threads" = "xyes" -a "x$ax_cv_[]_AC_LANG_ABBREV[]_openmp" = "xunknown"; then AC_MSG_ERROR([You don't seem to have a C compiler with OpenMP support installed which is required for threaded NFFT.]) fi # Check for MATLAB. AX_PROG_MATLAB if test "x$ax_prog_matlab" = "xyes" -a "x$PRECISION" != "xd"; then AC_MSG_ERROR([Building the Matlab interfaces requires double precision.]) fi if test "x$matlab_threads" = "xyes" -a "x$enable_threads" != "xyes"; then AC_MSG_ERROR([The NFFT Matlab interface with thread support requires the threaded NFFT to be built. Please re-run configure with \"--enable-openmp\".]) fi ################################################################################ # compiler options ################################################################################ # Try to choose good compiler options. if test "x$ac_test_CFLAGS" != "xset"; then saved_CPPFLAGS="$CPPFLAGS" saved_LDFLAGS="$LDFLAGS" saved_LIBS="$LIBS" CPPFLAGS="$CPPFLAGS $fftw3_CPPFLAGS" LIBS="$LIBS $fftw3_LIBS" LDFLAGS="$LDFLAGS $fftw3_LDFLAGS" AX_CC_MAXOPT CPPFLAGS="$saved_CPPFLAGS" LDFLAGS="$saved_LDFLAGS" LIBS="$saved_LIBS" fi # override CFLAGS selection when debugging if test "x${enable_debug}" = "xyes"; then CFLAGS="-g" # if test "x$ax_cv_c_compiler_vendor" = "xapple"; then # CFLAGS="$CFLAGS $ax_cv_apple_gcc_archflag" # fi fi # add gcc warnings, in debug/maintainer mode only if test "x${enable_debug}" = "xyes" || test "x$USE_MAINTAINER_MODE" = "xyes"; then if test "x$ac_cv_c_compiler_gnu" = "xyes"; then CFLAGS="$CFLAGS -Wall -W -Wcast-qual -Wpointer-arith -Wcast-align -pedantic" CFLAGS="$CFLAGS -Wno-long-long -Wshadow -Wbad-function-cast -Wwrite-strings" CFLAGS="$CFLAGS -Wstrict-prototypes -Wredundant-decls -Wnested-externs" CFLAGS="$CFLAGS -Wundef -Wconversion -Wmissing-prototypes " CFLAGS="$CFLAGS -Wmissing-declarations" fi fi # option to accept C99 CFLAGS="$CFLAGS $ac_cv_prog_cc_c99" CPPFLAGS="$CPPFLAGS $fftw3_CPPFLAGS" # add Matlab CFLAGS if test "x$ax_prog_matlab" = "xyes"; then CFLAGS="$CFLAGS $matlab_CFLAGS" fi ################################################################################ # check if mex.h can be included without undefinition of ################################################################################ ax_prog_matlab_gcc_require_undef_stdc_utf_16=no if test "x$ax_prog_matlab" = "xyes"; then AC_MSG_CHECKING([if inclusion of mex.h succeeds]) saved_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $matlab_CPPFLAGS" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include "mex.h"]],[[]])],[ax_prog_matlab_check_compile_mex_h=yes], [ax_prog_matlab_check_compile_mex_h=no]) AC_MSG_RESULT([$ax_prog_matlab_check_compile_mex_h]) if test "x$ax_prog_matlab_check_compile_mex_h" = "xno"; then AC_MSG_CHECKING([if undefining __STDC_UTF_16__ solves this issue]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#undef __STDC_UTF_16__ #include "mex.h"]],[[]])],[ax_prog_matlab_gcc_require_undef_stdc_utf_16=yes], []) AC_MSG_RESULT([$ax_prog_matlab_gcc_require_undef_stdc_utf_16]) fi CPPFLAGS="$saved_CPPFLAGS" fi if test "x$ax_prog_matlab_gcc_require_undef_stdc_utf_16" = "xyes"; then AC_DEFINE([HAVE_MATLAB_GCC_REQUIRE_UNDEF_STDC_UTF_16],[1],[Define to 1 if compilation of Matlab interface only succeeds when macro __STDC_UTF_16__ not defined.]) fi ################################################################################ # header files/data types/compiler characteristics ################################################################################ AC_CHECK_HEADERS([math.h stdio.h stdlib.h time.h sys/time.h \ complex.h string.h float.h limits.h stdarg.h stddef.h sys/types.h stdint.h \ inttypes.h stdbool.h malloc.h c_asm.h intrinsics.h mach/mach_time.h]) AC_HEADER_TIME AC_TYPE_SIZE_T AC_CHECK_TYPE([long double], [AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define to 1 if the compiler supports] ['long double'])],[]) AC_CHECK_TYPE([hrtime_t],[AC_DEFINE(HAVE_HRTIME_T, 1, [Define to 1 if hrtime_t] [is defined in ])],, [ #if HAVE_SYS_TIME_H #include #endif ]) AC_CHECK_TYPES(uintptr_t, [], [AC_CHECK_SIZEOF(void *)], [$ac_includes_default #ifdef HAVE_STDINT_H # include #endif]) AC_CHECK_SIZEOF(int) AC_CHECK_SIZEOF(unsigned int) AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(unsigned long) AC_CHECK_SIZEOF(long long) AC_CHECK_SIZEOF(unsigned long long) AC_CHECK_SIZEOF(size_t) AC_CHECK_SIZEOF(ptrdiff_t) AC_CHECK_SIZEOF(float) AC_CHECK_SIZEOF(double) AC_CHECK_SIZEOF(long double) # library functions AC_FUNC_ALLOCA AC_FUNC_STRTOD AC_FUNC_VPRINTF saved_LIBS=$LIBS AC_CHECK_LIB(m, sin, []) LIBS=$saved_LIBS AC_CHECK_FUNCS([gethrtime read_real_time time_base_to_time clock_gettime mach_absolute_time]) AC_CHECK_FUNCS([memset posix_memalign memalign]) AC_CHECK_FUNCS([_mm_malloc _mm_free sysctl]) AC_CHECK_FUNCS([abort snprintf sqrt]) AC_CHECK_FUNCS([sleep usleep nanosleep drand48 srand48]) AC_CHECK_FUNCS([gethostname]) AC_CHECK_DECLS([memalign, posix_memalign]) AC_CHECK_DECLS([sleep],[],[],[#include ]) AC_CHECK_DECLS([nanosleep],[],[],[#include ]) AC_CHECK_DECLS([drand48],[],[],[#include ]) AC_CHECK_DECLS([srand48],[],[],[#include ]) # Cray UNICOS _rtc() (real-time clock) intrinsic AC_MSG_CHECKING([for _rtc intrinsic]) rtc_ok=yes AC_TRY_LINK([#ifdef HAVE_INTRINSICS_H #include #endif], [_rtc()], [AC_DEFINE(HAVE__RTC,1,[Define if you have the UNICOS _rtc() intrinsic.])], [rtc_ok=no]) AC_MSG_RESULT($rtc_ok) AC_MSG_CHECKING([whether a cycle counter is available]) save_CPPFLAGS=$CPPFLAGS CPPFLAGS="$CPPFLAGS -I$srcdir/include" AC_TRY_CPP([#include "cycle.h" #ifndef HAVE_TICK_COUNTER # error No cycle counter #endif], [ok=yes], [ok=no]) AC_MSG_RESULT($ok) TICKS_PER_SECOND=1 if test $ok = no; then echo "***************************************************************" echo "WARNING: No cycle counter found. Time measurements in NFFT will" echo " show incorrect results. " echo "***************************************************************" else AC_TRY_RUN([#include "cycle.h" #include #if defined(HAVE_NANOSLEEP) #include static struct timespec ts = {1,0}; #define SLEEP nanosleep(&ts, 0) #elif defined(HAVE_SLEEP) #include #define SLEEP sleep(1) #elif defined(HAVE_USLEEP) #include #define SLEEP usleep(1000) #else #error wtf! #endif int main(){ ticks t0 = getticks(); SLEEP;{ double tps = elapsed(getticks(),t0)/1.0; FILE *f = fopen("ticks.tmp","w"); fprintf(f,"%.1f\n",tps); fclose(f);} return 0;}],[read TICKS_PER_SECOND < ticks.tmp],[],[]) rm -f ticks.tmp if test "$TICKS_PER_SECOND" = "1"; then echo "***************************************************************" echo "WARNING: Number of ticks per second could not be determined. " echo " Time measurements in NFFT will be in arbitrary units " echo " instead of seconds. " echo "***************************************************************" fi fi CPPFLAGS=$save_CPPFLAGS AC_SUBST(TICKS_PER_SECOND) if test "$PRECISION" = "l"; then #AC_CHECK_FUNCS([copysignl nextafterl nanl ceill floorl nearbyintl rintl roundl lrintl lroundl llrintl llroundl truncl fmodl remainderl remquol fdiml fmaxl fminl fmal fabsl sqrtl cbrtl hypotl expl exp2l expm1l logl log2l log10l log1pl logbl ilogbl modfl frexpl ldexpl scalbnl scalblnl powl cosl sinl tanl coshl sinhl tanhl acosl asinl atanl atan2l acoshl asinhl atanhl tgammal lgammal j0l j1l jnl jnl y0l y1l ynl erfl erfcl creall cimagl cabsl cargl conjl cprojl csqrtl cexpl clogl cpowl csinl ccosl ctanl casinl cacosl catanl csinhl ccoshl ctanhl casinhl cacoshl catanhl]) AC_CHECK_DECLS([copysignl, nextafterl, nanl, ceill, floorl, nearbyintl, rintl, roundl, lrintl, lroundl, llrintl, llroundl, truncl, fmodl, remainderl, remquol, fdiml, fmaxl, fminl, fmal, fabsl, sqrtl, cbrtl, hypotl, expl, exp2l, expm1l, logl, log2l, log10l, log1pl, logbl, ilogbl, modfl, frexpl, ldexpl, scalbnl, scalblnl, powl, cosl, sinl, tanl, coshl, sinhl, tanhl, acosl, asinl, atanl, atan2l, acoshl, asinhl, atanhl, tgammal, lgammal, j0l, j1l, jnl, y0l, y1l, ynl, erfl, erfcl, creall, cimagl, cabsl, cargl, conjl, cprojl, csqrtl, cexpl, clogl, cpowl, csinl, ccosl, ctanl, casinl, cacosl, catanl, csinhl, ccoshl, ctanhl, casinhl, cacoshl, catanhl],[],[], [#include #include ]) fi if test "$PRECISION" = "d"; then #AC_CHECK_FUNCS([copysign nextafter nan ceil floor nearbyint rint round lrint lround llrint llround trunc fmod remainder remquo fdim fmax fmin fma fabs sqrt cbrt hypot exp exp2 expm1 log log2 log10 log1p logb ilogb modf frexp ldexp scalbn scalbln pow cos sin tan cosh sinh tanh acos asin atan atan2 acosh asinh atanh tgamma lgamma j0 j1 jn y0 y1 yn erf erfc creal cimag cabs carg conj cproj csqrt cexp clog cpow csin ccos ctan casin cacos catan csinh ccosh ctanh casinh cacosh catanh]) AC_CHECK_DECLS([copysign, nextafter, nan, ceil, floor, nearbyint, rint, round, lrint, lround, llrint, llround, trunc, fmod, remainder, remquo, fdim, fmax, fmin, fma, fabs, sqrt, cbrt, hypot, exp, exp2, expm1, log, log2, log10, log1p, logb, ilogb, modf, frexp, ldexp, scalbn, scalbln, pow, cos, sin, tan, cosh, sinh, tanh, acos, asin, atan, atan2, acosh, asinh, atanh, tgamma, lgamma, j0, j1, jn, y0, y1, yn, erf, erfc, creal, cimag, cabs, carg, conj, cproj, csqrt, cexp, clog, cpow, csin, ccos, ctan, casin, cacos, catan, csinh, ccosh, ctanh, casinh, cacosh, catanh],[],[], [#include #include ]) fi if test "$PRECISION" = "s"; then #AC_CHECK_FUNCS([copysignf nextafterf nanf ceilf floorf nearbyintf rintf roundf lrintf lroundf llrintf llroundf truncf fmodf remainderf remquof fdimf fmaxf fminf fmaf fabsf sqrtf cbrtf hypotf expf exp2f expm1f logf log2f log10f log1pf logbf ilogbf modff frexpf ldexpf scalbnf scalblnf powf cosf sinf tanf coshf sinhf tanhf acosf asinf atanf atan2f acoshf asinhf atanhf tgammaf lgammaf j0f j1f jnf y0f y1f ynf erff erfcf crealf cimagf cabsf cargf conjf cprojf csqrtf cexpf clogf cpowf csinf ccosf ctanf casinf cacosf catanf csinhf ccoshf ctanhf casinhf cacoshf catanhf]) AC_CHECK_DECLS([copysignf, nextafterf, nanf, ceilf, floorf, nearbyintf, rintf, roundf, lrintf, lroundf, llrintf, llroundf, truncf, fmodf, remainderf, remquof, fdimf, fmaxf, fminf, fmaf, fabsf, sqrtf, cbrtf, hypotf, expf, exp2f, expm1f, logf, log2f, log10f, log1pf, logbf, ilogbf, modff, frexpf, ldexpf, scalbnf, scalblnf, powf, cosf, sinf, tanf, coshf, sinhf, tanhf, acosf, asinf, atanf, atan2f, acoshf, asinhf, atanhf, tgammaf, lgammaf, j0f, j1f, jnf, y0f, y1f, ynf, erff, erfcf, crealf, cimagf, cabsf, cargf, conjf, cprojf, csqrtf, cexpf, clogf, cpowf, csinf, ccosf, ctanf, casinf, cacosf, catanf, csinhf, ccoshf, ctanhf, casinhf, cacoshf, catanhf],[],[], [#include #include ]) fi # CUnit AX_CUNIT AM_CONDITIONAL(HAVE_CUNIT, test "x$ax_cv_cunit" = "xyes" ) # The output files to be generated AC_CONFIG_FILES(Makefile \ nfft3.pc \ doxygen/doxygen.Doxyfile \ include/Makefile \ include/ticks.h \ 3rdparty/Makefile \ 3rdparty/cstripack/Makefile \ kernel/Makefile \ kernel/fpt/Makefile \ kernel/mri/Makefile \ kernel/nfct/Makefile \ kernel/nfft/Makefile \ kernel/nfsft/Makefile \ kernel/nfsoft/Makefile \ kernel/nfst/Makefile \ kernel/nnfft/Makefile \ kernel/nsfft/Makefile \ kernel/solver/Makefile \ kernel/util/Makefile \ tests/Makefile \ tests/data/Makefile \ examples/Makefile \ examples/fpt/Makefile \ examples/mri/Makefile \ examples/nfct/Makefile \ examples/nfct/simple_test.c \ examples/nfft/Makefile \ examples/nfft/simple_test.c \ examples/nfft/simple_test_threads.c \ examples/nfsft/Makefile \ examples/nfsoft/Makefile \ examples/nfst/Makefile \ examples/nfst/simple_test.c \ examples/nnfft/Makefile \ examples/nsfft/Makefile \ examples/solver/Makefile \ examples/solver/glacier.c \ examples/solver/simple_test.c \ applications/Makefile \ applications/fastgauss/Makefile \ applications/fastgauss/fastgauss.c \ applications/fastsum/Makefile \ applications/fastsumS2/Makefile \ applications/quadratureS2/Makefile \ applications/mri/Makefile \ applications/mri/mri2d/Makefile \ applications/mri/mri3d/Makefile \ applications/polarFFT/Makefile \ applications/polarFFT/linogram_fft_test.c \ applications/polarFFT/mpolar_fft_test.c \ applications/polarFFT/polar_fft_test.c \ applications/radon/Makefile \ applications/radon/inverse_radon.c \ applications/radon/radon.c \ applications/iterS2/Makefile \ matlab/Makefile \ matlab/nfsft/Makefile \ matlab/nfft/Makefile \ matlab/nnfft/Makefile \ matlab/nfsft/@f_hat/Makefile \ matlab/nfsoft/Makefile \ doxygen/Makefile \ support/Makefile) AC_OUTPUT nfft-3.3.2/doc/000077500000000000000000000000001300072027400132145ustar00rootroot00000000000000nfft-3.3.2/doc/assets/000077500000000000000000000000001300072027400145165ustar00rootroot00000000000000nfft-3.3.2/doc/assets/logo.png000066400000000000000000000056251300072027400161740ustar00rootroot00000000000000‰PNG  IHDR–.ýFÈgAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<PLTEÝÿÕÕÿËËbbbþ==XXXìììõõõÿ´´##!!!½½½ñññ&&&þ33´ttÿùùÑrrÏþQQååårrrþ@@þXX–gg‹‹‹ÙWW™™™UUUmmm¸XXüüüÍÍÍ)))vvvþ,,ŽŽŽåFF;;;þUUkkký€€ÚÚÚÿõõªªª¶¶¶þNN”””¥¥¥ÆÆÆþDDþ99111êãþGG­­­þ••þÆÆÍggg¹¹¹tttÔ555{{{ÿââÿêêIIINNNÿ êTTþ‡‡ýqqýjjúúúýccžžžý``þKKRRRíþŠŠØ___ò\\n<ÿ¾¾ßÿººþ  þåå"##AAAEEEÿ©©t||êãã㇇‡‚‰‰ùÿÿÚÚýwwÑÑѶ Uþ&&ýmmýrrþ[[gqqÿüüZZZþŽŽÿÿþVVhhhþššxxxøøøþLLÿ¬¬þHHýnneeeýttÿííþaaÿÝÝfmmý~~Wbb÷ÕÕÕ...ýY]]ý||þxxÿÑÑ~~~þæéþ\\ÚÑþ||þvvÿttþiiýhhôooüýss2 ÿƒƒƒˆˆˆ€€€………\\\qqqááá}}}pppýggþ^^ýzzý{{|||]]]ßßßý^^‚‚‚ÈÈÈÿððþËËËýddÿÿóó¢¢¢ýyyŒŒŒààà„„„ÿ¦¦þjjúSS|qq^[[úDDúooë||~ddjeeqVVùyy%!!ò<§¾³lMÜ=¨]·ÊÔÖªµläøWßœìs2Oz­Ce댔¥™Úêß»…ßò׋ }Oæm Ûýjï #½e¹&¶&âà eMˆó¤ÿï­¦ÿ%kYw¸>l‰Ž69ÖlebËo;ž0pYK[æHmmXÖ@’5aYS›É¸?Ø*n¾”Àa†×Uno33z)aè2%ÃFeEàV–]$ÉnbYÛ³¶5§y—K-ÑÜ=~V3š0÷µ;8_?Bº2%BfOÙƒlJ¶€­Õ -\Εs÷ø–sìè°;2åIÒ, PbYI6â –)øm.?·žaÿ~ößY‡¹‚åß=âL$åsWbYI6A†dSÎSü¶Ä¾®,…¸áºÍ(ªÝƆn÷DŒ%åËlDªÆ1$YÈÜl-uõep=Z†[ÆóÚi=s~{»ŠÁS5„n¦ÌS…ð'ÙŠÂ2϶ü  7X± g_W'¬ÙˆÆ¦½óeƒJéEH×Q„d²M¤ŠW!YQ„¿€­rç@çâ\_Ô „[×"44ìR–"bÅG`Ùy’ì"R•FD8ðۊޘİYLÅ£fà!¸Õ ‘¤á»¬YJ'k¦ËÜI²`))~[“BJÂhJœ¯Pâ0ÔÜŠ4»“˜°{>ŸŠ¸`™Åø³n´Æ²É$ÙM,³°•ÂÖbè+At^ç®/aÃo¼»ëKžg£92˜@ëT$;¥²”]……¡Â²öɶüÂä !» WBPÇ]CCCmåòQ¯3¶Úé¿öS&´§¦ÂjÊö`4yyvvyf*ƒ,ˆÐš¼¼¶Â¼må¶äôEßcÛr¹˜­ø:ú¬¬¸/~ÕDðñÑÅÄ&ÛqñˆM×Áj –V1;3<’ccb`ûˆ˜Éo+ºàr\Ž­­aJ˜‹Ã59ÝvtôŽg$ñu,;mž’Òªô˜tOd¤F£©R(´8$£@â“ËÀ(5 ©V"©‚CÒ]ªÑÅ&ÓÞ;)~[ÿÐY ¼CCå]t×Ê;¿ .ër]]³uù"[uk9¶,H…GÚq‡µZÚŒ‘X©è¨B£‰ôI°5‡É—Ÿ¿™ûÁ¡_5œrP§r>Éìd‚JÒ¯ƒ±±¶ ±#èhÆ}_zÏBï“òAÅ ©$°^;¤Pü¶`>ê–¢ûUên]ýQ»{ L–VaÉ«‚L c Èt3ùm­Âó¡ßƒF]±Ïç(jnÛT㹟¶Àxt7B¾NKY즙 SQü¶ð|\.Àûú"lÅÖp\¢f T¼váHñбü]ùÈ™»€­xŽ ´±{ãù³¢Qóî lKã@H7DÓ)H—‡HRÅ3¶`ø†Á"ëì!,t;âõÒÅ.?þð´*{~[ÆŠ7¾´Šém‹ÆÿÂu â3I¶Á–’$3V|2Åo˲â $¡±¬PÔ¸?loÂ2ÈL¼W[îdf¶Šñ|äs¾wë»õú½¾MÛ}¨xi±âµ †…‘ý¤ŠgTÚ`[G°­0î7šœžÊžžÊÊ•+kvÒè÷`³I$餚ÉP0ù D:+›×ްu¯§§¦F_S³ò7ðælSÖ¨Õj‰šÎXDš…ÉjL ñQ‚eüëUDu-ß;ŽågnÀêî8.³mªñƒêIùêÁ–Œ¸0@»‰ßÖž}{Yö‰M"ì5aØ"V¼ä#V¼'Èøß¡DÔOãË»L"i㹈ææÆ Öž&¤ëé†+>ËÜøÝ‹¨OEˆG¦‘®å"Õø9:RÅgƒ,’ôíľ Üï°õ(…MœrÜ,47…cëA5~Pi`ˆGÁEiøÝ‹¶.La™ú»ù·øóÀñݯò÷'¹MšŠ8 6 å~|ǦŠÖ‚­ ¤|¸0Š@&ðAJôQøA†ð…Næ±ïPÈÀoó«³ÏQvÉ~œNMú(â¥[¶¦…#FYÄ–üˆcákþF®“wI7,Ó>Št¨±Ìm‡€­O#¾· NñÁ6 ©Bʰ‘øYAб&^~@æ#àþ?±hZV·•¹yIEND®B`‚nfft-3.3.2/doxygen.dox000066400000000000000000000073271300072027400146510ustar00rootroot00000000000000/* * Copyright (c) 2002, 2016 Jens Keiner, Stefan Kunis, Daniel Potts * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \mainpage notitle * * \section introduction Introduction * * \cite{nfft3} Fast Fourier transforms (FFTs) belong \cite{nfft3_2} to the '10 algorithms with the * greatest influence on the development and practice of science and * engineering \cite{nfft3} in the 20th century'. * The classic algorithm computes the discrete Fourier transform * \f[ * f_j= \sum_{k=-\frac{N}{2}}^{\frac{N}{2}-1} \hat{f}_{k} * {\rm e}^{2\pi{\rm i}\frac{kj}{N}} * \f] * for \f$j=-\frac{N}{2},\hdots,\frac{N}{2}-1\f$ and given complex * coefficients \f$\hat{f}_{k}\in\mathbb{C}\f$. * Using a divide and conquer approach, the number of floating point * operations is reduced from \f${\cal O}(N^2)\f$ for a straightforward * computation to only \f${\cal O}(N\log N)\f$. * In conjunction with publicly available efficient implementations the fast * Fourier transform has become of great importance in scientific computing. * * However, two shortcomings of traditional schemes are the need for * equispaced sampling and the restriction to the system of complex * exponential functions. * The NFFT is a C subroutine library for computing the nonequispaced discrete * Fourier transform (NDFT) and its generalisations in one or more dimensions, * of arbitrary input size, and of complex data. * * More precisely,we collect the possible frequencies * \f$\mathbf{k}\in\mathbb{Z}^d\f$ in the multi-index set * \f[ * I_{\mathbf{N}} := \left\{ \mathbf{k}=\left(k_t\right)_{t=0,\hdots,d-1} * \in \mathbb{Z}^d: - * \frac{N_t}{2} \le k_t < \frac{N_t}{2} ,\;t=0,\hdots,d-1\right\}, * \f] * where \f$\mathbf{N}=\left(N_t\right)_{t=0,\hdots,d-1}\f$ is the * multibandlimit, i.e., \f$N_t\in 2\mathbb{N}\f$. * For a finite number of given Fourier coefficients * \f$\hat f_{\mathbf{k}} \in \mathbb{C}\f$, * \f$\mathbf{k}\in I_{\mathbf{N}}\f$, we consider the * fast evaluation of the trigonometric polynomial * \f[ * f\left(\mathbf{x}\right) * := \sum_{ \mathbf{k}\in I_{ N}} \hat{f}_{\mathbf{ k}} * {\rm e}^{-2\pi{\rm i}\mathbf{k}\mathbf{ x}} * \f] * at given nonequispaced nodes \f$\mathbf{x}_j \in \mathbb{T}^d\f$, * \f$j=0,\ldots, M-1\f$, from the * \f$ d\f$-dimensional torus as well as the * adjoint problem, the fast evaluation of sums of the form * \f[ * \hat h_{\mathbf{k}} := \sum_{j=0}^{M-1} {f}_{j} * {\rm e}^{2\pi{\rm i}\mathbf{k}\mathbf{ x}_j}. * \f] * * \subsection generalisations Generalisations * * The generalisations of the NFFT include * - NNFFT - nonequispaced in time and frequency fast Fourier transform, * - NFCT/NFST - nonequispaced fast (co)sine transform, * - NSFFT - nonequispaced sparse fast Fourier transform, * - FPT - fast polynomial transform, * - NFSFT - nonequispaced fast spherical Fourier transform. * * Furthermore, we consider the inversion of the above transforms by * iterative methods. * * \section faq FAQ - Frequently Asked Questions * * * see https://www.tu-chemnitz.de/~potts/nfft/faq.php * */ nfft-3.3.2/doxygen/000077500000000000000000000000001300072027400141245ustar00rootroot00000000000000nfft-3.3.2/doxygen/Makefile.am000066400000000000000000000001251300072027400161560ustar00rootroot00000000000000EXTRA_DIST = doxygen.css doxygen.Doxyfile doxygen.Doxyfile.in footer.html header.htmlnfft-3.3.2/doxygen/doxygen.Doxyfile.in000066400000000000000000003057331300072027400177260ustar00rootroot00000000000000# Doxyfile 1.8.7 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv # built into libc) for the transcoding. See http://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = @PACKAGE_NAME@ # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = @PACKAGE_VERSION@ # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify an logo or icon that is included in # the documentation. The maximum height of the logo should not exceed 55 pixels # and the maximum width should not exceed 200 pixels. Doxygen will copy the logo # to the output directory. PROJECT_LOGO = @abs_top_srcdir@/doc/assets/logo.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = @abs_top_builddir@/doc # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = NO # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, # Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), # Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, # Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, # Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, # Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, # Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = NO # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a # new page for each member. If set to NO, the documentation of a member will be # part of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 2 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:\n" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: # FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: # Fortran. In the later case the parser tries to guess whether the code is fixed # or free formatted code, this is the default for Fortran type files), VHDL. For # instance to make doxygen treat .inc files as Fortran files (default is PHP), # and .f files as C (default is Fortran), use: inc=Fortran f=C. # # Note For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by by putting a % sign in front of the word # or globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined # locally in source files will be included in the documentation. If set to NO # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = YES # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO these classes will be included in the various overviews. This option has # no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # (class|struct|union) declarations. If set to NO these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = YES # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = NO # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = YES # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the # todo list. This list is created by putting \todo commands in the # documentation. # The default value is: YES. GENERATE_TODOLIST = NO # The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the # test list. This list is created by putting \test commands in the # documentation. # The default value is: YES. GENERATE_TESTLIST = NO # The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = NO # The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= NO # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES the list # will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. Do not use file names with spaces, bibtex cannot handle them. See # also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters # in a documented function, or documenting parameters that don't exist or using # markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO doxygen will only warn about wrong or incomplete parameter # documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. # Note: If this tag is empty the current directory is searched. INPUT = @abs_top_srcdir@/doxygen.dox \ @abs_top_srcdir@/include \ @abs_top_srcdir@/kernel \ @abs_top_srcdir@/examples \ @abs_top_srcdir@/applications # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: http://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank the # following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, # *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, # *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, # *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, # *.qsf, *.as and *.js. FILE_PATTERNS = *.h \ *.c \ *.dox # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = @abs_top_srcdir@/3rdparty \ @abs_top_srcdir@/applications/texture # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = @abs_top_srcdir@/doc/assets # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = @abs_top_srcdir@/doc/assets # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER ) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES, then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see http://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the config file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = #../doxygen/header.html # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = #../doxygen/footer.html # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- # defined cascading style sheet that is included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefor more robust against future updates. # Doxygen will copy the style sheet file to the output directory. For an example # see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = #../doxygen/doxygen.css # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the stylesheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to NO can help when comparing the output of multiple runs. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: http://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler ( hhc.exe). If non-empty # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated ( # YES) or that it should be included in the master .chm file ( NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated ( # YES) or a normal table of contents ( NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering # instead of using prerendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from http://www.mathjax.org before deployment. # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /