//TODO: Deal with vectors Analysis::RetType Analysis_FFT::Analyze() { // Ensure input data sets have the same number of points. size_t maxsize_ = 0; std::vector<bool> skipSet(input_dsets_.size(), true); std::vector<bool>::iterator skip = skipSet.begin(); for (Array1D::const_iterator DS = input_dsets_.begin(); DS != input_dsets_.end(); ++DS, ++skip) { // Check for empty set if ( (*DS)->Empty() ) { mprintf("Warning: Set %s is empty, skipping.\n", (*DS)->legend() ); continue; } if ( maxsize_ == 0 ) maxsize_ = (*DS)->Size(); else if ( (*DS)->Size() != maxsize_ ) { mprintf("Warning: Set %s does not have same size (%u) as initial set (%u). Skipping.\n", (*DS)->legend(), (*DS)->Size(), maxsize_ ); continue; } *skip = false; } // Setup FFT PubFFT pubfft; pubfft.SetupFFTforN( maxsize_ ); //mprintf("DEBUG: FFT size is %i\n",pubfft.size()); // Set up complex number array ComplexArray data1( pubfft.size() ); double sr = 1.0 / dt_; // 1 / sampling interval, sampling rate (freq) double fnyquist = sr / 2.0; // Nyquist frequency double total_time = dt_ * (double)maxsize_; // Total time (fundamental period) double f0 = 1.0 / total_time; // Fundamental frequency (first harmonic) Dimension Xdim(0.0, f0, "Freq."); mprintf("\tReporting FFT magnitude, normalized by N/2.\n" "\tOnly data up to the Nyquist frequency will be used.\n"); mprintf("\tSampling rate= %f ps^-1, Nyquist freq.= %f ps^-1\n", sr, fnyquist); mprintf("\tPoints= %zu, Fundamental period= %f ps, fundamental freq.= %f ps^-1\n", maxsize_, total_time, f0); double norm = (double)maxsize_ / 2; skip = skipSet.begin(); Array1D::const_iterator dsout = output_dsets_.begin(); for (Array1D::const_iterator DS = input_dsets_.begin(); DS != input_dsets_.end(); ++DS, ++dsout, ++skip) { if (*skip) continue; mprintf("\t\tCalculating FFT for set %s\n", (*DS)->legend()); // Reset data1 so it is padded with zeros data1.PadWithZero(0); // Place data from DS in real spots in data1 int datasize = (*DS)->Size(); for (int i = 0; i < datasize; ++i) data1[i*2] = ((DataSet_1D*)(*DS))->Dval(i); // DEBUG //for (int i = 0; i < pubfft.size()*2; i+=2) // mprintf("\t\t\t%i FFTinR=%f FFTinI=%f\n",i/2,data1[i],data1[i+1]); // Perform FFT pubfft.Forward( data1 ); // Place real data from FFT in output Data up to the Nyquist frequency int i2 = 0; for (int i1 = 0; i1 < datasize; ++i1) { double freq = i1 * f0; if (freq > fnyquist) break; double magnitude = sqrt(data1[i2]*data1[i2] + data1[i2+1]*data1[i2+1]); magnitude /= norm; //mprintf("\t\t\tReal=%f Img=%f Mag=%f\n",data1[i2],data1[i2+1],magnitude); (*dsout)->Add( i1, &magnitude ); i2 += 2; } (*dsout)->SetDim(Dimension::X, Xdim); } return Analysis::OK; }
// Analysis_Wavelet::Analyze() Analysis::RetType Analysis_Wavelet::Analyze() { // Step 1 - Create a matrix that is #atoms rows by #frames - 1 cols, // where matrix(frame, atom) is the distance that atom has // travelled from the previous frame. // TODO: Implement this in Action_Matrix()? mprintf(" WAVELET:\n"); // First set up atom mask. if (coords_->Top().SetupIntegerMask( mask_ )) return Analysis::ERR; mask_.MaskInfo(); int natoms = mask_.Nselected(); int nframes = (int)coords_->Size(); if (natoms < 1 || nframes < 2) { mprinterr("Error: Not enough frames (%i) or atoms (%i) in '%s'\n", nframes, natoms, coords_->legend()); return Analysis::ERR; } Matrix<double> d_matrix; mprintf("\t%i frames, %i atoms, distance matrix will require %.2f MB\n", (double)d_matrix.sizeInBytes(nframes, natoms) / (1024.0*1024.0)); d_matrix.resize(nframes, natoms); // Get initial frame. Frame currentFrame, lastFrame; currentFrame.SetupFrameFromMask( mask_, coords_->Top().Atoms() ); lastFrame = currentFrame; coords_->GetFrame( 0, lastFrame, mask_ ); // Iterate over frames for (int frm = 1; frm != nframes; frm++) { coords_->GetFrame( frm, currentFrame, mask_ ); int idx = frm; // Position in distance matrix; start at column 'frame' for (int at = 0; at != natoms; at++, idx += nframes) // Distance of atom in currentFrame from its position in lastFrame. d_matrix[idx] = sqrt(DIST2_NoImage( currentFrame.XYZ(at), lastFrame.XYZ(at) )); //lastFrame = currentFrame; // TODO: Re-enable? } # ifdef DEBUG_WAVELET // DEBUG: Write matrix to file. CpptrajFile dmatrixOut; // DEBUG dmatrixOut.OpenWrite("dmatrix.dat"); Matrix<double>::iterator mval = d_matrix.begin(); for (int row = 0; row != natoms; row++) { for (int col = 0; col != nframes; col++) dmatrixOut.Printf("%g ", *(mval++)); dmatrixOut.Printf("\n"); } dmatrixOut.CloseFile(); # endif // Precompute some factors for calculating scaled wavelets. const double one_over_sqrt_N = 1.0 / sqrt(static_cast<double>( nframes )); std::vector<int> arrayK( nframes ); arrayK[0] = -1 * (nframes/2); for (int i = 1; i != nframes; i++) arrayK[i] = arrayK[i-1] + 1; # ifdef DEBUG_WAVELET mprintf("DEBUG: K:"); for (std::vector<int>::const_iterator kval = arrayK.begin(); kval != arrayK.end(); ++kval) mprintf(" %i", *kval); mprintf("\n"); # endif // Step 2 - Get FFT of wavelet for each scale. PubFFT pubfft; pubfft.SetupFFTforN( nframes ); mprintf("\tMemory required for scaled wavelet array: %.2f MB\n", (double)(2 * nframes * nb_ * sizeof(double)) / (1024 * 1024)); typedef std::vector<ComplexArray> WaveletArray; WaveletArray FFT_of_Scaled_Wavelets; FFT_of_Scaled_Wavelets.reserve( nb_ ); typedef std::vector<double> Darray; Darray scaleVector; scaleVector.reserve( nb_ ); Darray MIN( nb_ * 2 ); for (int iscale = 0; iscale != nb_; iscale++) { // Calculate and store scale factor. scaleVector.push_back( S0_ * pow(2.0, iscale * ds_) ); // Populate MIN array MIN[iscale ] = (0.00647*pow((correction_*scaleVector.back()),1.41344)+19.7527)*chival_; MIN[iscale+nb_] = correction_*scaleVector.back(); // Calculate scalved wavelet ComplexArray scaledWavelet; switch (wavelet_type_) { case W_MORLET: scaledWavelet = F_Morlet(arrayK, scaleVector.back()); break; case W_PAUL : scaledWavelet = F_Paul(arrayK, scaleVector.back()); break; case W_NONE : return Analysis::ERR; // Sanity check } # ifdef DEBUG_WAVELET PrintComplex("wavelet_before_fft", scaledWavelet); # endif // Perform FFT pubfft.Forward( scaledWavelet ); // Normalize scaledWavelet.Normalize( one_over_sqrt_N ); # ifdef DEBUG_WAVELET PrintComplex("wavelet_after_fft", scaledWavelet); # endif FFT_of_Scaled_Wavelets.push_back( scaledWavelet ); } # ifdef DEBUG_WAVELET mprintf("DEBUG: Scaling factors:"); for (Darray::const_iterator sval = scaleVector.begin(); sval != scaleVector.end(); ++sval) mprintf(" %g", *sval); mprintf("\n"); mprintf("DEBUG: MIN:"); for (int i = 0; i != nb_; i++) mprintf(" %g", MIN[i]); mprintf("\n"); # endif // Step 3 - For each atom, calculate the convolution of scaled wavelets // with rows (atom distance vs frame) via dot product of the // frequency domains, i.e. Fourier-transformed, followed by an // inverse FT. DataSet_MatrixFlt& OUT = static_cast<DataSet_MatrixFlt&>( *output_ ); mprintf("\tMemory required for output matrix: %.2f MB\n", (double)Matrix<float>::sizeInBytes(nframes, natoms)/(1024.0*1024.0)); OUT.Allocate2D( nframes, natoms ); // Should initialize to zero Matrix<double> MAX; mprintf("\tMemory required for Max array: %.2f MB\n", (double)MAX.sizeInBytes(nframes, natoms)/(1024.0*1024.0)); MAX.resize( nframes, natoms ); Darray magnitude( nframes ); // Scratch space for calculating magnitude across rows for (int at = 0; at != natoms; at++) { ComplexArray AtomSignal( nframes ); // Initializes to zero // Calculate the distance variance for this atom and populate the array. int midx = at * nframes; // Index into d_matrix int cidx = 0; // Index into AtomSignal double d_avg = 0.0; double d_var = 0.0; for (int frm = 0; frm != nframes; frm++, cidx += 2, midx++) { d_avg += d_matrix[midx]; d_var += (d_matrix[midx] * d_matrix[midx]); AtomSignal[cidx] = d_matrix[midx]; } d_var = (d_var - ((d_avg * d_avg) / (double)nframes)) / ((double)(nframes - 1)); # ifdef DEBUG_WAVELET mprintf("VARIANCE: %g\n", d_var); # endif double var_norm = 1.0 / d_var; // Calculate FT of atom signal pubfft.Forward( AtomSignal ); # ifdef DEBUG_WAVELET PrintComplex("AtomSignal", AtomSignal); # endif // Normalize AtomSignal.Normalize( one_over_sqrt_N ); // Calculate dot product of atom signal with each scaled FT wavelet for (int iscale = 0; iscale != nb_; iscale++) { ComplexArray dot = AtomSignal.TimesComplexConj( FFT_of_Scaled_Wavelets[iscale] ); // Inverse FT of dot product pubfft.Back( dot ); # ifdef DEBUG_WAVELET PrintComplex("InverseFT_Dot", dot); # endif // Chi-squared testing midx = at * nframes; cidx = 0; for (int frm = 0; frm != nframes; frm++, cidx += 2, midx++) { magnitude[frm] = (dot[cidx]*dot[cidx] + dot[cidx+1]*dot[cidx+1]) * var_norm; if (magnitude[frm] < MIN[iscale]) magnitude[frm] = 0.0; if (magnitude[frm] > MAX[midx]) { MAX[midx] = magnitude[frm]; //Indices[midx] = iscale OUT[midx] = (float)(correction_ * scaleVector[iscale]); } } # ifdef DEBUG_WAVELET mprintf("DEBUG: AbsoluteValue:"); for (Darray::const_iterator dval = magnitude.begin(); dval != magnitude.end(); ++dval) mprintf(" %g", *dval); mprintf("\n"); # endif } // END loop over scales } // END loop over atoms # ifdef DEBUG_WAVELET // DEBUG: Print MAX CpptrajFile maxmatrixOut; // DEBUG maxmatrixOut.OpenWrite("maxmatrix.dat"); for (int col = 0; col != nframes; col++) { for (int row = 0; row != natoms; row++) maxmatrixOut.Printf("%g ", MAX.element(col, row)); maxmatrixOut.Printf("\n"); } maxmatrixOut.CloseFile(); # endif return Analysis::OK; }