00001 // @(#)root/base:$Id: TVirtualFFT.cxx 22967 2008-04-03 14:32:25Z rdm $ 00002 // Author: Anna Kreshuk 10/04/2006 00003 00004 /************************************************************************* 00005 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * 00006 * All rights reserved. * 00007 * * 00008 * For the licensing terms see $ROOTSYS/LICENSE. * 00009 * For the list of contributors see $ROOTSYS/README/CREDITS. * 00010 *************************************************************************/ 00011 00012 ////////////////////////////////////////////////////////////////////////// 00013 // 00014 // TVirtualFFT 00015 // 00016 // TVirtualFFT is an interface class for Fast Fourier Transforms. 00017 // 00018 // 00019 // 00020 // The default FFT library is FFTW. To use it, FFTW3 library should already 00021 // be installed, and ROOT should be have fftw3 module enabled, with the directories 00022 // of fftw3 include file and library specified (see installation instructions). 00023 // Function SetDefaultFFT() allows to change the default library. 00024 // 00025 // Available transform types: 00026 // FFT: 00027 // - "C2CFORWARD" - a complex input/output discrete Fourier transform (DFT) 00028 // in one or more dimensions, -1 in the exponent 00029 // - "C2CBACKWARD"- a complex input/output discrete Fourier transform (DFT) 00030 // in one or more dimensions, +1 in the exponent 00031 // - "R2C" - a real-input/complex-output discrete Fourier transform (DFT) 00032 // in one or more dimensions, 00033 // - "C2R" - inverse transforms to "R2C", taking complex input 00034 // (storing the non-redundant half of a logically Hermitian array) 00035 // to real output 00036 // - "R2HC" - a real-input DFT with output in ¡Èhalfcomplex¡É format, 00037 // i.e. real and imaginary parts for a transform of size n stored as 00038 // r0, r1, r2, ..., rn/2, i(n+1)/2-1, ..., i2, i1 00039 // - "HC2R" - computes the reverse of FFTW_R2HC, above 00040 // - "DHT" - computes a discrete Hartley transform 00041 // 00042 // Sine/cosine transforms: 00043 // Different types of transforms are specified by parameter kind of the SineCosine() static 00044 // function. 4 different kinds of sine and cosine transforms are available 00045 // DCT-I (REDFT00 in FFTW3 notation)- kind=0 00046 // DCT-II (REDFT10 in FFTW3 notation)- kind=1 00047 // DCT-III(REDFT01 in FFTW3 notation)- kind=2 00048 // DCT-IV (REDFT11 in FFTW3 notation)- kind=3 00049 // DST-I (RODFT00 in FFTW3 notation)- kind=4 00050 // DST-II (RODFT10 in FFTW3 notation)- kind=5 00051 // DST-III(RODFT01 in FFTW3 notation)- kind=6 00052 // DST-IV (RODFT11 in FFTW3 notation)- kind=7 00053 // Formulas and detailed descriptions can be found in the chapter 00054 // "What FFTW really computes" of the FFTW manual 00055 // 00056 // NOTE: FFTW computes unnormalized transforms, so doing a transform, followed by its 00057 // inverse will give the original array, multiplied by normalization constant 00058 // (transform size(N) for FFT, 2*(N-1) for DCT-I, 2*(N+1) for DST-I, 2*N for 00059 // other sine/cosine transforms) 00060 // 00061 // How to use it: 00062 // Call to the static function FFT returns a pointer to a fast fourier transform 00063 // with requested parameters. Call to the static function SineCosine returns a 00064 // pointer to a sine or cosine transform with requested parameters. Example: 00065 // { 00066 // Int_t N = 10; Double_t *in = new Double_t[N]; 00067 // TVirtualFFT *fftr2c = TVirtualFFT::FFT(1, &N, "R2C"); 00068 // fftr2c->SetPoints(in); 00069 // fftr2c->Transform(); 00070 // Double_t re, im; 00071 // for (Int_t i=0; i<N; i++) 00072 // fftr2c->GetPointComplex(i, re, im); 00073 // ... 00074 // fftr2c->SetPoints(in2); 00075 // ... 00076 // fftr2c->SetPoints(in3); 00077 // ... 00078 // } 00079 // Different options are explained in the function comments 00080 // 00081 // 00082 // 00083 // 00084 // 00085 ////////////////////////////////////////////////////////////////////////// 00086 00087 #include "TROOT.h" 00088 #include "TVirtualFFT.h" 00089 #include "TPluginManager.h" 00090 #include "TEnv.h" 00091 #include "TError.h" 00092 00093 TVirtualFFT *TVirtualFFT::fgFFT = 0; 00094 TString TVirtualFFT::fgDefault = ""; 00095 00096 ClassImp(TVirtualFFT) 00097 00098 //_____________________________________________________________________________ 00099 TVirtualFFT::~TVirtualFFT() 00100 { 00101 //destructor 00102 if (this==fgFFT) 00103 fgFFT = 0; 00104 } 00105 00106 //_____________________________________________________________________________ 00107 TVirtualFFT* TVirtualFFT::FFT(Int_t ndim, Int_t *n, Option_t *option) 00108 { 00109 //Returns a pointer to the FFT of requested size and type. 00110 //Parameters: 00111 // -ndim : number of transform dimensions 00112 // -n : sizes of each dimension (an array at least ndim long) 00113 // -option : consists of 3 parts - flag option and an option to create a new TVirtualFFT 00114 // 1) transform type option: 00115 // Available transform types are: 00116 // C2CForward, C2CBackward, C2R, R2C, R2HC, HC2R, DHT 00117 // see class description for details 00118 // 2) flag option: choosing how much time should be spent in planning the transform: 00119 // Possible options: 00120 // "ES" (from "estimate") - no time in preparing the transform, 00121 // but probably sub-optimal performance 00122 // "M" (from "measure") - some time spend in finding the optimal way 00123 // to do the transform 00124 // "P" (from "patient") - more time spend in finding the optimal way 00125 // to do the transform 00126 // "EX" (from "exhaustive") - the most optimal way is found 00127 // This option should be chosen depending on how many transforms of the 00128 // same size and type are going to be done. 00129 // Planning is only done once, for the first transform of this size and type. 00130 // 3) option allowing to choose between the global fgFFT and a new TVirtualFFT object 00131 // "" - default, changes and returns the global fgFFT variable 00132 // "K" (from "keep")- without touching the global fgFFT, 00133 // creates and returns a new TVirtualFFT*. User is then responsible for deleting it. 00134 // Examples of valid options: "R2C ES K", "C2CF M", "DHT P K", etc. 00135 00136 00137 Int_t inputtype=0, currenttype=0; 00138 TString opt = option; 00139 opt.ToUpper(); 00140 //find the tranform flag 00141 Option_t *flag; 00142 flag = "ES"; 00143 if (opt.Contains("ES")) flag = "ES"; 00144 if (opt.Contains("M")) flag = "M"; 00145 if (opt.Contains("P")) flag = "P"; 00146 if (opt.Contains("EX")) flag = "EX"; 00147 00148 Int_t ndiff = 0; 00149 00150 if (!opt.Contains("K")) { 00151 if (fgFFT){ 00152 //if the global transform exists, check if it should be changed 00153 if (fgFFT->GetNdim()!=ndim) 00154 ndiff++; 00155 else { 00156 Int_t *ncurrent = fgFFT->GetN(); 00157 for (Int_t i=0; i<ndim; i++){ 00158 if (n[i]!=ncurrent[i]) 00159 ndiff++; 00160 } 00161 } 00162 Option_t *t = fgFFT->GetType(); 00163 if (!opt.Contains(t)) { 00164 if (opt.Contains("HC") || opt.Contains("DHT")) 00165 inputtype = 1; 00166 if (strcmp(t,"R2HC")==0 || strcmp(t,"HC2R")==0 || strcmp(t,"DHT")==0) 00167 currenttype=1; 00168 00169 if (!(inputtype==1 && currenttype==1)) 00170 ndiff++; 00171 } 00172 if (ndiff>0){ 00173 delete fgFFT; 00174 fgFFT = 0; 00175 } 00176 } 00177 } 00178 00179 Int_t sign = 0; 00180 if (opt.Contains("C2CB") || opt.Contains("C2R")) 00181 sign = 1; 00182 if (opt.Contains("C2CF") || opt.Contains("R2C")) 00183 sign = -1; 00184 00185 TVirtualFFT *fft = 0; 00186 if (opt.Contains("K") || !fgFFT) { 00187 TPluginHandler *h; 00188 TString pluginname; 00189 if (fgDefault.Length()==0) fgDefault="fftw"; 00190 if (strcmp(fgDefault.Data(),"fftw")==0) { 00191 if (opt.Contains("C2C")) pluginname = "fftwc2c"; 00192 if (opt.Contains("C2R")) pluginname = "fftwc2r"; 00193 if (opt.Contains("R2C")) pluginname = "fftwr2c"; 00194 if (opt.Contains("HC") || opt.Contains("DHT")) pluginname = "fftwr2r"; 00195 if ((h=gROOT->GetPluginManager()->FindHandler("TVirtualFFT", pluginname))) { 00196 if (h->LoadPlugin()==-1) { 00197 ::Error("TVirtualFFT::FFT", "handler not found"); 00198 return 0; 00199 } 00200 fft = (TVirtualFFT*)h->ExecPlugin(3, ndim, n, kFALSE); 00201 if (!fft) { 00202 ::Error("TVirtualFFT::FFT", "plugin failed to create TVirtualFFT object"); 00203 return 0; 00204 } 00205 Int_t *kind = new Int_t[1]; 00206 if (pluginname=="fftwr2r") { 00207 if (opt.Contains("R2HC")) kind[0] = 10; 00208 if (opt.Contains("HC2R")) kind[0] = 11; 00209 if (opt.Contains("DHT")) kind[0] = 12; 00210 } 00211 fft->Init(flag, sign, kind); 00212 if (!opt.Contains("K")) { 00213 fgFFT = fft; 00214 } 00215 delete [] kind; 00216 return fft; 00217 } 00218 else { 00219 ::Error("TVirtualFFT::FFT", "plugin not found"); 00220 return 0; 00221 } 00222 } 00223 } else { 00224 //if the global transform already exists and just needs to be reinitialised 00225 //with different parameters 00226 if (fgFFT->GetSign()!=sign || !opt.Contains(fgFFT->GetTransformFlag()) || !opt.Contains(fgFFT->GetType())) { 00227 Int_t *kind = new Int_t[1]; 00228 if (inputtype==1) { 00229 if (opt.Contains("R2HC")) kind[0] = 10; 00230 if (opt.Contains("HC2R")) kind[0] = 11; 00231 if (opt.Contains("DHT")) kind[0] = 12; 00232 } 00233 fgFFT->Init(flag, sign, kind); 00234 delete [] kind; 00235 } 00236 } 00237 return fgFFT; 00238 } 00239 00240 //_____________________________________________________________________________ 00241 TVirtualFFT* TVirtualFFT::SineCosine(Int_t ndim, Int_t *n, Int_t *r2rkind, Option_t *option) 00242 { 00243 //Returns a pointer to a sine or cosine transform of requested size and kind 00244 // 00245 //Parameters: 00246 // -ndim : number of transform dimensions 00247 // -n : sizes of each dimension (an array at least ndim long) 00248 // -r2rkind : transform kind for each dimension 00249 // 4 different kinds of sine and cosine transforms are available 00250 // DCT-I - kind=0 00251 // DCT-II - kind=1 00252 // DCT-III - kind=2 00253 // DCT-IV - kind=3 00254 // DST-I - kind=4 00255 // DST-II - kind=5 00256 // DST-III - kind=6 00257 // DST-IV - kind=7 00258 // -option : consists of 2 parts - flag option and an option to create a new TVirtualFFT 00259 // - flag option: choosing how much time should be spent in planning the transform: 00260 // Possible options: 00261 // "ES" (from "estimate") - no time in preparing the transform, 00262 // but probably sub-optimal performance 00263 // "M" (from "measure") - some time spend in finding the optimal way 00264 // to do the transform 00265 // "P" (from "patient") - more time spend in finding the optimal way 00266 // to do the transform 00267 // "EX" (from "exhaustive") - the most optimal way is found 00268 // This option should be chosen depending on how many transforms of the 00269 // same size and type are going to be done. 00270 // Planning is only done once, for the first transform of this size and type. 00271 // - option allowing to choose between the global fgFFT and a new TVirtualFFT object 00272 // "" - default, changes and returns the global fgFFT variable 00273 // "K" (from "keep")- without touching the global fgFFT, 00274 // creates and returns a new TVirtualFFT*. User is then responsible for deleting it. 00275 // Examples of valid options: "ES K", "EX", etc 00276 00277 TString opt = option; 00278 //find the tranform flag 00279 Option_t *flag; 00280 flag = "ES"; 00281 if (opt.Contains("ES")) flag = "ES"; 00282 if (opt.Contains("M")) flag = "M"; 00283 if (opt.Contains("P")) flag = "P"; 00284 if (opt.Contains("EX")) flag = "EX"; 00285 00286 if (!opt.Contains("K")) { 00287 if (fgFFT){ 00288 Int_t ndiff = 0; 00289 if (fgFFT->GetNdim()!=ndim || strcmp(fgFFT->GetType(),"R2R")!=0) 00290 ndiff++; 00291 else { 00292 Int_t *ncurrent = fgFFT->GetN(); 00293 for (Int_t i=0; i<ndim; i++) { 00294 if (n[i] != ncurrent[i]) 00295 ndiff++; 00296 } 00297 00298 } 00299 if (ndiff>0) { 00300 delete fgFFT; 00301 fgFFT = 0; 00302 } 00303 } 00304 } 00305 TVirtualFFT *fft = 0; 00306 if (!fgFFT || opt.Contains("K")) { 00307 TPluginHandler *h; 00308 TString pluginname; 00309 if (fgDefault.Length()==0) fgDefault="fftw"; 00310 if (strcmp(fgDefault.Data(),"fftw")==0) { 00311 pluginname = "fftwr2r"; 00312 if ((h=gROOT->GetPluginManager()->FindHandler("TVirtualFFT", pluginname))) { 00313 if (h->LoadPlugin()==-1){ 00314 ::Error("TVirtualFFT::SineCosine", "handler not found"); 00315 return 0; 00316 } 00317 fft = (TVirtualFFT*)h->ExecPlugin(3, ndim, n, kFALSE); 00318 if (!fft) { 00319 ::Error("TVirtualFFT::SineCosine", "plugin failed to create TVirtualFFT object"); 00320 return 0; 00321 } 00322 fft->Init(flag, 0, r2rkind); 00323 if (!opt.Contains("K")) 00324 fgFFT = fft; 00325 return fft; 00326 } else { 00327 ::Error("TVirtualFFT::SineCosine", "handler not found"); 00328 return 0; 00329 } 00330 } 00331 } 00332 00333 //if (fgFFT->GetTransformFlag()!=flag) 00334 fgFFT->Init(flag,0, r2rkind); 00335 return fgFFT; 00336 } 00337 00338 //_____________________________________________________________________________ 00339 TVirtualFFT* TVirtualFFT::GetCurrentTransform() 00340 { 00341 // static: return current fgFFT 00342 00343 if (fgFFT) 00344 return fgFFT; 00345 else{ 00346 ::Warning("TVirtualFFT::GetCurrentTransform", "fgFFT is not defined yet"); 00347 return 0; 00348 } 00349 } 00350 00351 //_____________________________________________________________________________ 00352 void TVirtualFFT::SetTransform(TVirtualFFT* fft) 00353 { 00354 // static: set the current transfrom to parameter 00355 00356 fgFFT = fft; 00357 } 00358 00359 //_____________________________________________________________________________ 00360 const char *TVirtualFFT::GetDefaultFFT() 00361 { 00362 // static: return the name of the default fft 00363 00364 return fgDefault.Data(); 00365 } 00366 00367 //______________________________________________________________________________ 00368 void TVirtualFFT::SetDefaultFFT(const char *name) 00369 { 00370 // static: set name of default fft 00371 00372 if (fgDefault == name) return; 00373 delete fgFFT; 00374 fgFFT = 0; 00375 fgDefault = name; 00376 }