// @(#)root/base:$Id$
// Author: Anna Kreshuk  10/04/2006

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//
// TVirtualFFT
//
// TVirtualFFT is an interface class for Fast Fourier Transforms.
//
//
//
// The default FFT library is FFTW. To use it, FFTW3 library should already
// be installed, and ROOT should be have fftw3 module enabled, with the directories
// of fftw3 include file and library specified (see installation instructions).
// Function SetDefaultFFT() allows to change the default library.
//
// Available transform types:
// FFT:
// - "C2CFORWARD" - a complex input/output discrete Fourier transform (DFT)
//                  in one or more dimensions, -1 in the exponent
// - "C2CBACKWARD"- a complex input/output discrete Fourier transform (DFT)
//                  in one or more dimensions, +1 in the exponent
// - "R2C"        - a real-input/complex-output discrete Fourier transform (DFT)
//                  in one or more dimensions,
// - "C2R"        - inverse transforms to "R2C", taking complex input
//                  (storing the non-redundant half of a logically Hermitian array)
//                  to real output
// - "R2HC"       - a real-input DFT with output in ¡Èhalfcomplex¡É format,
//                  i.e. real and imaginary parts for a transform of size n stored as
//                  r0, r1, r2, ..., rn/2, i(n+1)/2-1, ..., i2, i1
// - "HC2R"       - computes the reverse of FFTW_R2HC, above
// - "DHT"        - computes a discrete Hartley transform
//
// Sine/cosine transforms:
// Different types of transforms are specified by parameter kind of the SineCosine() static
// function. 4 different kinds of sine and cosine transforms are available
//  DCT-I  (REDFT00 in FFTW3 notation)- kind=0
//  DCT-II (REDFT01 in FFTW3 notation)- kind=1
//  DCT-III(REDFT10 in FFTW3 notation)- kind=2
//  DCT-IV (REDFT11 in FFTW3 notation)- kind=3
//  DST-I  (RODFT00 in FFTW3 notation)- kind=4
//  DST-II (RODFT01 in FFTW3 notation)- kind=5
//  DST-III(RODFT10 in FFTW3 notation)- kind=6
//  DST-IV (RODFT11 in FFTW3 notation)- kind=7
// Formulas and detailed descriptions can be found in the chapter
// "What FFTW really computes" of the FFTW manual
//
// NOTE: FFTW computes unnormalized transforms, so doing a transform, followed by its
//       inverse will give the original array, multiplied by normalization constant
//       (transform size(N) for FFT, 2*(N-1) for DCT-I, 2*(N+1) for DST-I, 2*N for
//       other sine/cosine transforms)
//
// How to use it:
// Call to the static function FFT returns a pointer to a fast fourier transform
// with requested parameters. Call to the static function SineCosine returns a
// pointer to a sine or cosine transform with requested parameters. Example:
// {
//    Int_t N = 10; Double_t *in = new Double_t[N];
//    TVirtualFFT *fftr2c = TVirtualFFT::FFT(1, &N, "R2C");
//    fftr2c->SetPoints(in);
//    fftr2c->Transform();
//    Double_t re, im;
//    for (Int_t i=0; i<N; i++)
//       fftr2c->GetPointComplex(i, re, im);
//    ...
//    fftr2c->SetPoints(in2);
//    ...
//    fftr2c->SetPoints(in3);
//    ...
// }
// Different options are explained in the function comments
//
//
//
//
//
//////////////////////////////////////////////////////////////////////////

#include "TROOT.h"
#include "TVirtualFFT.h"
#include "TPluginManager.h"
#include "TEnv.h"
#include "TError.h"

TVirtualFFT *TVirtualFFT::fgFFT    = 0;
TString      TVirtualFFT::fgDefault   = "";

ClassImp(TVirtualFFT)

//_____________________________________________________________________________
TVirtualFFT::~TVirtualFFT()
{
   //destructor
   if (this==fgFFT)
      fgFFT = 0;
}

