```// @(#)root/fft:\$Id\$
// Author: Anna Kreshuk   07/4/2006

/*************************************************************************
*                                                                       *
* For the licensing terms see \$ROOTSYS/LICENSE.                         *
* For the list of contributors see \$ROOTSYS/README/CREDITS.             *
*************************************************************************/

//////////////////////////////////////////////////////////////////////////
//
// TFFTComplex
// One of the interface classes to the FFTW package, can be used directly
// or via the TVirtualFFT class. Only the basic interface of FFTW is implemented.
// Computes complex input/output discrete Fourier transforms (DFT)
// in one or more dimensions. For the detailed information on the computed
// transforms please refer to the FFTW manual, chapter "What FFTW really computes".
//
// How to use it:
// 1) Create an instance of TFFTComplex - this will allocate input and output
//    arrays (unless an in-place transform is specified)
// 2) Run the Init() function with the desired flags and settings
// 3) Set the data (via SetPoints(), SetPoint() or SetPointComplex() functions)
// 4) Run the Transform() function
// 5) Get the output (via GetPoints(), GetPoint() or GetPointComplex() functions)
// 6) Repeat steps 3)-5) as needed
//
// For a transform of the same size, but with different flags or sign, rerun the Init()
// function and continue with steps 3)-5)
// NOTE: 1) running Init() function will overwrite the input array! Don't set any data
//          before running the Init() function
//       2) FFTW computes unnormalized transform, so doing a transform followed by
//          its inverse will lead to the original array scaled by the transform size
//
//////////////////////////////////////////////////////////////////////////

#include "TFFTComplex.h"
#include "fftw3.h"
#include "TComplex.h"

ClassImp(TFFTComplex)

//_____________________________________________________________________________
TFFTComplex::TFFTComplex()
{
//default

fIn   = 0;
fOut  = 0;
fPlan = 0;
fN    = 0;
fFlags = 0;
fNdim = 0;
fTotalSize = 0;
fSign = 1;
}

//_____________________________________________________________________________
TFFTComplex::TFFTComplex(Int_t n, Bool_t inPlace)
{
//For 1d transforms
//Allocates memory for the input array, and, if inPlace = kFALSE, for the output array

fIn = fftw_malloc(sizeof(fftw_complex) *n);
if (!inPlace)
fOut = fftw_malloc(sizeof(fftw_complex) * n);
else
fOut = 0;
fN    = new Int_t[1];
fN[0] = n;
fTotalSize = n;
fNdim = 1;
fSign = 1;
fPlan = 0;
fFlags = 0;
}

//_____________________________________________________________________________
TFFTComplex::TFFTComplex(Int_t ndim, Int_t *n, Bool_t inPlace)
{
//For multidim. transforms
//Allocates memory for the input array, and, if inPlace = kFALSE, for the output array

fNdim = ndim;
fTotalSize = 1;
fN = new Int_t[fNdim];
for (Int_t i=0; i<fNdim; i++){
fN[i] = n[i];
fTotalSize*=n[i];
}
fIn = fftw_malloc(sizeof(fftw_complex)*fTotalSize);
if (!inPlace)
fOut = fftw_malloc(sizeof(fftw_complex) * fTotalSize);
else
fOut = 0;
fSign = 1;
fPlan = 0;
fFlags = 0;
}

//_____________________________________________________________________________
TFFTComplex::~TFFTComplex()
{
//Destroys the data arrays and the plan. However, some plan information stays around
//until the root session is over, and is reused if other plans of the same size are
//created

fftw_destroy_plan((fftw_plan)fPlan);
fPlan = 0;
fftw_free((fftw_complex*)fIn);
if (fOut)
fftw_free((fftw_complex*)fOut);
if (fN)
delete [] fN;
}

//_____________________________________________________________________________
void TFFTComplex::Init( Option_t *flags, Int_t sign,const Int_t* /*kind*/)
{
//Creates the fftw-plan
//
//NOTE:  input and output arrays are overwritten during initialisation,
//       so don't set any points, before running this function!!!!!
//
//2nd parameter: +1
//Argument kind is dummy and doesn't need to be specified
//Possible flag_options:
//"ES" (from "estimate") - no time in preparing the transform, but probably sub-optimal
//   performance
//"M" (from "measure") - some time spend in finding the optimal way to do the transform
//"P" (from "patient") - more time spend in finding the optimal way to do the transform
//"EX" (from "exhaustive") - the most optimal way is found
//This option should be chosen depending on how many transforms of the same size and
//type are going to be done. Planning is only done once, for the first transform of this
//size and type.

fSign = sign;
fFlags = flags;

if (fPlan)
fftw_destroy_plan((fftw_plan)fPlan);
fPlan = 0;

if (fOut)
fPlan = (void*)fftw_plan_dft(fNdim, fN, (fftw_complex*)fIn, (fftw_complex*)fOut, sign,MapFlag(flags));
else
fPlan = (void*)fftw_plan_dft(fNdim, fN, (fftw_complex*)fIn, (fftw_complex*)fIn, sign, MapFlag(flags));
}

//_____________________________________________________________________________
void TFFTComplex::Transform()
{
//Computes the transform, specified in Init() function

if (fPlan)
fftw_execute((fftw_plan)fPlan);
else {
Error("Transform", "transform not initialised");
return;
}
}

//_____________________________________________________________________________
void TFFTComplex::GetPoints(Double_t *data, Bool_t fromInput) const
{
//Copies the output(or input) into the argument array

if (!fromInput){
for (Int_t i=0; i<2*fTotalSize; i+=2){
data[i] = ((fftw_complex*)fOut)[i/2][0];
data[i+1] = ((fftw_complex*)fOut)[i/2][1];
}
} else {
for (Int_t i=0; i<2*fTotalSize; i+=2){
data[i] = ((fftw_complex*)fIn)[i/2][0];
data[i+1] = ((fftw_complex*)fIn)[i/2][1];
}
}
}

//_____________________________________________________________________________
void TFFTComplex::GetPointComplex(Int_t ipoint, Double_t &re, Double_t &im, Bool_t fromInput) const
{
//returns real and imaginary parts of the point #ipoint

if (fOut && !fromInput){
re = ((fftw_complex*)fOut)[ipoint][0];
im = ((fftw_complex*)fOut)[ipoint][1];
} else {
re = ((fftw_complex*)fIn)[ipoint][0];
im = ((fftw_complex*)fIn)[ipoint][1];
}
}

//_____________________________________________________________________________
void TFFTComplex::GetPointComplex(const Int_t *ipoint, Double_t &re, Double_t &im, Bool_t fromInput) const
{
//For multidimensional transforms. Returns real and imaginary parts of the point #ipoint

Int_t ireal = ipoint[0];
for (Int_t i=0; i<fNdim-1; i++)
ireal=fN[i+1]*ireal + ipoint[i+1];

if (fOut && !fromInput){
re = ((fftw_complex*)fOut)[ireal][0];
im = ((fftw_complex*)fOut)[ireal][1];
} else {
re = ((fftw_complex*)fIn)[ireal][0];
im = ((fftw_complex*)fIn)[ireal][1];
}
}

//_____________________________________________________________________________
void TFFTComplex::GetPointsComplex(Double_t *re, Double_t *im, Bool_t fromInput) const
{
//Copies real and imaginary parts of the output (input) into the argument arrays

if (fOut && !fromInput){
for (Int_t i=0; i<fTotalSize; i++){
re[i] = ((fftw_complex*)fOut)[i][0];
im[i] = ((fftw_complex*)fOut)[i][1];
}
} else {
for (Int_t i=0; i<fTotalSize; i++){
re[i] = ((fftw_complex*)fIn)[i][0];
im[i] = ((fftw_complex*)fIn)[i][1];
}
}
}

//_____________________________________________________________________________
void TFFTComplex::GetPointsComplex(Double_t *data, Bool_t fromInput) const
{
//Copies the output(input) into the argument array

if (fOut && !fromInput){
for (Int_t i=0; i<fTotalSize; i+=2){
data[i] = ((fftw_complex*)fOut)[i/2][0];
data[i+1] = ((fftw_complex*)fOut)[i/2][1];
}
} else {
for (Int_t i=0; i<fTotalSize; i+=2){
data[i] = ((fftw_complex*)fIn)[i/2][0];
data[i+1] = ((fftw_complex*)fIn)[i/2][1];
}
}
}

//_____________________________________________________________________________
void TFFTComplex::SetPoint(Int_t ipoint, Double_t re, Double_t im)
{
//sets real and imaginary parts of point # ipoint

((fftw_complex*)fIn)[ipoint][0]=re;
((fftw_complex*)fIn)[ipoint][1]=im;
}

//_____________________________________________________________________________
void TFFTComplex::SetPoint(const Int_t *ipoint, Double_t re, Double_t im)
{
//For multidim. transforms. Sets real and imaginary parts of point # ipoint

Int_t ireal = ipoint[0];
for (Int_t i=0; i<fNdim-1; i++)
ireal=fN[i+1]*ireal + ipoint[i+1];

((fftw_complex*)fIn)[ireal][0]=re;
((fftw_complex*)fIn)[ireal][1]=im;
}

//_____________________________________________________________________________
void TFFTComplex::SetPointComplex(Int_t ipoint, TComplex &c)
{
((fftw_complex*)fIn)[ipoint][0] = c.Re();
((fftw_complex*)fIn)[ipoint][1] = c.Im();
}

//_____________________________________________________________________________
void TFFTComplex::SetPoints(const Double_t *data)
{
//set all points. the values are copied. points should be ordered as follows:
//[re_0, im_0, re_1, im_1, ..., re_n, im_n)

for (Int_t i=0; i<2*fTotalSize-1; i+=2){
((fftw_complex*)fIn)[i/2][0]=data[i];
((fftw_complex*)fIn)[i/2][1]=data[i+1];
}
}

//_____________________________________________________________________________
void TFFTComplex::SetPointsComplex(const Double_t *re_data, const Double_t *im_data)
{
//set all points. the values are copied

if (!fIn){
Error("SetPointsComplex", "Size is not set yet");
return;
}
for (Int_t i=0; i<fTotalSize; i++){
((fftw_complex*)fIn)[i][0]=re_data[i];
((fftw_complex*)fIn)[i][1]=im_data[i];
}
}

//_____________________________________________________________________________
UInt_t TFFTComplex::MapFlag(Option_t *flag)
{
//allowed options:
//"ES" - FFTW_ESTIMATE
//"M" - FFTW_MEASURE
//"P" - FFTW_PATIENT
//"EX" - FFTW_EXHAUSTIVE

TString opt = flag;
opt.ToUpper();
if (opt.Contains("ES"))
return FFTW_ESTIMATE;
if (opt.Contains("M"))
return FFTW_MEASURE;
if (opt.Contains("P"))
return FFTW_PATIENT;
if (opt.Contains("EX"))
return FFTW_EXHAUSTIVE;
return FFTW_ESTIMATE;
}
```
TFFTComplex.cxx:1
TFFTComplex.cxx:2
TFFTComplex.cxx:3
TFFTComplex.cxx:4
TFFTComplex.cxx:5
TFFTComplex.cxx:6
TFFTComplex.cxx:7
TFFTComplex.cxx:8
TFFTComplex.cxx:9
TFFTComplex.cxx:10
TFFTComplex.cxx:11
TFFTComplex.cxx:12
TFFTComplex.cxx:13
TFFTComplex.cxx:14
TFFTComplex.cxx:15
TFFTComplex.cxx:16
TFFTComplex.cxx:17
TFFTComplex.cxx:18
TFFTComplex.cxx:19
TFFTComplex.cxx:20
TFFTComplex.cxx:21
TFFTComplex.cxx:22
TFFTComplex.cxx:23
TFFTComplex.cxx:24
TFFTComplex.cxx:25
TFFTComplex.cxx:26
TFFTComplex.cxx:27
TFFTComplex.cxx:28
TFFTComplex.cxx:29
TFFTComplex.cxx:30
TFFTComplex.cxx:31
TFFTComplex.cxx:32
TFFTComplex.cxx:33
TFFTComplex.cxx:34
TFFTComplex.cxx:35
TFFTComplex.cxx:36
TFFTComplex.cxx:37
TFFTComplex.cxx:38
TFFTComplex.cxx:39
TFFTComplex.cxx:40
TFFTComplex.cxx:41
TFFTComplex.cxx:42
TFFTComplex.cxx:43
TFFTComplex.cxx:44
TFFTComplex.cxx:45
TFFTComplex.cxx:46
TFFTComplex.cxx:47
TFFTComplex.cxx:48
TFFTComplex.cxx:49
TFFTComplex.cxx:50
TFFTComplex.cxx:51
TFFTComplex.cxx:52
TFFTComplex.cxx:53
TFFTComplex.cxx:54
TFFTComplex.cxx:55
TFFTComplex.cxx:56
TFFTComplex.cxx:57
TFFTComplex.cxx:58
TFFTComplex.cxx:59
TFFTComplex.cxx:60
TFFTComplex.cxx:61
TFFTComplex.cxx:62
TFFTComplex.cxx:63
TFFTComplex.cxx:64
TFFTComplex.cxx:65
TFFTComplex.cxx:66
TFFTComplex.cxx:67
TFFTComplex.cxx:68
TFFTComplex.cxx:69
TFFTComplex.cxx:70
TFFTComplex.cxx:71
TFFTComplex.cxx:72
TFFTComplex.cxx:73
TFFTComplex.cxx:74
TFFTComplex.cxx:75
TFFTComplex.cxx:76
TFFTComplex.cxx:77
TFFTComplex.cxx:78
TFFTComplex.cxx:79
TFFTComplex.cxx:80
TFFTComplex.cxx:81
TFFTComplex.cxx:82
TFFTComplex.cxx:83
TFFTComplex.cxx:84
TFFTComplex.cxx:85
TFFTComplex.cxx:86
TFFTComplex.cxx:87
TFFTComplex.cxx:88
TFFTComplex.cxx:89
TFFTComplex.cxx:90
TFFTComplex.cxx:91
TFFTComplex.cxx:92
TFFTComplex.cxx:93
TFFTComplex.cxx:94
TFFTComplex.cxx:95
TFFTComplex.cxx:96
TFFTComplex.cxx:97
TFFTComplex.cxx:98
TFFTComplex.cxx:99
TFFTComplex.cxx:100
TFFTComplex.cxx:101
TFFTComplex.cxx:102
TFFTComplex.cxx:103
TFFTComplex.cxx:104
TFFTComplex.cxx:105
TFFTComplex.cxx:106
TFFTComplex.cxx:107
TFFTComplex.cxx:108
TFFTComplex.cxx:109
TFFTComplex.cxx:110
TFFTComplex.cxx:111
TFFTComplex.cxx:112
TFFTComplex.cxx:113
TFFTComplex.cxx:114
TFFTComplex.cxx:115
TFFTComplex.cxx:116
TFFTComplex.cxx:117
TFFTComplex.cxx:118
TFFTComplex.cxx:119
TFFTComplex.cxx:120
TFFTComplex.cxx:121
TFFTComplex.cxx:122
TFFTComplex.cxx:123
TFFTComplex.cxx:124
TFFTComplex.cxx:125
TFFTComplex.cxx:126
TFFTComplex.cxx:127
TFFTComplex.cxx:128
TFFTComplex.cxx:129
TFFTComplex.cxx:130
TFFTComplex.cxx:131
TFFTComplex.cxx:132
TFFTComplex.cxx:133
TFFTComplex.cxx:134
TFFTComplex.cxx:135
TFFTComplex.cxx:136
TFFTComplex.cxx:137
TFFTComplex.cxx:138
TFFTComplex.cxx:139
TFFTComplex.cxx:140
TFFTComplex.cxx:141
TFFTComplex.cxx:142
TFFTComplex.cxx:143
TFFTComplex.cxx:144
TFFTComplex.cxx:145
TFFTComplex.cxx:146
TFFTComplex.cxx:147
TFFTComplex.cxx:148
TFFTComplex.cxx:149
TFFTComplex.cxx:150
TFFTComplex.cxx:151
TFFTComplex.cxx:152
TFFTComplex.cxx:153
TFFTComplex.cxx:154
TFFTComplex.cxx:155
TFFTComplex.cxx:156
TFFTComplex.cxx:157
TFFTComplex.cxx:158
TFFTComplex.cxx:159
TFFTComplex.cxx:160
TFFTComplex.cxx:161
TFFTComplex.cxx:162
TFFTComplex.cxx:163
TFFTComplex.cxx:164
TFFTComplex.cxx:165
TFFTComplex.cxx:166
TFFTComplex.cxx:167
TFFTComplex.cxx:168
TFFTComplex.cxx:169
TFFTComplex.cxx:170
TFFTComplex.cxx:171
TFFTComplex.cxx:172
TFFTComplex.cxx:173
TFFTComplex.cxx:174
TFFTComplex.cxx:175
TFFTComplex.cxx:176
TFFTComplex.cxx:177
TFFTComplex.cxx:178
TFFTComplex.cxx:179
TFFTComplex.cxx:180
TFFTComplex.cxx:181
TFFTComplex.cxx:182
TFFTComplex.cxx:183
TFFTComplex.cxx:184
TFFTComplex.cxx:185
TFFTComplex.cxx:186
TFFTComplex.cxx:187
TFFTComplex.cxx:188
TFFTComplex.cxx:189
TFFTComplex.cxx:190
TFFTComplex.cxx:191
TFFTComplex.cxx:192
TFFTComplex.cxx:193
TFFTComplex.cxx:194
TFFTComplex.cxx:195
TFFTComplex.cxx:196
TFFTComplex.cxx:197
TFFTComplex.cxx:198
TFFTComplex.cxx:199
TFFTComplex.cxx:200
TFFTComplex.cxx:201
TFFTComplex.cxx:202
TFFTComplex.cxx:203
TFFTComplex.cxx:204
TFFTComplex.cxx:205
TFFTComplex.cxx:206
TFFTComplex.cxx:207
TFFTComplex.cxx:208
TFFTComplex.cxx:209
TFFTComplex.cxx:210
TFFTComplex.cxx:211
TFFTComplex.cxx:212
TFFTComplex.cxx:213
TFFTComplex.cxx:214
TFFTComplex.cxx:215
TFFTComplex.cxx:216
TFFTComplex.cxx:217
TFFTComplex.cxx:218
TFFTComplex.cxx:219
TFFTComplex.cxx:220
TFFTComplex.cxx:221
TFFTComplex.cxx:222
TFFTComplex.cxx:223
TFFTComplex.cxx:224
TFFTComplex.cxx:225
TFFTComplex.cxx:226
TFFTComplex.cxx:227
TFFTComplex.cxx:228
TFFTComplex.cxx:229
TFFTComplex.cxx:230
TFFTComplex.cxx:231
TFFTComplex.cxx:232
TFFTComplex.cxx:233
TFFTComplex.cxx:234
TFFTComplex.cxx:235
TFFTComplex.cxx:236
TFFTComplex.cxx:237
TFFTComplex.cxx:238
TFFTComplex.cxx:239
TFFTComplex.cxx:240
TFFTComplex.cxx:241
TFFTComplex.cxx:242
TFFTComplex.cxx:243
TFFTComplex.cxx:244
TFFTComplex.cxx:245
TFFTComplex.cxx:246
TFFTComplex.cxx:247
TFFTComplex.cxx:248
TFFTComplex.cxx:249
TFFTComplex.cxx:250
TFFTComplex.cxx:251
TFFTComplex.cxx:252
TFFTComplex.cxx:253
TFFTComplex.cxx:254
TFFTComplex.cxx:255
TFFTComplex.cxx:256
TFFTComplex.cxx:257
TFFTComplex.cxx:258
TFFTComplex.cxx:259
TFFTComplex.cxx:260
TFFTComplex.cxx:261
TFFTComplex.cxx:262
TFFTComplex.cxx:263
TFFTComplex.cxx:264
TFFTComplex.cxx:265
TFFTComplex.cxx:266
TFFTComplex.cxx:267
TFFTComplex.cxx:268
TFFTComplex.cxx:269
TFFTComplex.cxx:270
TFFTComplex.cxx:271
TFFTComplex.cxx:272
TFFTComplex.cxx:273
TFFTComplex.cxx:274
TFFTComplex.cxx:275
TFFTComplex.cxx:276
TFFTComplex.cxx:277
TFFTComplex.cxx:278
TFFTComplex.cxx:279
TFFTComplex.cxx:280
TFFTComplex.cxx:281
TFFTComplex.cxx:282
TFFTComplex.cxx:283
TFFTComplex.cxx:284
TFFTComplex.cxx:285
TFFTComplex.cxx:286
TFFTComplex.cxx:287
TFFTComplex.cxx:288
TFFTComplex.cxx:289
TFFTComplex.cxx:290
TFFTComplex.cxx:291
TFFTComplex.cxx:292
TFFTComplex.cxx:293
TFFTComplex.cxx:294
TFFTComplex.cxx:295
TFFTComplex.cxx:296
TFFTComplex.cxx:297
TFFTComplex.cxx:298
TFFTComplex.cxx:299
TFFTComplex.cxx:300
TFFTComplex.cxx:301
TFFTComplex.cxx:302
TFFTComplex.cxx:303
TFFTComplex.cxx:304
TFFTComplex.cxx:305
TFFTComplex.cxx:306
TFFTComplex.cxx:307
TFFTComplex.cxx:308
TFFTComplex.cxx:309
TFFTComplex.cxx:310
TFFTComplex.cxx:311
TFFTComplex.cxx:312
TFFTComplex.cxx:313
TFFTComplex.cxx:314
TFFTComplex.cxx:315
TFFTComplex.cxx:316
TFFTComplex.cxx:317
TFFTComplex.cxx:318
TFFTComplex.cxx:319
TFFTComplex.cxx:320
TFFTComplex.cxx:321
TFFTComplex.cxx:322
TFFTComplex.cxx:323
TFFTComplex.cxx:324
TFFTComplex.cxx:325
TFFTComplex.cxx:326
TFFTComplex.cxx:327
TFFTComplex.cxx:328