GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/unrrdu/fft.c Lines: 21 84 25.0 %
Date: 2017-05-26 Branches: 3 44 6.8 %

Line Branch Exec Source
1
/*
2
  Teem: Tools to process and visualize scientific data and images             .
3
  Copyright (C) 2013, 2012, 2011, 2010, 2009  University of Chicago
4
  Copyright (C) 2008, 2007, 2006, 2005  Gordon Kindlmann
5
  Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998  University of Utah
6
7
  This library is free software; you can redistribute it and/or
8
  modify it under the terms of the GNU Lesser General Public License
9
  (LGPL) as published by the Free Software Foundation; either
10
  version 2.1 of the License, or (at your option) any later version.
11
  The terms of redistributing and/or modifying this software also
12
  include exceptions to the LGPL that facilitate static linking.
13
14
  This library is distributed in the hope that it will be useful,
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
  Lesser General Public License for more details.
18
19
  You should have received a copy of the GNU Lesser General Public License
20
  along with this library; if not, write to Free Software Foundation, Inc.,
21
  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
*/
23
24
#include "unrrdu.h"
25
#include "privateUnrrdu.h"
26
27
#define INFO "Fast Fourier Transform of selected axes"
28
static const char *_unrrdu_fftInfoL_yes =
29
  (INFO
30
   ". Initial attempt at wrapping the FFTW3 library; options are "
31
   "likely to change in Teem 2.0.\n "
32
   "* Uses nrrdFFT");
33
34
static const char *_unrrdu_fftInfoL_no =
35
  (INFO
36
   ". This Teem has NOT been compiled with FFTW3 <http://www.fftw.org/>. "
37
   "If it had been, "
38
   "this would be a command-line interface to that functionality. "
39
   "There is currently no non-FFTW implementation of the FFT available.\n "
40
   "* Uses nrrdFFT");
41
42
/* We create an airEnum to parse the "forward" and "backwards" values
43
   needed to specify which kind of transform to run */
44
45
static const char *
46
_directionStr[] = {
47
  "(unknown direction)",
48
  "forward",
49
  "backward"
50
};
51
52
static const char *
53
_directionDesc[] = {
54
  "unknown direction",
55
  "forward transform",
56
  "backward (inverse) transform"
57
};
58
59
/*  from fftw3.h
60
#define FFTW_FORWARD (-1)
61
#define FFTW_BACKWARD (+1)
62
*/
63
64
#define FORW (-1)
65
#define BACK (+1)
66
67
static const int
68
_directionVal[] = {
69
  0,
70
  FORW,
71
  BACK
72
};
73
74
static const char *
75
_directionStrEqv[] = {
76
  "f", "forw", "forward",
77
  "b", "back", "backward", "i", "inv", "inverse",
78
  ""
79
};
80
81
static const int
82
_directionValEqv[] = {
83
  FORW, FORW, FORW,
84
  BACK, BACK, BACK, BACK, BACK, BACK
85
};
86
87
static const airEnum
88
_direction_enm = {
89
  "direction",
90
  2,
91
  _directionStr,
92
  _directionVal,
93
  _directionDesc,
94
  _directionStrEqv,
95
  _directionValEqv,
96
  AIR_FALSE
97
};
98
99
static const airEnum *const
100
direction_enm = &_direction_enm;
101
102
int
103
unrrdu_fftMain(int argc, const char **argv, const char *me,
104
               hestParm *hparm) {
105
2
  hestOpt *opt = NULL;
106
1
  char *out, *err;
107
1
  Nrrd *nin, *_nin, *nout;
108
  int pret;
109
  airArray *mop;
110
111
1
  int sign, rigor, rescale, realInput;
112
1
  char *wispath;
113
  FILE *fwise;
114
1
  unsigned int *axes, axesLen;
115
116
1
  hestOptAdd(&opt, NULL, "dir", airTypeEnum, 1, 1, &sign, NULL,
117
             "forward (\"forw\", \"f\") or backward/inverse "
118
             "(\"back\", \"b\") transform ", NULL, direction_enm);
119
1
  hestOptAdd(&opt, "a,axes", "ax0", airTypeUInt, 1, -1, &axes, NULL,
120
             "the one or more axes that should be transformed", &axesLen);
121
1
  hestOptAdd(&opt, "pr,planrigor", "pr", airTypeEnum, 1, 1, &rigor, "est",
122
             "rigor with which fftw plan is constructed. Options include:\n "
123
             "\b\bo \"e\", \"est\", \"estimate\": only an estimate\n "
124
             "\b\bo \"m\", \"meas\", \"measure\": standard amount of "
125
             "measurements of system properties\n "
126
             "\b\bo \"p\", \"pat\", \"patient\": slower, more measurements\n "
127
             "\b\bo \"x\", \"ex\", \"exhaustive\": slowest, most measurements",
128
1
             NULL, nrrdFFTWPlanRigor);
129
1
  hestOptAdd(&opt, "r,rescale", "bool", airTypeBool, 1, 1, &rescale, "true",
130
             "scale fftw output (by sqrt(1/N)) so that forward and backward "
131
             "transforms will get back to original values");
132
1
  hestOptAdd(&opt, "w,wisdom", "filename", airTypeString, 1, 1, &wispath, "",
133
             "A filename here is used to read in fftw wisdom (if the file "
134
             "exists already), and is used to save out updated wisdom "
135
             "after the transform.  By default (not using this option), "
136
             "no wisdom is read or saved. Note: no wisdom is gained "
137
             "(that is, learned by FFTW) with planning rigor \"estimate\".");
138
1
  OPT_ADD_NIN(_nin, "input nrrd");
139
1
  hestOptAdd(&opt, "ri,realinput", NULL, airTypeInt, 0, 0, &realInput, NULL,
140
             "input is real-valued, so insert new length-2 axis 0 "
141
             "and set complex component to 0.0.  Axes to transform "
142
             "(indicated by \"-a\") will be incremented accordingly.");
143
1
  OPT_ADD_NOUT(out, "output nrrd");
144
145
1
  mop = airMopNew();
146
1
  airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways);