//_____________________________________________________________________________
TVirtualFFT* TVirtualFFT::FFT(Int_t ndim, Int_t *n, Option_t *option)
{
//Returns a pointer to the FFT of requested size and type.
//Parameters:
// -ndim : number of transform dimensions
// -n    : sizes of each dimension (an array at least ndim long)
// -option : consists of 3 parts - flag option and an option to create a new TVirtualFFT
//         1) transform type option:
//           Available transform types are:
//           C2CForward, C2CBackward, C2R, R2C, R2HC, HC2R, DHT
//           see class description for details
//         2) flag option: choosing how much time should be spent in planning the transform:
//           Possible 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.
//         3) option allowing to choose between the global fgFFT and a new TVirtualFFT object
//           ""  - default, changes and returns the global fgFFT variable
//           "K" (from "keep")- without touching the global fgFFT,
//           creates and returns a new TVirtualFFT*. User is then responsible for deleting it.
// Examples of valid options: "R2C ES K", "C2CF M", "DHT P K", etc.


   Int_t inputtype=0, currenttype=0;
   TString opt = option;
   opt.ToUpper();
   //find the tranform flag
   Option_t *flag;
   flag = "ES";
   if (opt.Contains("ES")) flag = "ES";
   if (opt.Contains("M"))  flag = "M";
   if (opt.Contains("P"))  flag = "P";
   if (opt.Contains("EX")) flag = "EX";

   Int_t ndiff = 0;

   if (!opt.Contains("K")) {
      if (fgFFT){
         //if the global transform exists, check if it should be changed
         if (fgFFT->GetNdim()!=ndim)
            ndiff++;
         else {
            Int_t *ncurrent = fgFFT->GetN();
            for (Int_t i=0; i<ndim; i++){
               if (n[i]!=ncurrent[i])
                  ndiff++;
            }
         }
         Option_t *t = fgFFT->GetType();
         if (!opt.Contains(t)) {
            if (opt.Contains("HC") || opt.Contains("DHT"))
               inputtype = 1;
            if (strcmp(t,"R2HC")==0 || strcmp(t,"HC2R")==0 || strcmp(t,"DHT")==0)
               currenttype=1;

            if (!(inputtype==1 && currenttype==1))
               ndiff++;
         }
         if (ndiff>0){
            delete fgFFT;
            fgFFT = 0;
         }
      }
   }

   Int_t sign = 0;
   if (opt.Contains("C2CB") || opt.Contains("C2R"))
      sign = 1;
   if (opt.Contains("C2CF") || opt.Contains("R2C"))
      sign = -1;

   TVirtualFFT *fft = 0;
   if (opt.Contains("K") || !fgFFT) {
      TPluginHandler *h;
      TString pluginname;
      if (fgDefault.Length()==0) fgDefault="fftw";
      if (strcmp(fgDefault.Data(),"fftw")==0) {
         if (opt.Contains("C2C")) pluginname = "fftwc2c";
         if (opt.Contains("C2R")) pluginname = "fftwc2r";
         if (opt.Contains("R2C")) pluginname = "fftwr2c";
         if (opt.Contains("HC") || opt.Contains("DHT")) pluginname = "fftwr2r";
         if ((h=gROOT->GetPluginManager()->FindHandler("TVirtualFFT", pluginname))) {
            if (h->LoadPlugin()==-1) {
               ::Error("TVirtualFFT::FFT", "handler not found");
               return 0;
            }
            fft = (TVirtualFFT*)h->ExecPlugin(3, ndim, n, kFALSE);
            if (!fft) {
               ::Error("TVirtualFFT::FFT", "plugin failed to create TVirtualFFT object");
               return 0;
            }
            Int_t *kind = new Int_t[1];
            if (pluginname=="fftwr2r") {
               if (opt.Contains("R2HC")) kind[0] = 10;
               if (opt.Contains("HC2R")) kind[0] = 11;
               if (opt.Contains("DHT")) kind[0] = 12;
            }
            fft->Init(flag, sign, kind);
            if (!opt.Contains("K")) {
               fgFFT = fft;
            }
            delete [] kind;
            return fft;
         }
         else {
            ::Error("TVirtualFFT::FFT", "plugin not found");
            return 0;
         }
      }
   } else {
      //if the global transform already exists and just needs to be reinitialised
      //with different parameters
      if (fgFFT->GetSign()!=sign || !opt.Contains(fgFFT->GetTransformFlag()) || !opt.Contains(fgFFT->GetType())) {
         Int_t *kind = new Int_t[1];
         if (inputtype==1) {
            if (opt.Contains("R2HC")) kind[0] = 10;
            if (opt.Contains("HC2R")) kind[0] = 11;
            if (opt.Contains("DHT")) kind[0] = 12;
         }
         fgFFT->Init(flag, sign, kind);
         delete [] kind;
      }
   }
   return fgFFT;
}

