// ============================================================================= // ----- RepName Class --------------------------------------------------------- // RepName CONSTRUCTOR File::RepName::RepName(FileName const& fname, int debugIn) : extChar_('.') { if (debugIn > 1) mprintf("\tREMDTRAJ: FileName=[%s]\n", fname.full()); if ( fname.Ext().empty() ) { mprinterr("Error: Traj %s has no numerical extension, required for automatic\n" "Error: detection of replica trajectories. Expected filename format is\n" "Error: <Prefix>.<#> (with optional compression extension), examples:\n" "Error: Rep.traj.nc.000, remd.x.01.gz etc.\n", fname.base()); return; } // Split off everything before replica extension size_t found = fname.Full().rfind( fname.Ext() ); Prefix_.assign( fname.Full().substr(0, found) ); ReplicaExt_.assign( fname.Ext() ); // This should be the numeric extension // Remove leading '.' if (ReplicaExt_[0] == '.') ReplicaExt_.erase(0,1); CompressExt_.assign( fname.Compress() ); if (debugIn > 1) { mprintf("\tREMDTRAJ: Prefix=[%s], #Ext=[%s], CompressExt=[%s]\n", Prefix_.c_str(), ReplicaExt_.c_str(), CompressExt_.c_str()); } // CHARMM replica numbers are format <name>_<num> if ( !validInteger(ReplicaExt_) ) { size_t uscore = fname.Full().rfind('_'); if (uscore != std::string::npos) { Prefix_.assign( fname.Full().substr(0, uscore) ); ReplicaExt_.assign( fname.Full().substr(uscore+1) ); extChar_ = '_'; if (debugIn > 0) mprintf("\tREMDTRAJ: CHARMM style replica names detected, prefix='%s' ext='%s'\n", Prefix_.c_str(), ReplicaExt_.c_str()); } } // Check that the numerical extension is valid. if ( !validInteger(ReplicaExt_) ) { mprinterr("Error: Replica extension [%s] is not an integer.\n", ReplicaExt_.c_str()); Prefix_.clear(); // Empty Prefix_ indicates error. return; } ExtWidth_ = (int)ReplicaExt_.size(); if (debugIn > 1) mprintf("\tREMDTRAJ: Numerical Extension width=%i\n", ExtWidth_); // Store lowest replica number lowestRepnum_ = convertToInteger( ReplicaExt_ ); // TODO: Do not allow negative replica numbers? if (debugIn > 1) mprintf("\tREMDTRAJ: index of first replica = %i\n", lowestRepnum_); }
int DataIO_XVG::ReadData(FileName const& fname, DataSetList& datasetlist, std::string const& dsname) { std::vector<std::string> Legends; BufferedLine infile; if (infile.OpenFileRead( fname )) return 1; const char* ptr = infile.Line(); if (ptr == 0) return 1; // Skip any comments while (ptr != 0 && ptr[0] == '#') ptr = infile.Line(); // Try to get set legends while (ptr != 0 && ptr[0] == '@') { ArgList line(ptr, " \t"); if (line.Nargs() > 3 && line[1][0] == 's') { std::string legend = line.GetStringKey("legend"); if (!legend.empty()) { // Spaces will cause issues with data set selection. for (std::string::iterator s = legend.begin(); s != legend.end(); ++s) if (*s == ' ') *s = '_'; Legends.push_back( legend ); } } ptr = infile.Line(); } if (Legends.empty()) { mprinterr("Error: No set legends found in XVG file.\n"); return 1; } if (ptr == 0) { mprinterr("Error: No data in XVG file.\n"); return 1; } // Create 1 data set for each legend DataSetList::DataListType inputSets; for (unsigned int i = 0; i != Legends.size(); i++) { MetaData md( dsname, i ); md.SetLegend( Legends[i] ); DataSet_double* ds = new DataSet_double(); if (ds == 0) return 1; ds->SetMeta( md ); inputSets.push_back( ds ); } mprintf("\t%s has %zu columns of data.\n", fname.base(), inputSets.size()); // Should now be positioned at first line of data. Assume first column is time values. DataSetList::Darray Xvals; int expectedCols = (int)inputSets.size() + 1; while (ptr != 0) { int ncols = infile.TokenizeLine(" \t"); if (ncols != expectedCols) mprinterr("Error: Line %i: %i columns != expected # cols %i\n", infile.LineNumber(), ncols, expectedCols); else { Xvals.push_back( atof( infile.NextToken() ) ); for (unsigned int i = 0; i != inputSets.size(); i++) ((DataSet_double*)inputSets[i])->AddElement( atof( infile.NextToken() ) ); } ptr = infile.Line(); } infile.CloseFile(); return (datasetlist.AddOrAppendSets( "", Xvals, inputSets )); }
// Action_Spam::init() Action::RetType Action_Spam::Init(ArgList& actionArgs, TopologyList* PFL, DataSetList* DSL, DataFileList* DFL, int debugIn) { // Always use imaged distances InitImaging(true); // This is needed everywhere in this function scope FileName filename; // See if we're doing pure water. If so, we don't need a peak file purewater_ = actionArgs.hasKey("purewater"); if (purewater_) { // We still need the cutoff double cut = actionArgs.getKeyDouble("cut", 12.0); cut2_ = cut * cut; doublecut_ = 2 * cut; onecut2_ = 1 / cut2_; // See if we write to a data file datafile_ = actionArgs.GetStringKey("out"); // Generate the data set name, and hold onto the master data set list std::string ds_name = actionArgs.GetStringKey("name"); if (ds_name.empty()) ds_name = myDSL_.GenerateDefaultName("SPAM"); // We only have one data set averaging over every water. Add it here myDSL_.AddSet(DataSet::DOUBLE, ds_name, NULL); solvname_ = actionArgs.GetStringKey("solv"); if (solvname_.empty()) solvname_ = std::string("WAT"); }else { // Get the file name with the peaks defined in it filename.SetFileName( actionArgs.GetStringNext() ); if (filename.empty() || !File::Exists(filename)) { mprinterr("Spam: Error: Peak file [%s] does not exist!\n", filename.full()); return Action::ERR; } // Get the remaining optional arguments solvname_ = actionArgs.GetStringKey("solv"); if (solvname_.empty()) solvname_ = std::string("WAT"); reorder_ = actionArgs.hasKey("reorder"); bulk_ = actionArgs.getKeyDouble("bulk", 0.0); double cut = actionArgs.getKeyDouble("cut", 12.0); cut2_ = cut * cut; doublecut_ = 2 * cut; onecut2_ = 1 / cut2_; std::string infoname = actionArgs.GetStringKey("info"); if (infoname.empty()) infoname = std::string("spam.info"); infofile_ = DFL->AddCpptrajFile(infoname, "SPAM info"); if (infofile_ == 0) return Action::ERR; // The default maskstr is the Oxygen atom of the solvent summaryfile_ = actionArgs.GetStringKey("summary"); // Divide site size by 2 to make it half the edge length (or radius) site_size_ = actionArgs.getKeyDouble("site_size", 2.5) / 2.0; sphere_ = actionArgs.hasKey("sphere"); // If it's a sphere, square the radius to compare with if (sphere_) site_size_ *= site_size_; datafile_ = actionArgs.GetStringKey("out"); std::string ds_name = actionArgs.GetStringKey("name"); if (ds_name.empty()) ds_name = myDSL_.GenerateDefaultName("SPAM"); // Parse through the peaks file and extract the peaks CpptrajFile peakfile; if (peakfile.OpenRead(filename)) { mprinterr("SPAM: Error: Could not open %s for reading!\n", filename.full()); return Action::ERR; } std::string line = peakfile.GetLine(); int npeaks = 0; while (!line.empty()) { if (sscanf(line.c_str(), "%d", &npeaks) != 1) { line = peakfile.GetLine(); continue; } line = peakfile.GetLine(); break; } while (!line.empty()) { double x, y, z, dens; if (sscanf(line.c_str(), "C %lg %lg %lg %lg", &x, &y, &z, &dens) != 4) { line = peakfile.GetLine(); continue; } line = peakfile.GetLine(); peaks_.push_back(Vec3(x, y, z)); } peakfile.CloseFile(); // Check that our initial number of peaks matches our parsed peaks. Warn // otherwise if (npeaks != (int)peaks_.size()) mprinterr("SPAM: Warning: %s claims to have %d peaks, but really has %d!\n", filename.full(), npeaks, peaks_.size()); // Now add all of the data sets MetaData md(ds_name); for (int i = 0; i < (int)peaks_.size(); i++) { md.SetAspect( integerToString(i+1) ); // TODO: Should this be Idx? if (myDSL_.AddSet(DataSet::DOUBLE, md) == 0) return Action::ERR; // Add a new list of integers to keep track of omitted frames std::vector<int> vec; peakFrameData_.push_back(vec); } } // Print info now if (purewater_) { mprintf("SPAM: Calculating bulk value for pure solvent\n"); if (!datafile_.empty()) mprintf("SPAM: Printing solvent energies to %s\n", datafile_.c_str()); mprintf("SPAM: Using a %.2f Angstrom non-bonded cutoff with shifted EEL.\n", sqrt(cut2_)); if (reorder_) mprintf("SPAM: Warning: Re-ordering makes no sense for pure solvent.\n"); if (!summaryfile_.empty()) mprintf("SPAM: Printing solvent SPAM summary to %s\n", summaryfile_.c_str()); }else { mprintf("SPAM: Solvent [%s] density peaks taken from %s.\n", solvname_.c_str(), filename.base()); mprintf("SPAM: %d density peaks will be analyzed from %s.\n", peaks_.size(), filename.base()); mprintf("SPAM: Occupation information printed to %s.\n", infofile_->Filename().full()); mprintf("SPAM: Sites are "); if (sphere_) mprintf("spheres with diameter %.3lf\n", site_size_); else mprintf("boxes with edge length %.3lf\n", site_size_); if (reorder_) { mprintf("SPAM: Re-ordering trajectory so each site always has "); mprintf("the same water molecule.\n"); } if (summaryfile_.empty() && datafile_.empty()) { if (!reorder_) { mprinterr("SPAM: Error: Not re-ordering trajectory or calculating energies. "); mprinterr("Nothing to do!\n"); return Action::ERR; } mprintf("SPAM: Not calculating any SPAM energies\n"); }else { mprintf("SPAM: Using a non-bonded cutoff of %.2lf Ang. with a EEL shifting function.\n", sqrt(cut2_)); mprintf("SPAM: Bulk solvent SPAM energy taken as %.3lf kcal/mol\n", bulk_); } } mprintf("#Citation: Cui, G.; Swails, J.M.; Manas, E.S.; \"SPAM: A Simple Approach\n" "# for Profiling Bound Water Molecules\"\n" "# J. Chem. Theory Comput., 2013, 9 (12), pp 5539–5549.\n"); return Action::OK; }