147
148

2
  if (nrrdFFTWEnabled) {
149
1
    USAGE(_unrrdu_fftInfoL_yes);
150
  } else {
151
2
    USAGE(_unrrdu_fftInfoL_no);
152
  }
153
  PARSE();
154
  airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways);
155
156
  nout = nrrdNew();
157
  airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways);
158
159
  if (realInput) {
160
    ptrdiff_t minPad[NRRD_DIM_MAX], maxPad[NRRD_DIM_MAX];
161
    unsigned int axi;
162
    Nrrd *ntmp;
163
    ntmp = nrrdNew();
164
    airMopAdd(mop, ntmp, (airMopper)nrrdNuke, airMopAlways);
165
    if (nrrdAxesInsert(ntmp, _nin, 0)) {
166
      airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
167
      fprintf(stderr, "%s: error creating complex axis:\n%s", me, err);
168
      airMopError(mop);
169
      return 1;
170
    }
171
    nin = nrrdNew();
172
    airMopAdd(mop, nin, (airMopper)nrrdNuke, airMopAlways);
173
    minPad[0] = 0;
174
    maxPad[0] = 1;
175
    for (axi=1; axi<ntmp->dim; axi++) {
176
      minPad[axi] = 0;
177
      maxPad[axi] = AIR_CAST(ptrdiff_t, ntmp->axis[axi].size-1);
178
    }
179
    if (nrrdPad_nva(nin, ntmp, minPad, maxPad, nrrdBoundaryPad, 0.0)) {
180
      airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
181
      fprintf(stderr, "%s: error padding out complex axis:\n%s", me, err);
182
      airMopError(mop);
183
      return 1;
184
    }
185
    /* increment specified axes to transform */
186
    for (axi=0; axi<axesLen; axi++) {
187
      axes[axi]++;
188
    }
189
    /* ntmp is really done with, we can free up the space now; this
190
       is one of the rare times we want airMopSub */
191
    airMopSub(mop, ntmp, (airMopper)nrrdNuke);
192
    nrrdNuke(ntmp);
193
  } else {
194
    /* input is apparently already complex */
195
    nin = _nin;
196
  }
197
198
  if (airStrlen(wispath) && nrrdFFTWEnabled) {
199
    fwise = fopen(wispath, "r");
200
    if (fwise) {
201
      if (nrrdFFTWWisdomRead(fwise)) {
202
        airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
203
        fprintf(stderr, "%s: error with fft wisdom:\n%s", me, err);
204
        airMopError(mop);
205
        return 1;
206
      }
207
      fclose(fwise);
208
    } else {
209
      fprintf(stderr, "%s: (\"%s\" couldn't be opened, will try to save "
210
              "wisdom afterwards)", me, wispath);
211
    }
212
  }
213
214
  if (nrrdFFT(nout, nin, axes, axesLen, sign, rescale, rigor)) {
215
    airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
216
    fprintf(stderr, "%s: error with fft:\n%s", me, err);
217
    airMopError(mop);
218
    return 1;
219
  }
220
221
  if (airStrlen(wispath) && nrrdFFTWEnabled) {
222
    if (!(fwise = fopen(wispath, "w"))) {
223
      fprintf(stderr, "%s: couldn't open %s for writing: %s\n",
224
              me, wispath, strerror(errno));
225
      airMopError(mop);
226
      return 1;
227
    }
228
    if (nrrdFFTWWisdomWrite(fwise)) {
229
      airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
230
      fprintf(stderr, "%s: error with fft wisdom:\n%s", me, err);
231
      airMopError(mop);
232
      return 1;
233
    }
234
    fclose(fwise);
235
  }
236
237
  SAVE(out, nout, NULL);
238
239
  airMopOkay(mop);
240
  return 0;
241
1
}
242
243
UNRRDU_CMD(fft, INFO);