Diana Software
QRealComplexFFTW3.cc
Go to the documentation of this file.
1 #include "QRealComplexFFTW3.hh"
2 #include <stdio.h>
3 #include <iostream>
4 #include "QVectorC.hh"
5 
6 ClassImp(Diana::QRealComplexFFTW3);
7 
9 
10 using namespace std;
12  : QFFT(), // <Call the empty ctor, do our own allocations
13  fStride(1) // We are only doing 1 dim transforms so stride=1
14 {
15 #ifdef _HAVE_FFTW3_
16  fSizeLock=false;
18  fNormalized = false;
19  // But leave the plans null for now (they will be created when needed)
20  fFFTW_Forward_Plan=NULL;
21  fFFTW_Backward_Plan=NULL;
22  fWindow = NULL;
24  fSize = 0;
25  fAllocatedSize = 0;
26  Resize(size);
27 #else
28  throw QError(QERR_UNKNOWN_ERR,__FILE__,__LINE__,
29  "Package mathtools not compiled with FFTW3 support!");
30 #endif
31 }
33  : QFFT(),
34  fStride(1)
35 {
36 #ifdef _HAVE_FFTW3_
37  fSizeLock=false;
38  fFFTW_Forward_Plan=NULL;
39  fFFTW_Backward_Plan=NULL;
40  fData = 0;
41  fComplexData=0;
42  fSize = 0;
43  fAllocatedSize = 0;
44  fWindow = NULL;
46 #else
47  throw QError(QERR_UNKNOWN_ERR,__FILE__,__LINE__,
48  "Package mathtools not compiled with FFTW3 support!");
49 #endif
50 }
51 
53  ClearCache();
54 }
55 
56 int QRealComplexFFTW3::TransformToFreq(const QVector& origData, QVectorC& FT,
57  bool compress){
58 #ifdef _HAVE_FFTW3_
59  if(!Resize(origData.Size()))
60  return -1;
61  if(compress)
62  FT.Resize(fSize/2+1);
63  else
64  FT.Resize(fSize);
65 
66  SetForward(true);
67 
68  // re adjust the window if not appropriate
70 
71  if(fFFTW_Forward_Plan==NULL)
72  if(!CreatePlan(true))
73  return -1;
74 
75  // If we are windowing
76  if(fWindow){
77  for(size_t i=0;i<fSize;i++)
78  fData[i]=origData[i]*fWindow[i];
79  }
80  else{
81  for(size_t i=0;i<fSize;i++)
82  fData[i]=origData[i];
83  }
84 
85  // Execute the plan
86  fftw_execute(fFFTW_Forward_Plan);
87 
88  // Now we have done the FFT, we should move the data back if needed
89  QVector &Re=FT.Re();
90  QVector &Im=FT.Im();
91  // Do the lower half
92  for(size_t i=0;i<fSize/2+1;i++){
93  Re[i]=fComplexData[i][0];
94  Im[i]=fComplexData[i][1];
95  }
96  if(!compress){
97  // Now we should fill out the complex conjugates
98  for(size_t i=0;i<fSize/2-1;i++){
99  Re[fSize/2+i+1]=Re[fSize/2-i-1];
100  Im[fSize/2+i+1]=-Im[fSize/2-i-1];
101  }
102  }
103 #else
104  throw QError(QERR_UNKNOWN_ERR,__FILE__,__LINE__,
105  "Package mathtools not compiled with FFTW3 support!");
106 #endif
107  return 0;
108 }
109 
110 int QRealComplexFFTW3::TransformFromFreq(const QVectorC& origFT, QVector& data,
111  bool compress){
112 #ifdef _HAVE_FFTW3_
113  int ret;
114  if(compress)
115  ret = Resize(2*(origFT.Size()-1));
116  else
117  ret = Resize(origFT.Size());
118 
119  if(!ret)
120  return -1;
121 
122  data.Resize(fSize);
123 
124  SetForward(false);
125 
126  // re adjust the window if not appropriate
128 
129  // Make sure a plan is in place
130  if(fFFTW_Backward_Plan==NULL)
131  if(!CreatePlan(false))
132  return -1;
133 
134  // Backward transforms
135  // Copy the data from the source
136  // Ignore all of the data in the second half of the vector.
137  const QVector &Re=origFT.Re();
138  const QVector &Im=origFT.Im();
139  for(size_t i=0;i<fSize/2+1;i++){
140  fComplexData[i][0]=Re[i];
141  fComplexData[i][1]=Im[i];
142  }
143  // Execute the plan
144  fftw_execute(fFFTW_Backward_Plan);
145 
146  if(fWindow){
147  for(size_t i=0;i<fSize;i++)
148  data[i]=fData[i]/fWindow[i];
149  }
150  else{
151  for(size_t i=0;i<fSize;i++)
152  data[i]=fData[i];
153  }
154  data/=fSize;
155 #else
156  throw QError(QERR_UNKNOWN_ERR,__FILE__,__LINE__,
157  "Package mathtools not compiled with FFTW3 support!");
158 #endif
159  return 0;
160 }
161 
162 int QRealComplexFFTW3::Transform(const QVector& origData, QVector& result){
163  return 0;
164 }
165 bool QRealComplexFFTW3::CreatePlan(bool IsForward){
166 #ifdef _HAVE_FFTW3_
167  if(IsForward){
168  fFFTW_Forward_Plan=fftw_plan_dft_r2c_1d(fSize,fData,fComplexData,
169  FFTW_MEASURE);
170  if(fFFTW_Forward_Plan==NULL)
171  return false;
172  }
173  else {
174  fFFTW_Backward_Plan=fftw_plan_dft_c2r_1d(fSize,fComplexData,fData,
175  FFTW_MEASURE);
176  if(fFFTW_Backward_Plan==NULL)
177  return false;
178  }
179 #endif
180  return true;
181 }
182 /***********************************************************************
183  This code requires FFTW >3.3.4 to work. Currently, by default it
184  will return false.
185 bool QRealComplexFFTW3::CheckPlanCompatible(const QVector& data,
186  const QVector& result) const {
187 
188  // Check if we can execute plan without moving data
189  bool externMem=true;
190 
191  double *real=(fDirection==kForward ? data.fData : result.fData);
192  double *comp=(fDirection==kForward ? result.fData : data.fData);
193 
194  // We cant be windowing
195  externMem &= !fWindow;
196  // The strides must be the same (this is trivially true here).
197  externMem &= (data.fStride==fStride && result.fStride==fStride);
198  // The alignments must be the same
199  externMem &=
200  (fftw_alignment_of(real) == fftw_alignment_of(fData));
201  externMem &=
202  (fftw_alignment_of(comp) == fftw_alignment_of(fComplexData));
203 
204  return externMem;
205 }
206 ************************************************************************/
207 bool QRealComplexFFTW3::Resize(size_t size){
208 #ifdef _HAVE_FFTW3_
209  if(fSize==size) return true;
210  else if(fSizeLock) return false;
211  else if(size < fAllocatedSize){
212  // Clear the cache, but leave the memory
213  ClearCache(false);
214  // Set a new size
215  fSize = size;
216  }
217  else {
218  // Clear the cache and the allocated memory
219  ClearCache(true);
220  // Set a new size
221  fSize=size;
222  // Set the new allocate size
223  fAllocatedSize=size;
224  // Allocate the memory for the real data
225  fData = QVector::ArrayAlloc(size);
226  // Allocate the memory for the complex data. Since this is a real
227  // FFT, the resulting array only needs to hold half of the complex
228  // values, but the data are not 'packed', and so we require only n+1
229  // (n is odd) or n+2 (n is even) double elements. (Or n/2+1 complex
230  // elements)
231  fComplexData=
232  (fftw_complex *)QVector::ArrayAlloc(size+((size % 2) ? 1 : 2));
233 
234  }
235 #endif
236  return true;
237 }
238 bool QRealComplexFFTW3::ClearCache(bool clearMem){
239 #ifdef _HAVE_FFTW3_
240  // Delete the allocated memory but don't delete the FFTW3
241  // wisdom. (But dont save it either.)
242  if(clearMem && fData){
244  QVector::ArrayFree((double *)fComplexData);
245  fData=NULL;
246  fComplexData=NULL;
247  }
248  if(fFFTW_Forward_Plan){
249  fftw_destroy_plan(fFFTW_Forward_Plan);
250  fFFTW_Forward_Plan=NULL;
251  }
252  if(fFFTW_Backward_Plan){
253  fftw_destroy_plan(fFFTW_Backward_Plan);
254  fFFTW_Backward_Plan=NULL;
255  }
256 #endif
257  return true;
258 }
260 #ifdef _HAVE_FFTW3_
261  if(w != fWindowType || fWindowSize != fSize){
262  QVector tmp = GetWindow(w,fSize,0,coherent);
263  size_t wsize = tmp.Size();
264  if(wsize > 0 ) {
265  fWindow = tmp.GetArray();
266  fWindowSize = fSize;
267  } else {
268  fWindow = NULL;
269  fWindowSize = 0;
270  }
271  fWindowType = w;
272  }
273 #endif
274 }
275 
276 // inside this else statement is code if we dont have the fftw3
277 // headers
278 
279 
281 
double Im(const Diana::QComplex &z)
Function to get the imag part.
Definition: QComplex.cc:262
double Re(const Diana::QComplex &z)
Function to get the real part.
Definition: QComplex.cc:260
#define Q_END_NAMESPACE
Definition: QDiana.hh:22
#define Q_BEGIN_NAMESPACE
Definition: QDiana.hh:20
@ QERR_UNKNOWN_ERR
Definition: QError.hh:108
ClassImp(Diana::QRealComplexFFTW3)
error class with error type and description
Definition: QError.hh:115
Interface for ffts in Diana analysis.
Definition: QFFT.hh:26
size_t fWindowSize
Definition: QFFT.hh:178
void SetForward(bool isForward)
virtual method. Must be implemented by daughter classes set the direction of the transform.
Definition: QFFT.hh:142
double * fData
Definition: QFFT.hh:176
WindowType
window type
Definition: QFFT.hh:30
@ WT_None
Definition: QFFT.hh:31
FFTDirection fDirection
Definition: QFFT.hh:173
WindowType fWindowType
Definition: QFFT.hh:179
static QVector GetWindow(WindowType wt, size_t size, size_t zeros=0, int coherent=0, int param=0)
create window and add zeros/2 to the left and zeros/2 to the right
Definition: QFFT.cc:82
double * fWindow
Definition: QFFT.hh:177
size_t fSize
Definition: QFFT.hh:172
@ kForward
Definition: QFFT.hh:47
bool fNormalized
Definition: QFFT.hh:174
virtual bool ClearCache(bool clearMem=true)
Free the allocated memory.
bool Resize(size_t s)
Resize the allocated memory.
size_t fAllocatedSize
Size of the allocated array.
virtual ~QRealComplexFFTW3()
destructor
virtual void SetWindowType(WindowType wt, int coherent=0)
resize working table and space
virtual bool CreatePlan(bool Forward)
Create a plan for this FFT (or any of this size)
virtual int Transform(const QVector &data, QVector &result)
Perform the transformation.
virtual int TransformFromFreq(const QVectorC &FT, QVector &spectrum, bool compress=false)
transform from the frequencies to the times
QRealComplexFFTW3()
empty constructor
bool fSizeLock
Lock the FFT size.
virtual int TransformToFreq(const QVector &data, QVectorC &FFT, bool compress=false)
transform from the times to the frequencies
static void ArrayFree(double *array)
Definition: QVector.cc:72
static double * ArrayAlloc(const UInt_t size)
Definition: QVector.cc:32