#include "TFFTRealComplex.h"
#include "fftw3.h"
#include "TComplex.h"
ClassImp(TFFTRealComplex)
TFFTRealComplex::TFFTRealComplex()
{
fIn = 0;
fOut = 0;
fPlan = 0;
fN = 0;
fFlags = 0;
fNdim = 0;
fTotalSize = 0;
}
TFFTRealComplex::TFFTRealComplex(Int_t n, Bool_t inPlace)
{
if (!inPlace){
fIn = fftw_malloc(sizeof(Double_t)*n);
fOut = fftw_malloc(sizeof(fftw_complex)*(n/2+1));
} else {
fIn = fftw_malloc(sizeof(Double_t)*(2*(n/2+1)));
fOut = 0;
}
fN = new Int_t[1];
fN[0] = n;
fTotalSize = n;
fNdim = 1;
fPlan = 0;
fFlags = 0;
}
TFFTRealComplex::TFFTRealComplex(Int_t ndim, Int_t *n, Bool_t inPlace)
{
if (ndim>1 && inPlace==kTRUE){
Error("TFFTRealComplex", "multidimensional in-place r2c transforms are not implemented yet");
return;
}
fNdim = ndim;
fTotalSize = 1;
fN = new Int_t[fNdim];
for (Int_t i=0; i<fNdim; i++){
fN[i] = n[i];
fTotalSize*=n[i];
}
Int_t sizeout = Int_t(Double_t(fTotalSize)*(n[ndim-1]/2+1)/n[ndim-1]);
if (!inPlace){
fIn = fftw_malloc(sizeof(Double_t)*fTotalSize);
fOut = fftw_malloc(sizeof(fftw_complex)*sizeout);
} else {
fIn = fftw_malloc(sizeof(Double_t)*(2*sizeout));
fOut = 0;
}
fPlan = 0;
fFlags = 0;
}
TFFTRealComplex::~TFFTRealComplex()
{
fftw_destroy_plan((fftw_plan)fPlan);
fPlan = 0;
fftw_free(fIn);
fIn = 0;
if (fOut)
fftw_free((fftw_complex*)fOut);
fOut = 0;
if (fN)
delete [] fN;
fN = 0;
}
void TFFTRealComplex::Init(Option_t *flags,Int_t , const Int_t* )
{
fFlags = flags;
if (fPlan)
fftw_destroy_plan((fftw_plan)fPlan);
fPlan = 0;
if (fOut)
fPlan = (void*)fftw_plan_dft_r2c(fNdim, fN, (Double_t*)fIn, (fftw_complex*)fOut,MapFlag(flags));
else
fPlan = (void*)fftw_plan_dft_r2c(fNdim, fN, (Double_t*)fIn, (fftw_complex*)fIn, MapFlag(flags));
}
void TFFTRealComplex::Transform()
{
if (fPlan){
fftw_execute((fftw_plan)fPlan);
}
else {
Error("Transform", "transform hasn't been initialised");
return;
}
}
void TFFTRealComplex::GetPoints(Double_t *data, Bool_t fromInput) const
{
if (fromInput){
for (Int_t i=0; i<fTotalSize; i++)
data[i] = ((Double_t*)fIn)[i];
} else {
Int_t realN = 2*Int_t(Double_t(fTotalSize)*(fN[fNdim-1]/2+1)/fN[fNdim-1]);
if (fOut){
for (Int_t i=0; i<realN; 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<realN; i++)
data[i] = ((Double_t*)fIn)[i];
}
}
}
Double_t TFFTRealComplex::GetPointReal(Int_t ipoint, Bool_t fromInput) const
{
if (fOut && !fromInput){
Warning("GetPointReal", "Output is complex. Only real part returned");
return ((fftw_complex*)fOut)[ipoint][0];
}
else
return ((Double_t*)fIn)[ipoint];
}
Double_t TFFTRealComplex::GetPointReal(const Int_t *ipoint, Bool_t fromInput) const
{
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){
Warning("GetPointReal", "Output is complex. Only real part returned");
return ((fftw_complex*)fOut)[ireal][0];
}
else
return ((Double_t*)fIn)[ireal];
}
void TFFTRealComplex::GetPointComplex(Int_t ipoint, Double_t &re, Double_t &im, Bool_t fromInput) const
{
if (fromInput){
re = ((Double_t*)fIn)[ipoint];
} else {
if (fNdim==1){
if (fOut){
if (ipoint<fN[0]/2+1){
re = ((fftw_complex*)fOut)[ipoint][0];
im = ((fftw_complex*)fOut)[ipoint][1];
} else {
re = ((fftw_complex*)fOut)[fN[0]-ipoint][0];
im = -((fftw_complex*)fOut)[fN[0]-ipoint][1];
}
} else {
if (ipoint<fN[0]/2+1){
re = ((Double_t*)fIn)[2*ipoint];
im = ((Double_t*)fIn)[2*ipoint+1];
} else {
re = ((Double_t*)fIn)[2*(fN[0]-ipoint)];
im = ((Double_t*)fIn)[2*(fN[0]-ipoint)+1];
}
}
}
else {
Int_t realN = 2*Int_t(Double_t(fTotalSize)*(fN[fNdim-1]/2+1)/fN[fNdim-1]);
if (ipoint>realN/2){
Error("GetPointComplex", "Illegal index value");
return;
}
if (fOut){
re = ((fftw_complex*)fOut)[ipoint][0];
im = ((fftw_complex*)fOut)[ipoint][1];
} else {
re = ((Double_t*)fIn)[2*ipoint];
im = ((Double_t*)fIn)[2*ipoint+1];
}
}
}
}
void TFFTRealComplex::GetPointComplex(const Int_t *ipoint, Double_t &re, Double_t &im, Bool_t fromInput) const
{
Int_t ireal = ipoint[0];
for (Int_t i=0; i<fNdim-2; i++)
ireal=fN[i+1]*ireal + ipoint[i+1];
ireal = (fN[fNdim-1]/2+1)*ireal + ipoint[fNdim-1];
if (fromInput){
re = ((Double_t*)fIn)[ireal];
return;
}
if (fNdim==1){
if (fOut){
if (ipoint[0] <fN[0]/2+1){
re = ((fftw_complex*)fOut)[ipoint[0]][0];
im = ((fftw_complex*)fOut)[ipoint[0]][1];
} else {
re = ((fftw_complex*)fOut)[fN[0]-ipoint[0]][0];
im = -((fftw_complex*)fOut)[fN[0]-ipoint[0]][1];
}
} else {
if (ireal <fN[0]/2+1){
re = ((Double_t*)fIn)[2*ipoint[0]];
im = ((Double_t*)fIn)[2*ipoint[0]+1];
} else {
re = ((Double_t*)fIn)[2*(fN[0]-ipoint[0])];
im = ((Double_t*)fIn)[2*(fN[0]-ipoint[0])+1];
}
}
}
else if (fNdim==2){
if (fOut){
if (ipoint[1]<fN[1]/2+1){
re = ((fftw_complex*)fOut)[ipoint[1]+(fN[1]/2+1)*ipoint[0]][0];
im = ((fftw_complex*)fOut)[ipoint[1]+(fN[1]/2+1)*ipoint[0]][1];
} else {
if (ipoint[0]==0){
re = ((fftw_complex*)fOut)[fN[1]-ipoint[1]][0];
im = -((fftw_complex*)fOut)[fN[1]-ipoint[1]][1];
} else {
re = ((fftw_complex*)fOut)[(fN[1]-ipoint[1])+(fN[1]/2+1)*(fN[0]-ipoint[0])][0];
im = -((fftw_complex*)fOut)[(fN[1]-ipoint[1])+(fN[1]/2+1)*(fN[0]-ipoint[0])][1];
}
}
} else {
if (ipoint[1]<fN[1]/2+1){
re = ((Double_t*)fIn)[2*(ipoint[1]+(fN[1]/2+1)*ipoint[0])];
im = ((Double_t*)fIn)[2*(ipoint[1]+(fN[1]/2+1)*ipoint[0])+1];
} else {
if (ipoint[0]==0){
re = ((Double_t*)fIn)[2*(fN[1]-ipoint[1])];
im = -((Double_t*)fIn)[2*(fN[1]-ipoint[1])+1];
} else {
re = ((Double_t*)fIn)[2*((fN[1]-ipoint[1])+(fN[1]/2+1)*(fN[0]-ipoint[0]))];
im = -((Double_t*)fIn)[2*((fN[1]-ipoint[1])+(fN[1]/2+1)*(fN[0]-ipoint[0]))+1];
}
}
}
}
else {
if (fOut){
re = ((fftw_complex*)fOut)[ireal][0];
im = ((fftw_complex*)fOut)[ireal][1];
} else {
re = ((Double_t*)fIn)[2*ireal];
im = ((Double_t*)fIn)[2*ireal+1];
}
}
}
Double_t* TFFTRealComplex::GetPointsReal(Bool_t fromInput) const
{
if (!fromInput){
Error("GetPointsReal", "Output array is complex");
return 0;
}
return (Double_t*)fIn;
}
void TFFTRealComplex::GetPointsComplex(Double_t *re, Double_t *im, Bool_t fromInput) const
{
Int_t nreal;
if (fOut && !fromInput){
nreal = Int_t(Double_t(fTotalSize)*(fN[fNdim-1]/2+1)/fN[fNdim-1]);
for (Int_t i=0; i<nreal; i++){
re[i] = ((fftw_complex*)fOut)[i][0];
im[i] = ((fftw_complex*)fOut)[i][1];
}
} else if (fromInput) {
for (Int_t i=0; i<fTotalSize; i++){
re[i] = ((Double_t *)fIn)[i];
im[i] = 0;
}
}
else {
nreal = 2*Int_t(Double_t(fTotalSize)*(fN[fNdim-1]/2+1)/fN[fNdim-1]);
for (Int_t i=0; i<nreal; i+=2){
re[i/2] = ((Double_t*)fIn)[i];
im[i/2] = ((Double_t*)fIn)[i+1];
}
}
}
void TFFTRealComplex::GetPointsComplex(Double_t *data, Bool_t fromInput) const
{
Int_t nreal;
if (fOut && !fromInput){
nreal = Int_t(Double_t(fTotalSize)*(fN[fNdim-1]/2+1)/fN[fNdim-1]);
for (Int_t i=0; i<nreal; i+=2){
data[i] = ((fftw_complex*)fOut)[i/2][0];
data[i+1] = ((fftw_complex*)fOut)[i/2][1];
}
} else if (fromInput){
for (Int_t i=0; i<fTotalSize; i+=2){
data[i] = ((Double_t*)fIn)[i/2];
data[i+1] = 0;
}
}
else {
nreal = 2*Int_t(Double_t(fTotalSize)*(fN[fNdim-1]/2+1)/fN[fNdim-1]);
for (Int_t i=0; i<nreal; i++)
data[i] = ((Double_t*)fIn)[i];
}
}
void TFFTRealComplex::SetPoint(Int_t ipoint, Double_t re, Double_t )
{
((Double_t *)fIn)[ipoint] = re;
}
void TFFTRealComplex::SetPoint(const Int_t *ipoint, Double_t re, Double_t )
{
Int_t ireal = ipoint[0];
for (Int_t i=0; i<fNdim-1; i++)
ireal=fN[i+1]*ireal + ipoint[i+1];
((Double_t*)fIn)[ireal]=re;
}
void TFFTRealComplex::SetPoints(const Double_t *data)
{
for (Int_t i=0; i<fTotalSize; i++){
((Double_t*)fIn)[i]=data[i];
}
}
void TFFTRealComplex::SetPointComplex(Int_t ipoint, TComplex &c)
{
((Double_t *)fIn)[ipoint]=c.Re();
}
void TFFTRealComplex::SetPointsComplex(const Double_t *re, const Double_t* )
{
for (Int_t i=0; i<fTotalSize; i++)
((Double_t *)fIn)[i] = re[i];
}
UInt_t TFFTRealComplex::MapFlag(Option_t *flag)
{
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;
}