/** Given an array of already set up data sets (from e.g. input data files) * and optional X values, add the sets to this list if they do not exist * or append any existing sets. */ int DataSetList::AddOrAppendSets(std::string const& XlabelIn, Darray const& Xvals, DataListType const& Sets) { if (debug_ > 0) mprintf("DEBUG: Calling AddOrAppendSets for %zu sets, %zu X values, Xlabel= %s.\n", Sets.size(), Xvals.size(), XlabelIn.c_str()); if (Sets.empty()) return 0; // No error for now. // If no X label assume 'Frame' for backwards compat. std::string Xlabel; if (XlabelIn.empty()) Xlabel.assign("Frame"); else Xlabel = XlabelIn; Dimension Xdim; // First determine if X values increase monotonically with a regular step bool isMonotonic = true; double xstep = 1.0; if (Xvals.size() > 1) { xstep = (Xvals.back() - Xvals.front()) / (double)(Xvals.size() - 1); for (Darray::const_iterator X = Xvals.begin()+2; X != Xvals.end(); ++X) if ((*X - *(X-1)) - xstep > Constants::SMALL) { isMonotonic = false; break; } // Set dim even for non-monotonic sets so Label is correct. FIXME is this ok? Xdim = Dimension( Xvals.front(), xstep, Xlabel ); } else // No X values. set generic X dim. Xdim = Dimension(1.0, 1.0, Xlabel); if (debug_ > 0) { mprintf("DEBUG: xstep %g xmin %g\n", Xdim.Step(), Xdim.Min()); if (isMonotonic) mprintf("DEBUG: Xdim is monotonic.\n"); } for (const_iterator ds = Sets.begin(); ds != Sets.end(); ++ds) { if (*ds == 0) continue; // TODO: Warn about blanks? if (debug_ > 0) mprintf("DEBUG: AddOrAppend set '%s'", (*ds)->legend()); if (isMonotonic) (*ds)->SetDim(Dimension::X, Xdim); DataSet* existingSet = CheckForSet( (*ds)->Meta() ); if (existingSet == 0) { // New set. If set is scalar 1D but X values are not monotonic, // convert to XY mesh if necessary. if ( !isMonotonic && (*ds)->Group() == DataSet::SCALAR_1D && (*ds)->Type() != DataSet::XYMESH ) { DataSet* xyptr = AddSet( DataSet::XYMESH, (*ds)->Meta() ); if (xyptr == 0) { mprinterr("Error: Could not convert set %s to XY mesh.\n", (*ds)->legend()); continue; // TODO exit instead? } if ( (*ds)->Size() != Xvals.size() ) { // Sanity check mprinterr("Error: # of X values does not match set %s size.\n", (*ds)->legend()); continue; } DataSet_1D const& set = static_cast<DataSet_1D const&>( *(*ds) ); DataSet_Mesh& xy = static_cast<DataSet_Mesh&>( *xyptr ); for (unsigned int i = 0; i != set.Size(); i++) xy.AddXY( Xvals[i], set.Dval(i) ); xy.SetDim(Dimension::X, Xdim); if (debug_ > 0) mprintf(", New set, converted to XY-MESH\n"); // Free memory since set has now been converted. delete *ds; } else { // No conversion. Just add. (*ds)->SetDim(Dimension::X, Xdim); AddSet( *ds ); if (debug_ > 0) mprintf(", New set\n"); } } else { if (debug_ > 0) mprintf(", appending to existing set\n"); // Set exists. Try to append this set to existing set. bool canAppend = true; if ( (*ds)->Group() == DataSet::GENERIC ) { // For GENERIC sets, base Type must match. // TODO: Should this logic be in DataSets? if ( (*ds)->Type() != existingSet->Type() ) canAppend = false; } else { // For non-GENERIC sets, Group must match if ( (*ds)->Group() != existingSet->Group() ) canAppend = false; } if (!canAppend) mprinterr("Error: Cannot append set of type %s to set of type %s\n", DataArray[(*ds)->Type()].Description, DataArray[existingSet->Type()].Description); // If cannot append or attempt to append fails, rename and add as new set. if (!canAppend || existingSet->Append( *ds )) { // TODO Dimension check? if (canAppend) mprintf("Warning: Append currently not supported for type %s\n", DataArray[existingSet->Type()].Description); MetaData md = (*ds)->Meta(); md.SetName( GenerateDefaultName("X") ); mprintf("Warning: Renaming %s to %s\n", (*ds)->Meta().PrintName().c_str(), md.PrintName().c_str()); (*ds)->SetMeta( md ); AddSet( *ds ); } else // Set was appended to existing set; memory can be freed. delete *ds; } } // END loop over input sets return 0; }
// Analysis_TI::Calc_Increment() int Analysis_TI::Calc_Increment() { // Determine max points if not given. int maxpts = avg_max_; if (maxpts == -1) { for (unsigned int idx = 0; idx != input_dsets_.size(); idx++) { DataSet_1D const& ds = static_cast<DataSet_1D const&>( *(input_dsets_[idx]) ); if (maxpts == -1) maxpts = (int)ds.Size(); else if (maxpts != (int)ds.Size()) { mprintf("Warning: # points in '%s' (%zu) is different than %i.\n", ds.legend(), ds.Size(), maxpts); maxpts = std::min( maxpts, (int)ds.Size() ); mprintf("Warning: Will only use %i points.\n", maxpts); } } } if (maxpts < 1) { mprinterr("Error: Max points to use is < 1.\n"); return 1; } if (avg_skip_ >= maxpts) { mprinterr("Error: 'avgskip' (%i) > max (%i).\n", avg_skip_, maxpts); return 1; } // sum: Hold the results of integration for each curve (increment) Darray sum; // points: Hold point values at which each avg is being calculated Iarray points; // Loop over input data sets. for (unsigned int idx = 0; idx != input_dsets_.size(); idx++) { DataSet_1D const& ds = static_cast<DataSet_1D const&>( *(input_dsets_[idx]) ); if (CheckSet(ds)) return 1; // Calculate averages for each increment Darray avg; Iarray increments; int count = 0; int endpt = maxpts -1; double currentSum = 0.0; if (debug_ > 0) mprintf("DEBUG: Lambda %g\n", xval_[idx]); for (int pt = avg_skip_; pt != maxpts; pt++) { currentSum += ds.Dval(pt); count++; if (count == avg_increment_ || pt == endpt) { avg.push_back( currentSum / ((double)(pt - avg_skip_ + 1)) ); increments.push_back(pt+1); if (debug_ > 0) mprintf("DEBUG:\t\tAvg from %i to %i: %g\n", avg_skip_+1, pt+1, avg.back()); count = 0; } } if (sum.empty()) { sum.resize(avg.size()); points = increments; } else if (sum.size() != avg.size()) { mprinterr("Error: Different # of increments for set '%s'; got %zu, expected %zu.\n", ds.legend(), avg.size(), sum.size()); return 1; } // Create increment curve data sets if (curve_.empty()) { MetaData md(dAout_->Meta().Name(), "TIcurve"); for (unsigned int j = 0; j != avg.size(); j++) { md.SetIdx( increments[j] ); DataSet* ds = masterDSL_->AddSet(DataSet::XYMESH, md); if (ds == 0) return Analysis::ERR; ds->ModifyDim(Dimension::X).SetLabel("Lambda"); ds->SetLegend( md.Name() + "_Skip" + integerToString(increments[j]) ); if (curveout_ != 0) curveout_->AddDataSet( ds ); curve_.push_back( ds ); } } for (unsigned int j = 0; j != avg.size(); j++) { DataSet_Mesh& CR = static_cast<DataSet_Mesh&>( *(curve_[j]) ); CR.AddXY(xval_[idx], avg[j]); if (mode_ == GAUSSIAN_QUAD) sum[j] += (wgt_[idx] * avg[j]); } } // END loop over data sets if (mode_ == TRAPEZOID) Integrate_Trapezoid(sum); // Store final integration values DataSet_Mesh& DA = static_cast<DataSet_Mesh&>( *dAout_ ); DA.ModifyDim(Dimension::X).SetLabel("Point"); for (unsigned int j = 0; j != points.size(); j++) DA.AddXY(points[j], sum[j]); return 0; }
// 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; }