// DataIO_CCP4::WriteData() int DataIO_CCP4::WriteData(FileName const& fname, DataSetList const& setList) { // Open output file CpptrajFile outfile; if (outfile.OpenWrite(fname)) { mprinterr("Error: Could not open CCP4 output file '%s'.\n", fname.full()); return 1; } // Warn about writing multiple sets if (setList.size() > 1) mprintf("Warning: %s: Writing multiple 3D sets in CCP4 format not supported.\n" "Warning: Only writing first set.\n", fname.full()); return WriteSet3D( setList.begin(), outfile ); }
/** Assuming lowest replica filename has been set, search for all other * replica names assuming a naming scheme of '<PREFIX>.<EXT>[.<CEXT>]', * where <EXT> is a numerical extension and <CEXT> is an optional * compression extension. * \return Found replica filenames, or an empty list on error. */ File::NameArray File::SearchForReplicas(FileName const& fname, int debug) { NameArray replica_filenames; if (!File::Exists(fname)) { mprinterr("Error: '%s' does not correspond to a file.\n", fname.full()); return replica_filenames; } RepName repName(fname, debug); if (repName.Error()) return replica_filenames; // Search for a replica number lower than this. Correct functioning // of the replica code requires the file specified by trajin be the // lowest # replica. if (File::Exists( repName.RepFilename( -1 ) )) { mprintf("Warning: Replica# found lower than file specified with trajin.\n" "Warning: Found \"%s\"; 'trajin remdtraj' requires lowest # replica.\n", repName.RepFilename( -1 ).full()); } // Add lowest replica filename, search for and add all replicas higher than it. replica_filenames.push_back( fname ); int rep_offset = 0; bool search_for_files = true; FileName trajFilename; while (search_for_files) { ++rep_offset; trajFilename = repName.RepFilename( rep_offset ); //mprintf("\t\tChecking for %s\n", trajFilename.full()); if (File::Exists( trajFilename )) replica_filenames.push_back( trajFilename ); else search_for_files = false; } return replica_filenames; }
// TODO: Accept const ArgList so arguments are not reset? CpptrajFile* DataFileList::AddCpptrajFile(FileName const& nameIn, std::string const& descrip, CFtype typeIn, bool allowStdout) { // If no filename and stdout not allowed, no output desired. if (nameIn.empty() && !allowStdout) return 0; FileName name; CpptrajFile* Current = 0; int currentIdx = -1; if (!nameIn.empty()) { name = nameIn; // Append ensemble number if set. if (ensembleNum_ != -1) name.Append( "." + integerToString(ensembleNum_) ); // Check if filename in use by DataFile. DataFile* df = GetDataFile(name); if (df != 0) { mprinterr("Error: Text output file name '%s' already in use by data file '%s'.\n", nameIn.full(), df->DataFilename().full()); return 0; } // Check if this filename already in use currentIdx = GetCpptrajFileIdx( name ); if (currentIdx != -1) Current = cfList_[currentIdx]; } // If no CpptrajFile associated with name, create new CpptrajFile if (Current==0) { switch (typeIn) { case TEXT: Current = new CpptrajFile(); break; case PDB: Current = (CpptrajFile*)(new PDBfile()); break; } Current->SetDebug(debug_); // Set up file for writing. //if (Current->SetupWrite( name, debug_ )) if (Current->OpenWrite( name )) { mprinterr("Error: Setting up text output file %s\n", name.full()); delete Current; return 0; } cfList_.push_back( Current ); cfData_.push_back( CFstruct(descrip, typeIn) ); } else { // If Current type does not match typeIn do not allow. if (typeIn != cfData_[currentIdx].Type()) { mprinterr("Error: Cannot change type of text output for '%s'.\n", Current->Filename().full()); return 0; } Current->SetDebug(debug_); // Update description if (!descrip.empty()) cfData_[currentIdx].UpdateDescrip( descrip ); } return Current; }
/** Each rank searches for replica based on lowest replica number. */ int TrajIOarray::SearchForReplicas(FileName const& fname, Parallel::Comm const& ensComm, Parallel::Comm const& trajComm) { RepName repName(fname, debug_); if (repName.Error()) return 1; // TODO check for lower replica number? FileName replicaFilename = repName.RepFilename( ensComm.Rank() ); // Only traj comm masters actually check for files. if (trajComm.Master()) { if (!File::Exists( replicaFilename )) { File::ErrorMsg( replicaFilename.full() ); rprinterr("Error: File '%s' not accessible.\n", replicaFilename.full()); return 1; } } // At this point each rank has found its replica. Populate filename array. for (int offset = 0; offset < ensComm.Size(); ++offset) replica_filenames_.push_back( repName.RepFilename( offset ) ); return 0; }
bool File::Exists(FileName const& fn) { if (!fn.empty()) { FILE* infile = fopen(fn.full(), "rb"); if (infile==0) { fileErrMsg_.assign( strerror(errno) ); return false; } fclose(infile); return true; } return false; }
/** Each rank searches for replica based on lowest replica number. */ File::NameArray File::SearchForReplicas(FileName const& fname, bool trajCommMaster, int ensRank, int ensSize, int debug) { NameArray replica_filenames; RepName repName(fname, debug); if (repName.Error()) return replica_filenames; // TODO check for lower replica number? FileName replicaFilename = repName.RepFilename( ensRank ); // Only traj comm masters actually check for files. if (trajCommMaster) { if (!File::Exists( replicaFilename )) { File::ErrorMsg( replicaFilename.full() ); rprinterr("Error: File '%s' not accessible.\n", replicaFilename.full()); return replica_filenames; } } // At this point each rank has found its replica. Populate filename array. for (int offset = 0; offset < ensSize; ++offset) replica_filenames.push_back( repName.RepFilename( offset ) ); return replica_filenames; }
// DataIO_OpenDx::ReadData() int DataIO_OpenDx::ReadData(FileName const& fname, DataSetList& datasetlist, std::string const& dsname) { // Add grid data set. Default to float for now. DataSet* ds = datasetlist.AddSet( DataSet::GRID_FLT, dsname, "GRID" ); if (ds==0) return 1; if (LoadGrid(fname.full(), *ds)) { // Load failed. Erase grid data set. datasetlist.RemoveSet( ds ); return 1; } return 0; }
// ParmFile::ReadTopology() int ParmFile::ReadTopology(Topology& Top, FileName const& fnameIn, ArgList const& argListIn, int debugIn) { if (fnameIn.empty()) { mprinterr("Error: No input topology name given.\n"); return 1; } if (!File::Exists( fnameIn )) { mprinterr("Error: Topology '%s' does not exist.\n", fnameIn.full()); return 1; } parmName_ = fnameIn; ArgList argIn = argListIn; ParmFormatType pfType; ParmIO* parmio = 0; Top.SetDebug( debugIn ); // Only force bond search when 'bondsearch' is specified. bool bondsearch = false; if (argIn.Contains("bondsearch")) { Top.SetOffset( argIn.getKeyDouble("bondsearch", -1.0) ); bondsearch = true; } // 'as' keyword specifies a format std::string as_arg = argIn.GetStringKey("as"); if (!as_arg.empty()) { pfType = (ParmFormatType)FileTypes::GetFormatFromString( PF_KeyArray, as_arg, UNKNOWN_PARM ); if (pfType == UNKNOWN_PARM) { mprinterr("Error: Topology format '%s' not recognized.\n", as_arg.c_str()); return 1; } parmio = (ParmIO*)FileTypes::AllocIO( PF_AllocArray, pfType, false ); } else parmio = DetectFormat( parmName_, pfType ); if (parmio == 0) { mprinterr("Error: Could not determine format of topology '%s'\n", parmName_.full()); return 1; } mprintf("\tReading '%s' as %s\n", parmName_.full(), FileTypes::FormatDescription(PF_AllocArray, pfType) ); parmio->SetDebug( debugIn ); if (parmio->processReadArgs(argIn)) return 1; int err = parmio->ReadParm( parmName_.Full(), Top); // Perform setup common to all parm files. if (err == 0) err = Top.CommonSetup(bondsearch || parmio->NeedsBondSearch()); else mprinterr("Error reading topology file '%s'\n", parmName_.full()); delete parmio; if (err > 0) return 1; return 0; }
// ============================================================================= // ----- 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_); }
/** Add lowest replica file name and names from comma-separated list. */ int TrajIOarray::AddReplicasFromArgs(FileName const& name0, std::string const& commaNames) { if (name0.empty()) return 1; if (!File::Exists( name0 )) { File::ErrorMsg( name0.full() ); return 1; } replica_filenames_.push_back( name0 ); ArgList remdtraj_list( commaNames, "," ); for (ArgList::const_iterator fname = remdtraj_list.begin(); fname != remdtraj_list.end(); ++fname) { FileName trajFilename( *fname ); if (!File::Exists( trajFilename )) { File::ErrorMsg( trajFilename.full() ); return 1; } replica_filenames_.push_back( trajFilename ); } return 0; }
// Parm_CIF::ReadParm() int Parm_CIF::ReadParm(FileName const& fname, Topology &TopIn) { CIFfile infile; CIFfile::DataBlock::data_it line; if (infile.Read( fname, debug_ )) return 1; CIFfile::DataBlock const& block = infile.GetDataBlock("_atom_site"); if (block.empty()) { mprinterr("Error: CIF data block '_atom_site' not found.\n"); return 1; } // Does this CIF contain multiple models? int Nmodels = 0; int model_col = block.ColumnIndex("pdbx_PDB_model_num"); if (model_col != -1) { line = block.end(); --line; Nmodels = convertToInteger( (*line)[model_col] ); if (Nmodels > 1) mprintf("Warning: CIF '%s' contains %i models. Using first model for topology.\n", fname.full(), Nmodels); } // Get essential columns int COL[NENTRY]; for (int i = 0; i < (int)NENTRY; i++) { COL[i] = block.ColumnIndex(Entries[i]); if (COL[i] == -1) { mprinterr("Error: In CIF file '%s' could not find entry '%s' in block '%s'\n", fname.full(), Entries[i], block.Header().c_str()); return 1; } if (debug_>0) mprintf("DEBUG: '%s' column = %i\n", Entries[i], COL[i]); } // Get optional columns int occ_col = block.ColumnIndex("occupancy"); int bfac_col = block.ColumnIndex("B_iso_or_equiv"); int icode_col = block.ColumnIndex("pdbx_PDB_ins_code"); int altloc_col = block.ColumnIndex("label_alt_id"); std::vector<AtomExtra> extra; // Loop over all atom sites int current_res = 0; double XYZ[3]; double occupancy = 1.0; double bfactor = 0.0; char altloc = ' '; char icode; icode = ' '; Frame Coords; for (line = block.begin(); line != block.end(); ++line) { // If more than 1 model check if we are done. if (Nmodels > 1) { if ( convertToInteger( (*line)[model_col] ) > 1 ) break; } if (occ_col != -1) occupancy = convertToDouble( (*line)[ occ_col ] ); if (bfac_col != -1) bfactor = convertToDouble( (*line)[ bfac_col ] ); if (altloc_col != -1) altloc = (*line)[ altloc_col ][0]; // '.' altloc means blank? if (altloc == '.') altloc = ' '; extra.push_back( AtomExtra(occupancy, bfactor, altloc) ); if (icode_col != -1) { icode = (*line)[ icode_col ][0]; // '?' icode means blank if (icode == '?') icode = ' '; } XYZ[0] = convertToDouble( (*line)[ COL[X] ] ); XYZ[1] = convertToDouble( (*line)[ COL[Y] ] ); XYZ[2] = convertToDouble( (*line)[ COL[Z] ] ); NameType currentResName( (*line)[ COL[RNAME] ] ); // It seems that in some CIF files, there doesnt have to be a residue // number. Check if residue name has changed. if ( (*line)[ COL[RNUM] ][0] == '.' ) { Topology::res_iterator lastResidue = TopIn.ResEnd(); --lastResidue; if ( currentResName != (*lastResidue).Name() ) current_res = TopIn.Nres() + 1; } else current_res = convertToInteger( (*line)[ COL[RNUM] ] ); TopIn.AddTopAtom( Atom((*line)[ COL[ANAME] ], " "), Residue(currentResName, current_res, icode, (*line)[ COL[CHAINID] ][0]) ); Coords.AddXYZ( XYZ ); } if (TopIn.SetExtraAtomInfo( 0, extra )) return 1; // Search for bonds // FIXME nobondsearch? BondSearch( TopIn, Coords, Offset_, debug_ ); // Get title. CIFfile::DataBlock const& entryblock = infile.GetDataBlock("_entry"); std::string ciftitle; if (!entryblock.empty()) ciftitle = entryblock.Data("id"); TopIn.SetParmName( ciftitle, infile.CIFname() ); // Get unit cell parameters if present. CIFfile::DataBlock const& cellblock = infile.GetDataBlock("_cell"); if (!cellblock.empty()) { double cif_box[6]; cif_box[0] = convertToDouble( cellblock.Data("length_a") ); cif_box[1] = convertToDouble( cellblock.Data("length_b") ); cif_box[2] = convertToDouble( cellblock.Data("length_c") ); cif_box[3] = convertToDouble( cellblock.Data("angle_alpha") ); cif_box[4] = convertToDouble( cellblock.Data("angle_beta" ) ); cif_box[5] = convertToDouble( cellblock.Data("angle_gamma") ); mprintf("\tRead cell info from CIF: a=%g b=%g c=%g alpha=%g beta=%g gamma=%g\n", cif_box[0], cif_box[1], cif_box[2], cif_box[3], cif_box[4], cif_box[5]); TopIn.SetParmBox( Box(cif_box) ); } return 0; }
// DataIO_Mdout::ReadData() int DataIO_Mdout::ReadData(FileName const& fname, DataSetList& datasetlist, std::string const& dsname) { mprintf("\tReading from mdout file: %s\n", fname.full()); BufferedLine buffer; if (buffer.OpenFileRead( fname )) return 1; const char* ptr = buffer.Line(); if (ptr == 0) { mprinterr("Error: Nothing in MDOUT file: %s\n", fname.full()); return 1; } // ----- PARSE THE INPUT SECTION ----- int imin = -1; // imin for this file const char* Trigger = 0; // Trigger for storing energies, must be 8 chars long. int frame = 0; // Frame counter for this file double dt = 1.0; // Timestep for this file (MD) double t0 = 0.0; // Initial time for this file (MD) int ntpr = 1; // Value of ntpr int irest = 0; // Value of irest while ( ptr != 0 && strncmp(ptr, " 2. CONTROL DATA", 20) != 0 ) ptr = buffer.Line(); if (ptr == 0) return EOF_ERROR(); // Determine whether this is dynamics or minimization, get dt ptr = buffer.Line(); // Dashes ptr = buffer.Line(); // Blank ptr = buffer.Line(); // title line while ( strncmp(ptr, " 3. ATOMIC", 13) != 0 ) { ArgList mdin_args( ptr, " ,=" ); // Remove commas, equal signs // Scan for stuff we want //mprintf("DEBUG:\tInput[%i] %s", mdin_args.Nargs(), mdin_args.ArgLine()); for (int col=0; col < mdin_args.Nargs(); col += 2) { int col1 = col + 1; if (mdin_args[col] == "imin") { imin = convertToInteger( mdin_args[ col1 ] ); if (debug_ > 0) mprintf("\t\tMDIN: imin is %i\n", imin); // Set a trigger for printing. For imin5 this is the word minimization. // For imin0 or imin1 this is NSTEP. if (imin==0) Trigger = " NSTEP ="; else if (imin==1) Trigger = " NSTEP"; else if (imin==5) Trigger = "minimiza"; // Since imin0 and imin1 first trigger has no data, set frame 1 lower. if (imin==1 || imin==0) frame = -1; } else if (mdin_args[col] == "dt") { dt = convertToDouble( mdin_args[ col1 ] ); if (debug_ > 0) mprintf("\t\tMDIN: dt is %f\n", dt); } else if (mdin_args[col] == "t") { t0 = convertToDouble( mdin_args[ col1 ] ); if (debug_ > 0) mprintf("\t\tMDIN: t is %f\n", t0); } else if (mdin_args[col] == "ntpr") { ntpr = convertToInteger( mdin_args[ col1 ] ); if (debug_ > 0) mprintf("\t\tMDIN: ntpr is %i\n", ntpr); } else if (mdin_args[col] == "irest") { irest = convertToInteger( mdin_args[ col1 ] ); if (debug_ > 0) mprintf("\t\tMDIN: irest is %i\n", irest); } } ptr = buffer.Line(); if (ptr == 0) return EOF_ERROR(); } if (Trigger == 0) { mprinterr("Error: Could not determine whether MDOUT is md, min, or post-process.\n"); return 1; } // ----- PARSE THE ATOMIC ... SECTION ----- while ( ptr != 0 && strncmp(ptr, " 4. RESULTS", 14) != 0 ) { ptr = buffer.Line(); // If run is a restart, set the initial time value. if (irest == 1) { if (strncmp(ptr, " begin time", 11) == 0) { sscanf(ptr, " begin time read from input coords = %lf", &t0); if (debug_ > 0) mprintf("\t\tMD restart initial time= %f\n", t0); } } } if (ptr == 0) return EOF_ERROR(); // ----- PARSE THE RESULTS SECTION ----- bool finalE = false; int nstep; int minStep = 0; // For imin=1 only if (irest == 0) nstep = 0; else nstep = ntpr; double Energy[N_FIELDTYPES]; std::fill( Energy, Energy+N_FIELDTYPES, 0.0 ); std::vector<bool> EnergyExists(N_FIELDTYPES, false); DataSetList::Darray TimeVals; DataSetList::DataListType inputSets(N_FIELDTYPES, 0); Sarray Name(2); double time = 0.0; while (ptr != 0) { // Check for end of imin 0 or 1 run; do not record Average and Stdevs if ( (imin == 1 && (strncmp(ptr, " FINAL", 25) == 0 || strncmp(ptr, " 5. TIMINGS", 14) == 0 )) || (imin == 0 && strncmp(ptr, " A V", 9) == 0)) finalE = true; // Check for '| TI region 2' to prevent reading duplicate energies if ( strncmp(ptr, "| TI region 2", 14) == 0 ) { while (ptr != 0 && !(ptr[0] == ' ' && ptr[1] == '-')) ptr = buffer.Line(); if (ptr == 0) return EOF_ERROR(); } // Record set for energy post-processing if (imin == 5 && strncmp(ptr, "minimizing", 10) == 0) nstep = atoi( ptr + 22 ); // MAIN OUTPUT ROUTINE // If the trigger has been reached print output. // For imin0 and imin1 the first trigger will have no data. // If the end of the file has been reached print then exit. if ( strncmp(ptr, Trigger, 8) == 0 || finalE ) { if (frame > -1) { // Store all energies present. for (int i = 0; i < (int)N_FIELDTYPES; i++) { if (EnergyExists[i]) { if (inputSets[i] == 0) { MetaData md( dsname, Enames[i] ); md.SetLegend( dsname + "_" + Enames[i] ); inputSets[i] = new DataSet_double(); inputSets[i]->SetMeta( md ); } // Since energy terms can appear and vanish over the course of the // mdout file, resize if necessary. if (frame > (int)inputSets[i]->Size()) ((DataSet_double*)inputSets[i])->Resize( frame ); ((DataSet_double*)inputSets[i])->AddElement( Energy[i] ); } } TimeVals.push_back( time ); nstep += ntpr; } frame++; if (finalE) break; } // Check for NSTEP in minimization or post-processing. Values will be // on the next line. NOTE: NSTEP means something different for imin=5. if ((imin == 1 || imin == 5) && strncmp(ptr, " NSTEP", 8) == 0) { ptr = buffer.Line(); // Get next line //sscanf(ptr, " %6lf %13lE %13lE %13lE", Energy+NSTEP, Energy+EPtot, Energy+RMS, Energy+GMAX); sscanf(ptr, " %i %lE %lE %lE", &minStep, Energy+EPtot, Energy+RMS, Energy+GMAX); EnergyExists[EPtot] = true; EnergyExists[RMS] = true; EnergyExists[GMAX] = true; ptr = buffer.Line(); } // Tokenize line, scan through until '=' is reached; value after is target. int ntokens = buffer.TokenizeLine(" "); if (ntokens > 0) { int nidx = 0; Name[0].clear(); Name[1].clear(); for (int tidx = 0; tidx < ntokens; tidx++) { const char* tkn = buffer.NextToken(); if (tkn[0] == '=') { FieldType Eindex = getEindex(Name); tkn = buffer.NextToken(); ++tidx; if (tkn == 0) mprintf("Warning: No numerical value, line %i column %i. Skipping.\n", buffer.LineNumber(), tidx+1); else if (tkn[0] == '*' || tkn[0] == 'N') // Assume if number begins with N it is NaN mprintf("Warning: Numerical overflow detected, line %i column %i. Skipping.\n", buffer.LineNumber(), tidx+1); else { if (Eindex != N_FIELDTYPES) { Energy[Eindex] = atof( tkn ); EnergyExists[Eindex] = true; } } nidx = 0; Name[0].clear(); Name[1].clear(); } else { if (nidx > 1) break; // Two tokens, no '=' found. Not an E line. Name[nidx++].assign( tkn ); } } } // Set time switch (imin) { case 5: time = (double)nstep + t0; break; case 1: time = (double)minStep + t0; break; case 0: time = ((double)nstep * dt) + t0; break; } // Read in next line ptr = buffer.Line(); } mprintf("\t%i frames\n", frame); buffer.CloseFile(); std::string Xlabel; if (imin == 5) Xlabel.assign("Set"); else if (imin == 1) Xlabel.assign("Nstep"); else Xlabel.assign("Time"); // imin == 0 if (datasetlist.AddOrAppendSets( Xlabel, TimeVals, inputSets )) return 1; return 0; }
/** Free the given temporary file name. */ void FreeTempName(FileName const& temp) { TempFileNames_.remove( temp ); if (Exists(temp)) remove(temp.full()); }
// DataIO_OpenDx::WriteData() int DataIO_OpenDx::WriteData(FileName const& fname, DataSetList const& setList) { // Open output file CpptrajFile outfile; if (outfile.OpenWrite(fname)) { mprinterr("Error: Could not open OpenDX output file.\n"); return 1; } // Warn about writing multiple sets if (setList.size() > 1) mprintf("Warning: %s: Writing multiple 3D sets in OpenDX format may result in unexpected behavior\n", fname.full()); int err = 0; for (DataSetList::const_iterator set = setList.begin(); set != setList.end(); ++set) err += WriteSet3D( *(*set), outfile ); return err; }
// 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; }