/** Print atoms for which the cumulative energy satisfies the given * cutoffs. Also create MOL2 files containing those atoms. */ int Action_Pairwise::PrintCutAtoms(Frame const& frame, int frameNum, EoutType ctype, Darray const& Earray, double cutIn) { AtomMask CutMask; // Hold atoms that satisfy the cutoff Darray CutCharges; // Hold evdw/eelec corresponding to CutMask atoms. if (Eout_ != 0) { if (nb_calcType_==COMPARE_REF) Eout_->Printf("\tPAIRWISE: Cumulative d%s:", CalcString[ctype]); else Eout_->Printf("\tPAIRWISE: Cumulative %s:", CalcString[ctype]); Eout_->Printf(" %s < %.4f, %s > %.4f\n", CalcString[ctype], -cutIn, CalcString[ctype], cutIn); } for (AtomMask::const_iterator atom = Mask0_.begin(); atom != Mask0_.end(); ++atom) { if (fabs(Earray[*atom]) > cutIn) { if (Eout_ != 0) Eout_->Printf("\t\t%6i@%s: %12.4f\n", *atom+1, (*CurrentParm_)[*atom].c_str(), Earray[*atom]); CutMask.AddAtom(*atom); CutCharges.push_back(Earray[*atom]); } } // Write mol2 with atoms satisfying cutoff if (!mol2Prefix_.empty() && !CutMask.None()) { if (WriteCutFrame(frameNum, *CurrentParm_, CutMask, CutCharges, frame, mol2Prefix_ + CutName[ctype])) return 1; } return 0; }
// Action_Matrix::FillMassArray() Action_Matrix::Darray Action_Matrix::FillMassArray(Topology const& currentParm, AtomMask const& mask) const { Darray mass; mass.reserve( mask.Nselected() ); for (AtomMask::const_iterator atom = mask.begin(); atom != mask.end(); ++atom) mass.push_back( currentParm[ *atom ].Mass() ); return mass; }
// Analysis_TI::Calc_Nskip() int Analysis_TI::Calc_Nskip() { // sum: Hold the results of integration for each curve (skip value) Darray sum(nskip_.size(), 0.0); // lastSkipPoint: Points after which averages can be recorded Iarray lastSkipPoint; for (Iarray::const_iterator it = nskip_.begin(); it != nskip_.end(); ++it) lastSkipPoint.push_back( *it - 1 ); // 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; // Determine if skip values are valid for this set. Darray Npoints; // Number of points after skipping for (Iarray::const_iterator it = nskip_.begin(); it != nskip_.end(); ++it) { int np = (int)ds.Size() - *it; if (np < 1) { mprinterr("Error: Skipped too many points (set '%s' size is %zu)\n",ds.legend(),ds.Size()); return 1; } Npoints.push_back((double)np); } // Calculate averages for each value of skip Darray avg(nskip_.size(), 0.0); for (int i = 0; i != (int)ds.Size(); i++) { for (unsigned int j = 0; j != nskip_.size(); j++) if (i > lastSkipPoint[j]) avg[j] += ds.Dval( i ); } // Store average DV/DL for each value of skip for (unsigned int j = 0; j != nskip_.size(); j++) { avg[j] /= Npoints[j]; if (debug_ > 0) mprintf("\t%s Skip= %i <DV/DL>= %g\n", ds.legend(), nskip_[j], avg[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 input data sets if (mode_ == TRAPEZOID) Integrate_Trapezoid(sum); // Store final TI integration values. DataSet_Mesh& DA = static_cast<DataSet_Mesh&>( *dAout_ ); DA.ModifyDim(Dimension::X).SetLabel("PtsSkipped"); for (unsigned int j = 0; j != nskip_.size(); j++) DA.AddXY(nskip_[j], sum[j]); return 0; }
Analysis::RetType Analysis_TI::Analyze() { Darray sum(nskip_.size(), 0.0); DataSet_Mesh& DA = static_cast<DataSet_Mesh&>( *dAout_ ); Iarray lastSkipPoint; // Points after which averages can be recorded for (Iarray::const_iterator it = nskip_.begin(); it != nskip_.end(); ++it) lastSkipPoint.push_back( *it - 1 ); // Run for multiple skip values, helps test convergences. for (unsigned int idx = 0; idx != input_dsets_.size(); idx++) { DataSet_1D const& ds = static_cast<DataSet_1D const&>( *(input_dsets_[idx]) ); if (ds.Size() < 1) { mprinterr("Error: Set '%s' is empty.\n", ds.legend()); return Analysis::ERR; } // Determine if skip values are valid for this set. Darray Npoints; // Number of points after skipping for (Iarray::const_iterator it = nskip_.begin(); it != nskip_.end(); ++it) { int np = (int)ds.Size() - *it; if (np < 1) { mprinterr("Error: Skipped too many points (set '%s' size is %zu)\n",ds.legend(),ds.Size()); return Analysis::ERR; } Npoints.push_back((double)np); } // Calculate averages for each value of skip Darray avg(nskip_.size(), 0.0); for (int i = 0; i != (int)ds.Size(); i++) { for (unsigned int j = 0; j != nskip_.size(); j++) if (i > lastSkipPoint[j]) avg[j] += ds.Dval( i ); } // Store average DV/DL for each value of skip for (unsigned int j = 0; j != nskip_.size(); j++) { avg[j] /= Npoints[j]; //mprintf("\t<DV/DL>=%g\n", avg); DataSet_Mesh& CR = static_cast<DataSet_Mesh&>( *(curve_[j]) ); CR.AddXY(quad_[idx], avg[j]); sum[j] += (wgt_[idx] * avg[j]); } } for (unsigned int j = 0; j != nskip_.size(); j++) DA.AddXY(nskip_[j], sum[j]); return Analysis::OK; }
// 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; }
// Exec_SortEnsembleData::Sort_pH_Data() int Exec_SortEnsembleData::Sort_pH_Data(DataSetList const& setsToSort, DataSetList& OutputSets, unsigned int maxFrames) const { // Cast sets back to DataSet_PHREMD typedef std::vector<DataSet_PHREMD*> Parray; Parray PHsets; for (DataSetList::const_iterator ds = setsToSort.begin(); ds != setsToSort.end(); ++ds) PHsets.push_back( (DataSet_PHREMD*)*ds ); // Gather initial pH data values, ensure no duplicates typedef std::vector<double> Darray; Darray pHvalues; # ifdef MPI pHvalues.resize( Parallel::Ensemble_Size() ); Darray phtmp; for (Parray::const_iterator ds = PHsets.begin(); ds != PHsets.end(); ++ds) phtmp.push_back( (*ds)->Initial_pH() ); if (comm_.AllGather(&phtmp[0], phtmp.size(), MPI_DOUBLE, &pHvalues[0])) { rprinterr("Error: Gathering pH values.\n"); return 1; } # else for (Parray::const_iterator ds = PHsets.begin(); ds != PHsets.end(); ++ds) pHvalues.push_back( (*ds)->Initial_pH() ); # endif ReplicaInfo::Map<double> pH_map; if (pH_map.CreateMap( pHvalues )) { rprinterr("Error: Duplicate pH value detected (%.2f) in ensemble.\n", pH_map.Duplicate()); return 1; } Darray sortedPH; mprintf("\tInitial pH values:"); for (ReplicaInfo::Map<double>::const_iterator ph = pH_map.begin(); ph != pH_map.end(); ++ph) { mprintf(" %6.2f", ph->first); sortedPH.push_back( ph->first ); } mprintf("\n"); // Create sets to hold sorted pH values. Create a set for each pH value // and each residue. Final output sets will be PH0R0, PH0R1, PH1R0, ... // TODO check that residue info all the same DataSet_PHREMD::Rarray const& Residues = PHsets[0]->Residues(); int defaultState = 0; # ifdef MPI if ( PHsets[0]->Type() == DataSet::PH_IMPL) defaultState = -1; # endif if (debug_ > 0) rprintf("DEBUG: Sorting %u frames for %zu sets, %zu pH values.\n", maxFrames, PHsets.size(), sortedPH.size()); for (unsigned int idx = 0; idx != sortedPH.size(); idx++) { OutputSets.SetEnsembleNum( idx ); for (unsigned int res = 0; res != Residues.size(); ++res) { MetaData md(PHsets[0]->Meta().Name(), Residues[res].Name().Truncated(), Residues[res].Num()); DataSet_pH* out = (DataSet_pH*)OutputSets.AddSet( DataSet::PH, md ); if (out==0) return 1; //out->SetLegend( "pH " + doubleToString( sortedPH[idx] ) ); out->Set_Solvent_pH( sortedPH[idx] ); out->SetResidueInfo( Residues[res] ); out->SetTimeValues(PHsets[0]->Time()); out->Resize( maxFrames, defaultState ); } } // --------------------------------------------- if ( PHsets[0]->Type() == DataSet::PH_EXPL) { // Loop over unsorted sets for (Parray::const_iterator ds = PHsets.begin(); ds != PHsets.end(); ++ds) { DataSet_PHREMD_Explicit* in = (DataSet_PHREMD_Explicit*)*ds; unsigned int phidx = 0; for (unsigned int n = 0; n < maxFrames; n++) { float phval = in->pH_Values()[n]; int setidx = pH_map.FindIndex( phval ) * Residues.size(); //rprintf("DEBUG: %6u Set %10s pH= %6.2f going to %2i\n", n+1, in->legend(), phval, idx); //mflush(); for (unsigned int res = 0; res < in->Residues().size(); res++, setidx++, phidx++) { DataSet_pH* out = (DataSet_pH*)OutputSets[setidx]; //if (res == 0 && idx == 0) { // rprintf("DEBUG: Frame %3u res %2u State %2i pH %6.2f\n", // n, res, in->Res(res).State(n), phval); // mflush(); //} out->SetState(n, in->ResStates()[phidx], in->RecordType(n)); } } } // END loop over unsorted sets # ifdef MPI // Now we need to reduce down each set onto the thread where it belongs. if (Parallel::World().Size() > 1) { for (int idx = 0; idx != (int)OutputSets.size(); idx++) { DataSet_pH* out = (DataSet_pH*)OutputSets[idx]; int ensembleRank = Parallel::MemberEnsCommRank( out->Meta().EnsembleNum() ); //rprintf("DEBUG: Reduce set %s to rank %i\n", out->legend(), ensembleRank); out->Reduce( comm_, ensembleRank ); } // Remove sets that do not belong on this rank for (int idx = (int)OutputSets.size() - 1; idx > -1; idx--) { DataSet* out = OutputSets[idx]; int ensembleRank = Parallel::MemberEnsCommRank( out->Meta().EnsembleNum() ); if (ensembleRank != comm_.Rank()) { //rprintf("DEBUG: Remove set %s (%i) from rank %i\n", out->legend(), // idx, comm_.Rank()); OutputSets.RemoveSet( out ); } } } # endif // --------------------------------------------- } else if ( PHsets[0]->Type() == DataSet::PH_IMPL) { # ifdef MPI typedef std::vector<int> Iarray; typedef std::vector<Iarray> Iarray2; typedef std::vector<bool> Barray; // True if I have this pH value Barray isMyPh( sortedPH.size(), false ); // Which rank in ensemble has which pH Iarray pHrank( sortedPH.size(), 0 ); for (int phidx = 0; phidx != (int)sortedPH.size(); phidx++) { int ensembleRank = Parallel::MemberEnsCommRank( phidx ); pHrank[phidx] = ensembleRank; isMyPh[phidx] = (ensembleRank == comm_.Rank()); } // DEBUG for (unsigned int idx = 0; idx != pHrank.size(); idx++) mprintf("\tpH %6.2f on rank %i\n", sortedPH[idx], pHrank[idx]); // Hold frame-residue-state for each pH not on this rank. Iarray2 FrmResState( sortedPH.size() ); // Loop over unsorted sets for (Parray::const_iterator ds = PHsets.begin(); ds != PHsets.end(); ++ds) { DataSet_PHREMD_Implicit* in = (DataSet_PHREMD_Implicit*)*ds; // Loop over frames for (unsigned int n = 0; n < maxFrames; n++) { DataSet_PHREMD_Implicit::Record const& Rec = in->Records()[n]; float phval = Rec.pH(); int phidx = pH_map.FindIndex( phval ); if (isMyPh[phidx]) { // This pH belongs to me. Set value. int setidx = phidx * Residues.size(); if (Rec.RecType() == Cph::FULL_RECORD) { // Info for all residues for (unsigned int res = 0; res < in->Residues().size(); res++, setidx++) ((DataSet_pH*)OutputSets[setidx])->SetState(n, Rec.ResStates()[res], Rec.RecType()); } else if (Rec.RecType() > -1) { // Info for single residue, record type for all residues //rprintf("\tSetting my pH %6.2f frame %8i state %2i idx %6i res %6i '%s'\n", sortedPH[phidx], n, Rec.ResStates()[0], setidx, Rec.RecType(), OutputSets[setidx+Rec.RecType()]->legend()); for (int res = 0; res < (int)in->Residues().size(); res++, setidx++) if (res == Rec.RecType()) ((DataSet_pH*)OutputSets[setidx])->SetState(n, Rec.ResStates()[0], Rec.RecType()); else ((DataSet_pH*)OutputSets[setidx])->SetRecType(n, Rec.RecType()); } } else { // This pH belongs to another rank. Save it. if (Rec.RecType() > -1) { // Info for a single residue present FrmResState[phidx].push_back( n ); FrmResState[phidx].push_back( Rec.RecType() ); FrmResState[phidx].push_back( Rec.ResStates()[0] ); } else { // Info for all residues present FrmResState[phidx].push_back( n ); FrmResState[phidx].push_back( Rec.RecType() ); for (unsigned int res = 0; res < in->Residues().size(); res++) FrmResState[phidx].push_back( Rec.ResStates()[res] ); } } } // END loop over frames } // END loop over sets // DEBUG /* comm_.Barrier(); for (int rank = 0; rank < comm_.Size(); rank++) { if (rank == comm_.Rank()) { for (unsigned int phidx = 0; phidx != sortedPH.size(); phidx++) { rprintf("DEBUG: pH %6.2f: %8s %6s %2s\n", sortedPH[phidx], "Frm", "Res", "St"); Iarray const& FRS = FrmResState[phidx]; unsigned int idx = 0; while (idx < FRS.size()) { int rec = FRS[idx+1]; if (rec > -1) { rprintf(" %8i %6i %2i\n", FRS[idx], rec, FRS[idx+2]); idx += 3; } else { rprintf(" %8i %6i All Residues\n", FRS[idx], rec); idx += (2 + Residues.size()); } } } } comm_.Barrier(); } */ // Communicate states to other ranks typedef std::vector<unsigned int> Uarray; Uarray sizeOnRank( comm_.Size() ); for (unsigned int phidx = 0; phidx != sortedPH.size(); phidx++) { // Each rank says how many frames of this pH they have collected and // send to rank the pH belongs to. unsigned int nph = FrmResState[phidx].size(); comm_.Gather(&nph, 1, MPI_UNSIGNED, &sizeOnRank[0], pHrank[phidx]); if (pHrank[phidx] == comm_.Rank()) { // This pH belongs to me. I should have no frames at this pH. if (sizeOnRank[comm_.Rank()] > 0) { rprinterr("Internal Error: Rank has frames to communicate at its pH\n"); Parallel::Abort(1); } unsigned int totalSize = 0; for (unsigned int idx = 0; idx != sizeOnRank.size(); idx++) { totalSize += sizeOnRank[idx]; //rprintf("DEBUG: Rank %4u has %8u frames of pH %6.2f\n", // idx, sizeOnRank[idx], sortedPH[phidx]); } //rprintf("DEBUG: Total incoming size: %u\n", totalSize); FrmResState[phidx].resize( totalSize ); // Receive state info for this pH from other ranks int* frsArray = &(FrmResState[phidx][0]); for (int rank = 0; rank != comm_.Size(); rank++) { if (rank != comm_.Rank()) { comm_.Recv(frsArray, sizeOnRank[rank], MPI_INT, rank, 1600+rank); frsArray += sizeOnRank[rank]; } } } else { // This pH belongs to another rank. Send my info there. int* frsArray = &(FrmResState[phidx][0]); comm_.Send(frsArray, nph, MPI_INT, pHrank[phidx], 1600+comm_.Rank()); } comm_.Barrier(); } // Fill in state info std::vector<DataSet*> ToRemove; for (unsigned int phidx = 0; phidx != sortedPH.size(); phidx++) { int setidx = phidx * Residues.size(); if (pHrank[phidx] == comm_.Rank()) { Iarray const& FRS = FrmResState[phidx]; // This pH belongs to me. Fill in the information received from // other ranks. unsigned int idx = 0; while (idx < FRS.size()) { int rec = FRS[idx+1]; if (rec > -1) { // Info for single residue, record type for all residues //rprintf("\tSetting pH %6.2f frame %8i state %2i idx %6i res %6i '%s'\n", sortedPH[phidx], FRS[idx], FRS[idx+2], setidx, rec, OutputSets[setidx+rec]->legend()); for (int res = 0; res != (int)Residues.size(); res++) { DataSet_pH* out = (DataSet_pH*)OutputSets[setidx + res]; if (rec == res) out->SetState( FRS[idx], FRS[idx+2], rec ); else out->SetRecType( FRS[idx], rec ); } idx += 3; } else { //rprintf(" %8i %6i All Residues\n", FRS[idx], rec); int frm = FRS[idx]; idx += 2; for (unsigned int res = 0; res != Residues.size(); res++, idx++) { DataSet_pH* out = (DataSet_pH*)OutputSets[setidx + res]; out->SetState( frm, FRS[idx], rec ); } } } // Fill in any remaining data. FIXME safe to assume first frame is set? for (unsigned int res = 0; res != Residues.size(); res++) { DataSet_pH* out = (DataSet_pH*)OutputSets[setidx + res]; for (unsigned int n = 1; n < maxFrames; n++) if (out->State(n) == -1) out->SetState(n, out->State(n-1), out->RecordType(n)); } } else { // This pH does not belong to me. Mark associated data sets to be removed. for (unsigned int res = 0; res != Residues.size(); res++) ToRemove.push_back( OutputSets[setidx + res] ); } } // Remove data sets that do not belong to me. for (std::vector<DataSet*>::reverse_iterator it = ToRemove.rbegin(); it != ToRemove.rend(); ++it) { //rprintf("DEBUG: '%s' does not belong to me.\n", (*it)->legend()); OutputSets.RemoveSet( *it ); } # else /* if not MPI */ // Loop over frames for (unsigned int n = 0; n < maxFrames; n++) { // Loop over unsorted sets for (Parray::const_iterator ds = PHsets.begin(); ds != PHsets.end(); ++ds) { DataSet_PHREMD_Implicit* in = (DataSet_PHREMD_Implicit*)*ds; DataSet_PHREMD_Implicit::Record const& Rec = in->Records()[n]; float phval = Rec.pH(); int setidx = pH_map.FindIndex( phval ) * Residues.size(); if (Rec.RecType() == Cph::FULL_RECORD) { for (unsigned int res = 0; res < in->Residues().size(); res++, setidx++) { DataSet_pH* out = (DataSet_pH*)OutputSets[setidx]; //if (res == 0 && idx == 0) { // rprintf("DEBUG: Frame %3u res %2u State %2i pH %6.2f\n", // n, res, in->Res(res).State(n), phval); // mflush(); //} out->SetState(n, Rec.ResStates()[res], Rec.RecType()); } } else { for (int res = 0; res < (int)in->Residues().size(); res++, setidx++) { DataSet_pH* out = (DataSet_pH*)OutputSets[setidx]; if (res == Rec.RecType()) out->SetState(n, Rec.ResStates()[0], Rec.RecType()); else // State for this residue not recorded - use previous state. // Should be fine since first state always has all residues. out->SetState(n, out->State(n-1), Rec.RecType()); } } } // END loop over unsorted sets } // END loop over frames # endif /* MPI */ // --------------------------------------------- } else { return 1; // Sanity check } 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; }