//_____________________________________________________________________________
TVirtualFFT* TVirtualFFT::SineCosine(Int_t ndim, Int_t *n, Int_t *r2rkind, Option_t *option)
{
//Returns a pointer to a sine or cosine transform of requested size and kind
//
//Parameters:
// -ndim    : number of transform dimensions
// -n       : sizes of each dimension (an array at least ndim long)
// -r2rkind : transform kind for each dimension
//     4 different kinds of sine and cosine transforms are available
//     DCT-I    - kind=0
//     DCT-II   - kind=1
//     DCT-III  - kind=2
//     DCT-IV   - kind=3
//     DST-I    - kind=4
//     DST-II   - kind=5
//     DST-III  - kind=6
//     DST-IV   - kind=7
// -option : consists of 2 parts - flag option and an option to create a new TVirtualFFT
//         - flag option: choosing how much time should be spent in planning the transform:
//           Possible 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.
//         - option allowing to choose between the global fgFFT and a new TVirtualFFT object
//           ""  - default, changes and returns the global fgFFT variable
//           "K" (from "keep")- without touching the global fgFFT,
//           creates and returns a new TVirtualFFT*. User is then responsible for deleting it.
// Examples of valid options: "ES K", "EX", etc

   TString opt = option;
   //find the tranform flag
   Option_t *flag;
   flag = "ES";
   if (opt.Contains("ES")) flag = "ES";
   if (opt.Contains("M"))  flag = "M";
   if (opt.Contains("P"))  flag = "P";
   if (opt.Contains("EX")) flag = "EX";

   if (!opt.Contains("K")) {
      if (fgFFT){
         Int_t ndiff = 0;
         if (fgFFT->GetNdim()!=ndim || strcmp(fgFFT->GetType(),"R2R")!=0)
            ndiff++;
         else {
            Int_t *ncurrent = fgFFT->GetN();
            for (Int_t i=0; i<ndim; i++) {
               if (n[i] != ncurrent[i])
                  ndiff++;
            }

         }
         if (ndiff>0) {
            delete fgFFT;
            fgFFT = 0;
         }
      }
   }
   TVirtualFFT *fft = 0;
   if (!fgFFT || opt.Contains("K")) {
      TPluginHandler *h;
      TString pluginname;
      if (fgDefault.Length()==0) fgDefault="fftw";
      if (strcmp(fgDefault.Data(),"fftw")==0) {
         pluginname = "fftwr2r";
         if ((h=gROOT->GetPluginManager()->FindHandler("TVirtualFFT", pluginname))) {
            if (h->LoadPlugin()==-1){
               ::Error("TVirtualFFT::SineCosine", "handler not found");
               return 0;
            }
            fft = (TVirtualFFT*)h->ExecPlugin(3, ndim, n, kFALSE);
            if (!fft) {
               ::Error("TVirtualFFT::SineCosine", "plugin failed to create TVirtualFFT object");
               return 0;
            }
            fft->Init(flag, 0, r2rkind);
            if (!opt.Contains("K"))
               fgFFT = fft;
            return fft;
         } else {
            ::Error("TVirtualFFT::SineCosine", "handler not found");
            return 0;
         }
      }
   }

   //if (fgFFT->GetTransformFlag()!=flag)
   fgFFT->Init(flag,0, r2rkind);
   return fgFFT;
}

//_____________________________________________________________________________
TVirtualFFT* TVirtualFFT::GetCurrentTransform()
{
// static: return current fgFFT

   if (fgFFT)
      return fgFFT;
   else{
      ::Warning("TVirtualFFT::GetCurrentTransform", "fgFFT is not defined yet");
      return 0;
   }
}

//_____________________________________________________________________________
void TVirtualFFT::SetTransform(TVirtualFFT* fft)
{
// static: set the current transfrom to parameter

   fgFFT = fft;
}

//_____________________________________________________________________________
const char *TVirtualFFT::GetDefaultFFT()
{
// static: return the name of the default fft

   return fgDefault.Data();
}

//______________________________________________________________________________
void TVirtualFFT::SetDefaultFFT(const char *name)
{
   // static: set name of default fft

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