/** Given an argument with format, DataSet_Name[,min,max,step,bins], check * that DataSet_Name exists and is valid. Add the argument to * dimensionArgs and the corresponding dataset to histdata. */ int Analysis_Hist::CheckDimension(std::string const& input, DataSetList& DSLin) { ArgList arglist; // Separate input string by ',' arglist.SetList(input, ","); if (arglist.Nargs()<1) { mprinterr("Error: No arguments found in histogram argument: %s\n",input.c_str()); return 1; } // First argument should specify dataset name if (debug_>0) mprintf("\tHist: Setting up histogram dimension using dataset %s\n", arglist.Command()); DataSet* dset = DSLin.GetDataSet( arglist[0] ); if (dset == 0) { mprinterr("Error: Dataset %s not found.\n",arglist.Command()); return 1; } // For now only 1D scalar data sets can be histogrammed if (dset->Group() != DataSet::SCALAR_1D) { mprinterr("Error: Cannot histogram data set '%s'\n", dset->legend()); mprinterr("Error: Currently only 1D scalar data sets can be histogrammed.\n"); return 1; } // TODO parse remaining args here, create data structure. dimensionArgs_.push_back( arglist ); histdata_.push_back( (DataSet_1D*)dset ); return 0; }
// Action_Grid::Init() Action::RetType Action_Grid::Init(ArgList& actionArgs, ActionInit& init, int debugIn) { debug_ = debugIn; nframes_ = 0; // Get output filename std::string filename = actionArgs.GetStringKey("out"); // Get grid options grid_ = GridInit( "GRID", actionArgs, init.DSL() ); if (grid_ == 0) return Action::ERR; # ifdef MPI if (ParallelGridInit(init.TrajComm(), grid_)) return Action::ERR; # endif // Get extra options max_ = actionArgs.getKeyDouble("max", 0.80); madura_ = actionArgs.getKeyDouble("madura", 0); smooth_ = actionArgs.getKeyDouble("smoothdensity", 0); invert_ = actionArgs.hasKey("invert"); pdbfile_ = init.DFL().AddCpptrajFile(actionArgs.GetStringKey("pdb"),"Grid PDB",DataFileList::PDB,true); density_ = actionArgs.getKeyDouble("density",0.033456); if (actionArgs.hasKey("normframe")) normalize_ = TO_FRAME; else if (actionArgs.hasKey("normdensity")) normalize_ = TO_DENSITY; else normalize_ = NONE; if (normalize_ != NONE && (smooth_ > 0.0 || madura_ > 0.0)) { mprinterr("Error: Normalize options are not compatible with smoothdensity/madura options.\n"); init.DSL().RemoveSet( grid_ ); return Action::ERR; } // Get mask std::string maskexpr = actionArgs.GetMaskNext(); if (maskexpr.empty()) { mprinterr("Error: GRID: No mask specified.\n"); init.DSL().RemoveSet( grid_ ); return Action::ERR; } mask_.SetMaskString(maskexpr); // Setup output file // For backwards compat., if no 'out' assume next string is filename if (filename.empty() && actionArgs.Nargs() > 1 && !actionArgs.Marked(1)) filename = actionArgs.GetStringNext(); DataFile* outfile = init.DFL().AddDataFile(filename, actionArgs); if (outfile != 0) outfile->AddDataSet((DataSet*)grid_); // Info mprintf(" GRID:\n"); GridInfo( *grid_ ); if (outfile != 0) mprintf("\tGrid will be printed to file %s\n", outfile->DataFilename().full()); mprintf("\tGrid data set: '%s'\n", grid_->legend()); mprintf("\tMask expression: [%s]\n",mask_.MaskString()); if (pdbfile_ != 0) mprintf("\tPseudo-PDB will be printed to %s\n", pdbfile_->Filename().full()); if (normalize_ == TO_FRAME) mprintf("\tGrid will be normalized by number of frames.\n"); else if (normalize_ == TO_DENSITY) mprintf("\tGrid will be normalized to a density of %g molecules/Ang^3.\n", density_); // TODO: print extra options return Action::OK; }
/// \return 1 if problem with or not a Tinker Atom/Title line. static inline int SetNatomAndTitle(ArgList& lineIn, int& natom, std::string& title) { if (lineIn.Nargs() < 1) return 1; natom = lineIn.getNextInteger( -1 ); if (natom < 1) return 1; std::string nextWord = lineIn.GetStringNext(); //if (nextWord.empty()) return 1; while (!nextWord.empty()) { if (!title.empty()) title += ' '; title.append( nextWord ); nextWord = lineIn.GetStringNext(); } return 0; }
static inline bool IsAtomLine(ArgList& lineIn) { for (int i = 0; i < lineIn.Nargs(); i++) { std::string item = lineIn.GetStringNext(); if (i == 0 || i >= 5) { try { convertToInteger( item ); } catch (std::runtime_error e) { return false; } } else if (i >= 2 && i < 5) { try { convertToDouble( item ); } catch (std::runtime_error e) { return false; } } } return true; }
/** Given an ArgList containing name,[min,max,step,bins,col,N], set up a * coordinate with that name and parameters min, max, step, bins. * If '*' or not specified, a default value will be set. * \return 1 if error occurs, 0 otherwise. */ int Analysis_Hist::setupDimension(ArgList &arglist, DataSet_1D const& dset, size_t& offset) { bool minArg = false; bool maxArg = false; bool stepArg = false; bool binsArg = false; if (debug_>1) arglist.PrintList(); // Set up dimension name // NOTE: arglist[0] should be same as dset name from CheckDimension std::string const& dLabel = arglist[0]; // Cycle through coordinate arguments. Any argument left blank will be // assigned a default value later. double dMin = 0.0; double dMax = 0.0; double dStep = 0.0; int dBins = -1; for (int i = 1; i < arglist.Nargs(); i++) { if (debug_>1) mprintf("DEBUG: setupCoord: Token %i (%s)\n", i, arglist[i].c_str()); // '*' means default explicitly requested if (arglist[i] == "*") continue; switch (i) { case 1 : dMin = convertToDouble( arglist[i]); minArg = true; break; case 2 : dMax = convertToDouble( arglist[i]); maxArg = true; break; case 3 : dStep = convertToDouble( arglist[i]); stepArg = true; break; case 4 : dBins = convertToInteger(arglist[i]); binsArg = true; break; } } // If no min arg and no default min arg, get min from dataset if (!minArg) { if (!minArgSet_) dMin = dset.Min(); else dMin = default_min_; } // If no max arg and no default max arg, get max from dataset if (!maxArg) { if (!maxArgSet_) dMax = dset.Max(); else dMax = default_max_; } // If bins/step not specified, use default if (!binsArg) dBins = default_bins_; if (!stepArg) dStep = default_step_; // Calculate dimension from given args. HistBin dim; if (dim.CalcBinsOrStep( dMin, dMax, dStep, dBins, dLabel )) { mprinterr("Error: Could not set up histogram dimension '%s'\n", dLabel.c_str()); return 1; } dim.PrintHistBin(); dimensions_.push_back( dim ); // Recalculate offsets for all dimensions starting at farthest coord. This // follows row major ordering. size_t last_offset = 1UL; // For checking overflow. offset = 1UL; binOffsets_.resize( dimensions_.size() ); OffType::iterator bOff = binOffsets_.begin(); for (HdimType::const_iterator rd = dimensions_.begin(); rd != dimensions_.end(); ++rd, ++bOff) { if (debug_>0) mprintf("\tHistogram: %s offset is %zu\n", rd->label(), offset); *bOff = (long int)offset; offset *= rd->Bins(); // Check for overflow. if ( offset < last_offset ) { mprinterr("Error: Too many bins for histogram. Try reducing the number of bins and/or\n" "Error: the number of dimensions.\n"); return 1; } last_offset = offset; } // offset should now be equal to the total number of bins across all dimensions if (debug_>0) mprintf("\tHistogram: Total Bins = %zu\n",offset); return 0; }
// Action_Radial::Init() Action::RetType Action_Radial::Init(ArgList& actionArgs, ActionInit& init, int debugIn) { debug_ = debugIn; // Get Keywords image_.InitImaging( !(actionArgs.hasKey("noimage")) ); std::string outfilename = actionArgs.GetStringKey("out"); // Default particle density (mols/Ang^3) for water based on 1.0 g/mL density_ = actionArgs.getKeyDouble("density",0.033456); if (actionArgs.hasKey("center1")) rmode_ = CENTER1; else if (actionArgs.hasKey("center2")) rmode_ = CENTER2; else if (actionArgs.hasKey("nointramol")) rmode_ = NO_INTRAMOL; else rmode_ = NORMAL; useVolume_ = actionArgs.hasKey("volume"); DataFile* intrdfFile = init.DFL().AddDataFile(actionArgs.GetStringKey("intrdf")); DataFile* rawrdfFile = init.DFL().AddDataFile(actionArgs.GetStringKey("rawrdf")); spacing_ = actionArgs.getNextDouble(-1.0); if (spacing_ < 0) { mprinterr("Error: Radial: No spacing argument or arg < 0.\n"); Help(); return Action::ERR; } double maximum = actionArgs.getNextDouble(-1.0); if (maximum < 0) { mprinterr("Error: Radial: No maximum argument or arg < 0.\n"); Help(); return Action::ERR; } // Store max^2, distances^2 greater than max^2 do not need to be // binned and therefore do not need a sqrt calc. maximum2_ = maximum * maximum; // Get First Mask std::string mask1 = actionArgs.GetMaskNext(); if (mask1.empty()) { mprinterr("Error: Radial: No mask given.\n"); return Action::ERR; } Mask1_.SetMaskString(mask1); // Check for second mask - if none specified use first mask std::string mask2 = actionArgs.GetMaskNext(); if (!mask2.empty()) Mask2_.SetMaskString(mask2); else Mask2_.SetMaskString(mask1); // If filename not yet specified check for backwards compat. if (outfilename.empty() && actionArgs.Nargs() > 1 && !actionArgs.Marked(1)) outfilename = actionArgs.GetStringNext(); // Set up output dataset. Dset_ = init.DSL().AddSet( DataSet::DOUBLE, actionArgs.GetStringNext(), "g(r)"); if (Dset_ == 0) return RDF_ERR("Could not allocate RDF data set."); DataFile* outfile = init.DFL().AddDataFile(outfilename, actionArgs); if (outfile != 0) outfile->AddDataSet( Dset_ ); // Make default precision a little higher than normal Dset_->SetupFormat().SetFormatWidthPrecision(12,6); // Set DataSet legend from mask strings. Dset_->SetLegend(Mask1_.MaskExpression() + " => " + Mask2_.MaskExpression()); // TODO: Set Yaxis label in DataFile // Calculate number of bins one_over_spacing_ = 1 / spacing_; double temp_numbins = maximum * one_over_spacing_; temp_numbins = ceil(temp_numbins); numBins_ = (int) temp_numbins; // Setup output datafile. Align on bin centers instead of left. // TODO: Use Rdim for binning? Dimension Rdim( spacing_ / 2.0, spacing_, "Distance (Ang)" ); Dset_->SetDim(Dimension::X, Rdim); // Set up output for integral of mask2 if specified. if (intrdfFile != 0) { intrdf_ = init.DSL().AddSet( DataSet::DOUBLE, MetaData(Dset_->Meta().Name(), "int" )); if (intrdf_ == 0) return RDF_ERR("Could not allocate RDF integral data set."); intrdf_->SetupFormat().SetFormatWidthPrecision(12,6); intrdf_->SetLegend("Int[" + Mask2_.MaskExpression() + "]"); intrdf_->SetDim(Dimension::X, Rdim); intrdfFile->AddDataSet( intrdf_ ); } else intrdf_ = 0; // Set up output for raw rdf if (rawrdfFile != 0) { rawrdf_ = init.DSL().AddSet( DataSet::DOUBLE, MetaData(Dset_->Meta().Name(), "raw" )); if (rawrdf_ == 0) return RDF_ERR("Could not allocate raw RDF data set."); rawrdf_->SetupFormat().SetFormatWidthPrecision(12,6); rawrdf_->SetLegend("Raw[" + Dset_->Meta().Legend() + "]"); rawrdf_->SetDim(Dimension::X, Rdim); rawrdfFile->AddDataSet( rawrdf_ ); } else rawrdf_ = 0; // Set up histogram RDF_ = new int[ numBins_ ]; std::fill(RDF_, RDF_ + numBins_, 0); # ifdef _OPENMP // Since RDF is shared by all threads and we cant guarantee that a given // bin in RDF wont be accessed at the same time by the same thread, // each thread needs its own bin space. #pragma omp parallel { if (omp_get_thread_num()==0) numthreads_ = omp_get_num_threads(); } rdf_thread_ = new int*[ numthreads_ ]; for (int i=0; i < numthreads_; i++) { rdf_thread_[i] = new int[ numBins_ ]; std::fill(rdf_thread_[i], rdf_thread_[i] + numBins_, 0); } # endif mprintf(" RADIAL: Calculating RDF for atoms in mask [%s]",Mask1_.MaskString()); if (!mask2.empty()) mprintf(" to atoms in mask [%s]",Mask2_.MaskString()); mprintf("\n"); if (outfile != 0) mprintf(" Output to %s.\n", outfile->DataFilename().full()); if (intrdf_ != 0) mprintf(" Integral of mask2 atoms will be output to %s\n", intrdfFile->DataFilename().full()); if (rawrdf_ != 0) mprintf(" Raw RDF bin values will be output to %s\n", rawrdfFile->DataFilename().full()); if (rmode_==CENTER1) mprintf(" Using center of atoms in mask1.\n"); else if (rmode_==CENTER2) mprintf(" Using center of atoms in mask2.\n"); mprintf(" Histogram max %f, spacing %f, bins %i.\n",maximum, spacing_,numBins_); if (useVolume_) mprintf(" Normalizing based on cell volume.\n"); else mprintf(" Normalizing using particle density of %f molecules/Ang^3.\n",density_); if (!image_.UseImage()) mprintf(" Imaging disabled.\n"); if (numthreads_ > 1) mprintf(" Parallelizing RDF calculation with %i threads.\n",numthreads_); return Action::OK; }
/** Replace all variables in given ArgList with their values. */ ArgList VariableArray::ReplaceVariables(ArgList const& argIn, DataSetList const& DSL, int debug) { if (debug > 0) mprintf("DEBUG: Before variable replacement: [%s]\n", argIn.ArgLine()); ArgList modCmd = argIn; for (int n = 0; n < modCmd.Nargs(); n++) { size_t pos = modCmd[n].find("$"); while (pos != std::string::npos) { // Argument is/contains a variable. Find first non-alphanumeric char size_t len = 1; for (size_t pos1 = pos+1; pos1 < modCmd[n].size(); pos1++, len++) if (!isalnum(modCmd[n][pos1])) break; std::string var_in_arg = modCmd[n].substr(pos, len); // See if variable occurs in CurrentVars_ Varray::const_iterator vp = CurrentVars_.begin(); for (; vp != CurrentVars_.end(); ++vp) if (vp->first == var_in_arg) break; // If found replace with value from CurrentVars_ if (vp != CurrentVars_.end()) { if (debug > 0) mprintf("DEBUG: Replaced variable '%s' with value '%s'\n", var_in_arg.c_str(), vp->second.c_str()); std::string arg = modCmd[n]; arg.replace(pos, vp->first.size(), vp->second); modCmd.ChangeArg(n, arg); } else { // Not found in CurrentVars_; see if this is a DataSet. for (size_t pos1 = pos+len; pos1 < modCmd[n].size(); pos1++, len++) if (!isalnum(modCmd[n][pos1]) && modCmd[n][pos1] != '[' && modCmd[n][pos1] != ':' && modCmd[n][pos1] != ']' && modCmd[n][pos1] != '_' && modCmd[n][pos1] != '-' && modCmd[n][pos1] != '%') break; var_in_arg = modCmd[n].substr(pos+1, len-1); DataSet* ds = DSL.GetDataSet( var_in_arg ); if (ds == 0) { mprinterr("Error: Unrecognized variable in command: %s\n", var_in_arg.c_str()); return ArgList(); } else { if (ds->Type() != DataSet::STRING && ds->Group() != DataSet::SCALAR_1D) { mprinterr("Error: Only 1D data sets supported.\n"); return ArgList(); } if (ds->Size() < 1) { mprinterr("Error: Set is empty.\n"); return ArgList(); } if (ds->Size() > 1) mprintf("Warning: Only using first value.\n"); std::string value; if (ds->Type() == DataSet::STRING) value = (*((DataSet_string*)ds))[0]; else value = doubleToString(((DataSet_1D*)ds)->Dval(0)); if (debug > 0) mprintf("DEBUG: Replaced variable '$%s' with value '%s' from DataSet '%s'\n", var_in_arg.c_str(), value.c_str(), ds->legend()); std::string arg = modCmd[n]; arg.replace(pos, var_in_arg.size()+1, value); modCmd.ChangeArg(n, arg); } } pos = modCmd[n].find("$"); } // END loop over this argument } return modCmd; }
/** Set up variable with value. In this case allow any amount of whitespace, * so re-tokenize the original argument line (minus the command). */ CpptrajState::RetType Control_Set::SetupControl(CpptrajState& State, ArgList& argIn, Varray& CurrentVars) { ArgList remaining = argIn.RemainingArgs(); size_t pos0 = remaining.ArgLineStr().find_first_of("="); if (pos0 == std::string::npos) { mprinterr("Error: Expected <var>=<value>\n"); return CpptrajState::ERR; } size_t pos1 = pos0; bool append = false; if (pos0 > 0 && remaining.ArgLineStr()[pos0-1] == '+') { pos0--; append = true; } std::string variable = NoWhitespace( remaining.ArgLineStr().substr(0, pos0) ); if (variable.empty()) { mprinterr("Error: No variable name.\n"); return CpptrajState::ERR; } ArgList equals( NoLeadingWhitespace(remaining.ArgLineStr().substr(pos1+1)) ); std::string value; if (equals.Contains("inmask")) { AtomMask mask( equals.GetStringKey("inmask") ); Topology* top = State.DSL().GetTopByIndex( equals ); if (top == 0) return CpptrajState::ERR; if (top->SetupIntegerMask( mask )) return CpptrajState::ERR; if (equals.hasKey("atoms")) value = integerToString( mask.Nselected() ); else if (equals.hasKey("residues")) { int curRes = -1; int nres = 0; for (AtomMask::const_iterator at = mask.begin(); at != mask.end(); ++at) { int res = (*top)[*at].ResNum(); if (res != curRes) { nres++; curRes = res; } } value = integerToString( nres ); } else if (equals.hasKey("molecules")) { int curMol = -1; int nmol = 0; for (AtomMask::const_iterator at = mask.begin(); at != mask.end(); ++at) { int mol = (*top)[*at].MolNum(); if (mol != curMol) { nmol++; curMol = mol; } } value = integerToString( nmol ); } else { mprinterr("Error: Expected 'atoms', 'residues', or 'molecules'.\n"); return CpptrajState::ERR; } } else if (equals.hasKey("trajinframes")) { value = integerToString(State.InputTrajList().MaxFrames()); } else value = equals.ArgLineStr(); if (append) CurrentVars.AppendVariable( "$" + variable, value ); else CurrentVars.UpdateVariable( "$" + variable, value ); mprintf("\tVariable '%s' set to '%s'\n", variable.c_str(), value.c_str()); for (int iarg = 0; iarg < argIn.Nargs(); iarg++) argIn.MarkArg( iarg ); return CpptrajState::OK; }
/** Set up each mask/integer loop. */ int ControlBlock_For::SetupBlock(CpptrajState& State, ArgList& argIn) { mprintf(" Setting up 'for' loop.\n"); Vars_.clear(); Topology* currentTop = 0; static const char* TypeStr[] = { "ATOMS ", "RESIDUES ", "MOLECULES ", "MOL_FIRST_RES ", "MOL_LAST_RES " }; static const char* OpStr[] = {"+=", "-=", "<", ">"}; description_.assign("for ("); int MaxIterations = -1; int iarg = 0; while (iarg < argIn.Nargs()) { // Advance to next unmarked argument. while (iarg < argIn.Nargs() && argIn.Marked(iarg)) iarg++; if (iarg == argIn.Nargs()) break; // Determine 'for' type ForType ftype = UNKNOWN; bool isMaskFor = true; int argToMark = iarg; if ( argIn[iarg] == "atoms" ) ftype = ATOMS; else if ( argIn[iarg] == "residues" ) ftype = RESIDUES; else if ( argIn[iarg] == "molecules" ) ftype = MOLECULES; else if ( argIn[iarg] == "molfirstres" ) ftype = MOLFIRSTRES; else if ( argIn[iarg] == "mollastres" ) ftype = MOLLASTRES; else if ( argIn[iarg].find(";") != std::string::npos ) { isMaskFor = false; ftype = INTEGER; } // If type is still unknown, check for list. if (ftype == UNKNOWN) { if (iarg+1 < argIn.Nargs() && argIn[iarg+1] == "in") { ftype = LIST; isMaskFor = false; argToMark = iarg+1; } } // Exit if type could not be determined. if (ftype == UNKNOWN) { mprinterr("Error: for loop type not specfied.\n"); return 1; } argIn.MarkArg(argToMark); Vars_.push_back( LoopVar() ); LoopVar& MH = Vars_.back(); int Niterations = -1; // Set up for specific type if (description_ != "for (") description_.append(", "); // ------------------------------------------- if (isMaskFor) { // {atoms|residues|molecules} <var> inmask <mask> [TOP KEYWORDS] if (argIn[iarg+2] != "inmask") { mprinterr("Error: Expected 'inmask', got %s\n", argIn[iarg+2].c_str()); return 1; } AtomMask currentMask; if (currentMask.SetMaskString( argIn.GetStringKey("inmask") )) return 1; MH.varType_ = ftype; Topology* top = State.DSL().GetTopByIndex( argIn ); if (top != 0) currentTop = top; if (currentTop == 0) return 1; MH.varname_ = argIn.GetStringNext(); if (MH.varname_.empty()) { mprinterr("Error: 'for inmask': missing variable name.\n"); return 1; } MH.varname_ = "$" + MH.varname_; // Set up mask if (currentTop->SetupIntegerMask( currentMask )) return 1; currentMask.MaskInfo(); if (currentMask.None()) return 1; // Set up indices if (MH.varType_ == ATOMS) MH.Idxs_ = currentMask.Selected(); else if (MH.varType_ == RESIDUES) { int curRes = -1; for (AtomMask::const_iterator at = currentMask.begin(); at != currentMask.end(); ++at) { int res = (*currentTop)[*at].ResNum(); if (res != curRes) { MH.Idxs_.push_back( res ); curRes = res; } } } else if (MH.varType_ == MOLECULES || MH.varType_ == MOLFIRSTRES || MH.varType_ == MOLLASTRES) { int curMol = -1; for (AtomMask::const_iterator at = currentMask.begin(); at != currentMask.end(); ++at) { int mol = (*currentTop)[*at].MolNum(); if (mol != curMol) { if (MH.varType_ == MOLECULES) MH.Idxs_.push_back( mol ); else { int res; if (MH.varType_ == MOLFIRSTRES) res = (*currentTop)[ currentTop->Mol( mol ).BeginAtom() ].ResNum(); else // MOLLASTRES res = (*currentTop)[ currentTop->Mol( mol ).EndAtom()-1 ].ResNum(); MH.Idxs_.push_back( res ); } curMol = mol; } } } Niterations = (int)MH.Idxs_.size(); description_.append(std::string(TypeStr[MH.varType_]) + MH.varname_ + " inmask " + currentMask.MaskExpression()); // ------------------------------------------- } else if (ftype == INTEGER) { // [<var>=<start>;[<var><OP><end>;]<var><OP>[<value>]] MH.varType_ = ftype; ArgList varArg( argIn[iarg], ";" ); if (varArg.Nargs() < 2 || varArg.Nargs() > 3) { mprinterr("Error: Malformed 'for' loop variable.\n" "Error: Expected '[<var>=<start>;[<var><OP><end>;]<var><OP>[<value>]]'\n" "Error: Got '%s'\n", argIn[iarg].c_str()); return 1; } // First argument: <var>=<start> ArgList startArg( varArg[0], "=" ); if (startArg.Nargs() != 2) { mprinterr("Error: Malformed 'start' argument.\n" "Error: Expected <var>=<start>, got '%s'\n", varArg[0].c_str()); return 1; } MH.varname_ = startArg[0]; if (!validInteger(startArg[1])) { // TODO allow variables mprinterr("Error: Start argument must be an integer.\n"); return 1; } else MH.start_ = convertToInteger(startArg[1]); // Second argument: <var><OP><end> size_t pos0 = MH.varname_.size(); size_t pos1 = pos0 + 1; MH.endOp_ = NO_OP; int iargIdx = 1; if (varArg.Nargs() == 3) { iargIdx = 2; if ( varArg[1][pos0] == '<' ) MH.endOp_ = LESS_THAN; else if (varArg[1][pos0] == '>') MH.endOp_ = GREATER_THAN; if (MH.endOp_ == NO_OP) { mprinterr("Error: Unrecognized end op: '%s'\n", varArg[1].substr(pos0, pos1-pos0).c_str()); return 1; } std::string endStr = varArg[1].substr(pos1); if (!validInteger(endStr)) { // TODO allow variables mprinterr("Error: End argument must be an integer.\n"); return 1; } else MH.end_ = convertToInteger(endStr); } // Third argument: <var><OP>[<value>] pos1 = pos0 + 2; MH.incOp_ = NO_OP; bool needValue = false; if ( varArg[iargIdx][pos0] == '+' ) { if (varArg[iargIdx][pos0+1] == '+') { MH.incOp_ = INCREMENT; MH.inc_ = 1; } else if (varArg[iargIdx][pos0+1] == '=') { MH.incOp_ = INCREMENT; needValue = true; } } else if ( varArg[iargIdx][pos0] == '-' ) { if (varArg[iargIdx][pos0+1] == '-' ) { MH.incOp_ = DECREMENT; MH.inc_ = 1; } else if (varArg[iargIdx][pos0+1] == '=') { MH.incOp_ = DECREMENT; needValue = true; } } if (MH.incOp_ == NO_OP) { mprinterr("Error: Unrecognized increment op: '%s'\n", varArg[iargIdx].substr(pos0, pos1-pos0).c_str()); return 1; } if (needValue) { std::string incStr = varArg[iargIdx].substr(pos1); if (!validInteger(incStr)) { mprinterr("Error: increment value is not a valid integer.\n"); return 1; } MH.inc_ = convertToInteger(incStr); if (MH.inc_ < 1) { mprinterr("Error: Extra '-' detected in increment.\n"); return 1; } } // Description MH.varname_ = "$" + MH.varname_; std::string sval = integerToString(MH.start_); description_.append("(" + MH.varname_ + "=" + sval + "; "); std::string eval; if (iargIdx == 2) { // End argument present eval = integerToString(MH.end_); description_.append(MH.varname_ + std::string(OpStr[MH.endOp_]) + eval + "; "); // Check end > start for increment, start > end for decrement int maxval, minval; if (MH.incOp_ == INCREMENT) { if (MH.start_ >= MH.end_) { mprinterr("Error: start must be less than end for increment.\n"); return 1; } minval = MH.start_; maxval = MH.end_; } else { if (MH.end_ >= MH.start_) { mprinterr("Error: end must be less than start for decrement.\n"); return 1; } minval = MH.end_; maxval = MH.start_; } // Figure out number of iterations Niterations = (maxval - minval) / MH.inc_; if (((maxval-minval) % MH.inc_) > 0) Niterations++; } description_.append( MH.varname_ + std::string(OpStr[MH.incOp_]) + integerToString(MH.inc_) + ")" ); // If decrementing just negate value if (MH.incOp_ == DECREMENT) MH.inc_ = -MH.inc_; // DEBUG //mprintf("DEBUG: start=%i endOp=%i end=%i incOp=%i val=%i startArg=%s endArg=%s\n", // MH.start_, (int)MH.endOp_, MH.end_, (int)MH.incOp_, MH.inc_, // MH.startArg_.c_str(), MH.endArg_.c_str()); // ------------------------------------------- } else if (ftype == LIST) { // <var> in <string0>[,<string1>...] MH.varType_ = ftype; // Variable name MH.varname_ = argIn.GetStringNext(); if (MH.varname_.empty()) { mprinterr("Error: 'for in': missing variable name.\n"); return 1; } MH.varname_ = "$" + MH.varname_; // Comma-separated list of strings std::string listArg = argIn.GetStringNext(); if (listArg.empty()) { mprinterr("Error: 'for in': missing comma-separated list of strings.\n"); return 1; } ArgList list(listArg, ","); if (list.Nargs() < 1) { mprinterr("Error: Could not parse '%s' for 'for in'\n", listArg.c_str()); return 1; } for (int il = 0; il != list.Nargs(); il++) { // Check if file name expansion should occur if (list[il].find_first_of("*?") != std::string::npos) { File::NameArray files = File::ExpandToFilenames( list[il] ); for (File::NameArray::const_iterator fn = files.begin(); fn != files.end(); ++fn) MH.List_.push_back( fn->Full() ); } else MH.List_.push_back( list[il] ); } Niterations = (int)MH.List_.size(); // Description description_.append( MH.varname_ + " in " + listArg ); } // Check number of values if (MaxIterations == -1) MaxIterations = Niterations; else if (Niterations != -1 && Niterations != MaxIterations) { mprintf("Warning: # iterations %i != previous # iterations %i\n", Niterations, MaxIterations); MaxIterations = std::min(Niterations, MaxIterations); } } mprintf("\tLoop will execute for %i iterations.\n", MaxIterations); if (MaxIterations < 1) { mprinterr("Error: Loop has less than 1 iteration.\n"); return 1; } description_.append(") do"); return 0; }
// Action_Diffusion::Init() Action::RetType Action_Diffusion::Init(ArgList& actionArgs, ActionInit& init, int debugIn) { # ifdef MPI trajComm_ = init.TrajComm(); # endif debug_ = debugIn; image_.InitImaging( !(actionArgs.hasKey("noimage")) ); // Determine if this is old syntax or new. if (actionArgs.Nargs() > 2 && actionArgs.ArgIsMask(1) && validDouble(actionArgs[2])) { // Old syntax: <mask> <time per frame> [average] [<prefix>] printIndividual_ = !(actionArgs.hasKey("average")); calcDiffConst_ = false; mprintf("Warning: Deprecated syntax for 'diffusion'. Consider using new syntax:\n"); ShortHelp(); mask_.SetMaskString( actionArgs.GetMaskNext() ); time_ = actionArgs.getNextDouble(1.0); if (CheckTimeArg(time_)) return Action::ERR; std::string outputNameRoot = actionArgs.GetStringNext(); // Default filename: 'diffusion' if (outputNameRoot.empty()) outputNameRoot.assign("diffusion"); // Open output files ArgList oldArgs("prec 8.3 noheader"); DataFile::DataFormatType dft = DataFile::DATAFILE; outputx_ = init.DFL().AddDataFile(outputNameRoot+"_x.xmgr", dft, oldArgs); outputy_ = init.DFL().AddDataFile(outputNameRoot+"_y.xmgr", dft, oldArgs); outputz_ = init.DFL().AddDataFile(outputNameRoot+"_z.xmgr", dft, oldArgs); outputr_ = init.DFL().AddDataFile(outputNameRoot+"_r.xmgr", dft, oldArgs); outputa_ = init.DFL().AddDataFile(outputNameRoot+"_a.xmgr", dft, oldArgs); } else { // New syntax: [{separateout <suffix> | out <filename>}] [time <time per frame>] // [<mask>] [<set name>] [individual] [diffout <filename>] [nocalc] printIndividual_ = actionArgs.hasKey("individual"); calcDiffConst_ = !(actionArgs.hasKey("nocalc")); std::string suffix = actionArgs.GetStringKey("separateout"); std::string outname = actionArgs.GetStringKey("out"); if (!outname.empty() && !suffix.empty()) { mprinterr("Error: Specify either 'out' or 'separateout', not both.\n"); return Action::ERR; } diffout_ = init.DFL().AddDataFile(actionArgs.GetStringKey("diffout")); time_ = actionArgs.getKeyDouble("time", 1.0); if (CheckTimeArg(time_)) return Action::ERR; mask_.SetMaskString( actionArgs.GetMaskNext() ); // Open output files. if (!suffix.empty()) { FileName FName( suffix ); outputx_ = init.DFL().AddDataFile(FName.PrependFileName("x_"), actionArgs); outputy_ = init.DFL().AddDataFile(FName.PrependFileName("y_"), actionArgs); outputz_ = init.DFL().AddDataFile(FName.PrependFileName("z_"), actionArgs); outputr_ = init.DFL().AddDataFile(FName.PrependFileName("r_"), actionArgs); outputa_ = init.DFL().AddDataFile(FName.PrependFileName("a_"), actionArgs); if (diffout_ == 0 && calcDiffConst_) diffout_ = init.DFL().AddDataFile(FName.PrependFileName("diff_"), actionArgs); } else if (!outname.empty()) { outputr_ = init.DFL().AddDataFile( outname, actionArgs ); outputx_ = outputy_ = outputz_ = outputa_ = outputr_; } } if (diffout_ != 0) calcDiffConst_ = true; // Add DataSets dsname_ = actionArgs.GetStringNext(); if (dsname_.empty()) dsname_ = init.DSL().GenerateDefaultName("Diff"); avg_x_ = init.DSL().AddSet(DataSet::DOUBLE, MetaData(dsname_, "X")); avg_y_ = init.DSL().AddSet(DataSet::DOUBLE, MetaData(dsname_, "Y")); avg_z_ = init.DSL().AddSet(DataSet::DOUBLE, MetaData(dsname_, "Z")); avg_r_ = init.DSL().AddSet(DataSet::DOUBLE, MetaData(dsname_, "R")); avg_a_ = init.DSL().AddSet(DataSet::DOUBLE, MetaData(dsname_, "A")); if (avg_x_ == 0 || avg_y_ == 0 || avg_z_ == 0 || avg_r_ == 0 || avg_a_ == 0) return Action::ERR; if (outputr_ != 0) outputr_->AddDataSet( avg_r_ ); if (outputx_ != 0) outputx_->AddDataSet( avg_x_ ); if (outputy_ != 0) outputy_->AddDataSet( avg_y_ ); if (outputz_ != 0) outputz_->AddDataSet( avg_z_ ); if (outputa_ != 0) outputa_->AddDataSet( avg_a_ ); // Set X dim Xdim_ = Dimension(0.0, time_, "Time"); avg_x_->SetDim(Dimension::X, Xdim_); avg_y_->SetDim(Dimension::X, Xdim_); avg_z_->SetDim(Dimension::X, Xdim_); avg_r_->SetDim(Dimension::X, Xdim_); avg_a_->SetDim(Dimension::X, Xdim_); // Add DataSets for diffusion constant calc if (calcDiffConst_) { MetaData::tsType ts = MetaData::NOT_TS; diffConst_ = init.DSL().AddSet(DataSet::DOUBLE, MetaData(dsname_, "D", ts)); diffLabel_ = init.DSL().AddSet(DataSet::STRING, MetaData(dsname_, "Label", ts)); diffSlope_ = init.DSL().AddSet(DataSet::DOUBLE, MetaData(dsname_, "Slope", ts)); diffInter_ = init.DSL().AddSet(DataSet::DOUBLE, MetaData(dsname_, "Intercept", ts)); diffCorrl_ = init.DSL().AddSet(DataSet::DOUBLE, MetaData(dsname_, "Corr", ts)); if (diffConst_ == 0 || diffLabel_ == 0 || diffSlope_ == 0 || diffInter_ == 0 || diffCorrl_ == 0) return Action::ERR; # ifdef MPI // No sync needed since these are not time series diffConst_->SetNeedsSync( false ); diffLabel_->SetNeedsSync( false ); diffSlope_->SetNeedsSync( false ); diffInter_->SetNeedsSync( false ); diffCorrl_->SetNeedsSync( false ); # endif if (diffout_ != 0) { diffout_->AddDataSet( diffConst_ ); diffout_->AddDataSet( diffSlope_ ); diffout_->AddDataSet( diffInter_ ); diffout_->AddDataSet( diffCorrl_ ); diffout_->AddDataSet( diffLabel_ ); } Dimension Ddim( 1, 1, "Set" ); diffConst_->SetDim(Dimension::X, Ddim); diffLabel_->SetDim(Dimension::X, Ddim); diffSlope_->SetDim(Dimension::X, Ddim); diffInter_->SetDim(Dimension::X, Ddim); diffCorrl_->SetDim(Dimension::X, Ddim); } // Save master data set list, needed when printIndividual_ masterDSL_ = init.DslPtr(); mprintf(" DIFFUSION:\n"); mprintf("\tAtom Mask is [%s]\n", mask_.MaskString()); if (printIndividual_) mprintf("\tBoth average and individual diffusion will be calculated.\n"); else mprintf("\tOnly average diffusion will be calculated.\n"); mprintf("\tData set base name: %s\n", avg_x_->Meta().Name().c_str()); if (image_.UseImage()) mprintf("\tCorrections for imaging enabled.\n"); else mprintf("\tCorrections for imaging disabled.\n"); // If one file defined, assume all are. if (outputx_ != 0) { mprintf("\tOutput files:\n" "\t %s: (x) Mean square displacement(s) in the X direction (in Ang.^2).\n" "\t %s: (y) Mean square displacement(s) in the Y direction (in Ang.^2).\n" "\t %s: (z) Mean square displacement(s) in the Z direction (in Ang.^2).\n" "\t %s: (r) Overall mean square displacement(s) (in Ang.^2).\n" "\t %s: (a) Total distance travelled (in Ang.).\n", outputx_->DataFilename().full(), outputy_->DataFilename().full(), outputz_->DataFilename().full(), outputr_->DataFilename().full(), outputa_->DataFilename().full()); } mprintf("\tThe time between frames is %g ps.\n", time_); if (calcDiffConst_) { mprintf("\tCalculating diffusion constants by fitting slope to MSD vs time\n" "\t and multiplying by 10.0/2*N (where N is # of dimensions), units\n" "\t are 1x10^-5 cm^2/s.\n"); if (diffout_ != 0) mprintf("\tDiffusion constant output to '%s'\n", diffout_->DataFilename().full()); else mprintf("\tDiffusion constant output to STDOUT.\n"); } else mprintf("\tTo calculate diffusion constant from mean squared displacement plots,\n" "\t calculate the slope of MSD vs time and multiply by 10.0/2*N (where N\n" "\t is # of dimensions); this will give units of 1x10^-5 cm^2/s.\n"); return Action::OK; }
// Action_Watershell::Init() Action::RetType Action_Watershell::Init(ArgList& actionArgs, ActionInit& init, int debugIn) { image_.InitImaging( !actionArgs.hasKey("noimage") ); // Get keywords std::string filename = actionArgs.GetStringKey("out"); lowerCutoff_ = actionArgs.getKeyDouble("lower", 3.4); upperCutoff_ = actionArgs.getKeyDouble("upper", 5.0); // Get solute mask std::string maskexpr = actionArgs.GetMaskNext(); if (maskexpr.empty()) { mprinterr("Error: Solute mask must be specified.\n"); return Action::ERR; } soluteMask_.SetMaskString( maskexpr ); // Check for solvent mask std::string solventmaskexpr = actionArgs.GetMaskNext(); if (!solventmaskexpr.empty()) solventMask_.SetMaskString( solventmaskexpr ); // For backwards compat., if no 'out' assume next string is file name if (filename.empty() && actionArgs.Nargs() > 2 && !actionArgs.Marked(2)) filename = actionArgs.GetStringNext(); DataFile* outfile = init.DFL().AddDataFile( filename, actionArgs ); // Set up datasets std::string dsname = actionArgs.GetStringNext(); if (dsname.empty()) dsname = init.DSL().GenerateDefaultName("WS"); lower_ = init.DSL().AddSet(DataSet::INTEGER, MetaData(dsname, "lower")); upper_ = init.DSL().AddSet(DataSet::INTEGER, MetaData(dsname, "upper")); if (lower_ == 0 || upper_ == 0) return Action::ERR; if (outfile != 0) { outfile->AddDataSet(lower_); outfile->AddDataSet(upper_); } # ifndef CUDA # ifdef _OPENMP // Determine number of parallel threads int numthreads = 0; #pragma omp parallel { if (omp_get_thread_num()==0) numthreads = omp_get_num_threads(); } shellStatus_thread_.resize( numthreads ); # endif # endif mprintf(" WATERSHELL:"); if (outfile != 0) mprintf(" Output to %s", outfile->DataFilename().full()); mprintf("\n"); if (!image_.UseImage()) mprintf("\tImaging is disabled.\n"); mprintf("\tThe first shell will contain solvent < %.3f angstroms from\n", lowerCutoff_); mprintf("\t the solute; the second shell < %.3f angstroms...\n", upperCutoff_); mprintf("\tSolute atoms will be specified by [%s]\n",soluteMask_.MaskString()); if (solventMask_.MaskStringSet()) mprintf("\tSolvent atoms will be specified by [%s]\n", solventMask_.MaskString()); #ifdef CUDA mprintf("\tDistance calculations will be GPU-accelerated with CUDA.\n"); #else # ifdef _OPENMP if (shellStatus_thread_.size() > 1) mprintf("\tParallelizing calculation with %zu threads.\n", shellStatus_thread_.size()); # endif #endif mprintf("\t# solvent molecules in 'lower' shell stored in set '%s'\n", lower_->legend()); mprintf("\t# solvent molecules in 'upper' shell stored in set '%s'\n", upper_->legend()); // Pre-square upper and lower cutoffs lowerCutoff_ *= lowerCutoff_; upperCutoff_ *= upperCutoff_; return Action::OK; }
// DataIO_Std::Read_1D() int DataIO_Std::Read_1D(std::string const& fname, DataSetList& datasetlist, std::string const& dsname) { ArgList labels; bool hasLabels = false; // Buffer file BufferedLine buffer; if (buffer.OpenFileRead( fname )) return 1; // Read the first line. Attempt to determine the number of columns const char* linebuffer = buffer.Line(); if (linebuffer == 0) return 1; int ntoken = buffer.TokenizeLine( SEPARATORS ); if ( ntoken == 0 ) { mprinterr("Error: No columns detected in %s\n", buffer.Filename().full()); return 1; } // Try to skip past any comments. If line begins with a '#', assume it // contains labels. bool isCommentLine = true; const char* ptr = linebuffer; while (isCommentLine) { // Skip past any whitespace while ( *ptr != '\0' && isspace(*ptr) ) ++ptr; // Assume these are column labels until proven otherwise. if (*ptr == '#') { labels.SetList(ptr+1, SEPARATORS ); if (!labels.empty()) { hasLabels = true; // If first label is Frame assume it is the index column if (labels[0] == "Frame" && indexcol_ == -1) indexcol_ = 0; } linebuffer = buffer.Line(); ptr = linebuffer; if (ptr == 0) { mprinterr("Error: No data found in file.\n"); return 1; } } else // Not a recognized comment character, assume data. isCommentLine = false; } // Special case: check if labels are '#F1 F2 <name> [nframes <#>]'. If so, assume // this is a cluster matrix file. if ((labels.Nargs() == 3 || labels.Nargs() == 5) && labels[0] == "F1" && labels[1] == "F2") { mprintf("Warning: Header format '#F1 F2 <name>' detected, assuming cluster pairwise matrix.\n"); return IS_ASCII_CMATRIX; } // Column user args start from 1 if (indexcol_ > -1) mprintf("\tUsing column %i as index column.\n", indexcol_ + 1); // Should be at first data line. Tokenize the line. ntoken = buffer.TokenizeLine( SEPARATORS ); // If # of data columns does not match # labels, clear labels. if ( !labels.empty() && ntoken != labels.Nargs() ) { labels.ClearList(); hasLabels = false; } // Index column checks if (indexcol_ != -1 ) { if (indexcol_ >= ntoken) { mprinterr("Error: Specified index column %i is out of range (%i columns).\n", indexcol_+1, ntoken); return 1; } if (!onlycols_.Empty() && !onlycols_.InRange(indexcol_)) { mprinterr("Error: Index column %i specified, but not in given column range '%s'\n", indexcol_+1, onlycols_.RangeArg()); return 1; } } // Determine the type of data stored in each column. Assume numbers should // be read with double precision. MetaData md( dsname ); DataSetList::DataListType inputSets; unsigned int nsets = 0; for (int col = 0; col != ntoken; ++col) { std::string token( buffer.NextToken() ); if (!onlycols_.Empty() && !onlycols_.InRange( col )) { mprintf("\tSkipping column %i\n", col+1); inputSets.push_back( 0 ); } else { md.SetIdx( col+1 ); if (hasLabels) md.SetLegend( labels[col] ); if ( col == indexcol_ ) { // Always save the index column as floating point inputSets.push_back( new DataSet_double() ); } else if (validInteger(token)) { // Integer number inputSets.push_back( datasetlist.Allocate(DataSet::INTEGER) ); } else if (validDouble(token)) { // Floating point number inputSets.push_back( new DataSet_double() ); } else { // Assume string. Not allowed for index column. if (col == indexcol_) { mprintf("Warning: '%s' index column %i has string values. No indices will be read.\n", buffer.Filename().full(), indexcol_+1); indexcol_ = -1; } inputSets.push_back( new DataSet_string() ); } inputSets.back()->SetMeta( md ); nsets++; } } if (inputSets.empty() || nsets == 0) { mprinterr("Error: No data detected.\n"); return 1; } // Read in data while (linebuffer != 0) { if ( buffer.TokenizeLine( SEPARATORS ) != ntoken ) { PrintColumnError(buffer.LineNumber()); break; } // Convert data in columns for (int i = 0; i < ntoken; ++i) { const char* token = buffer.NextToken(); if (inputSets[i] != 0) { if (inputSets[i]->Type() == DataSet::DOUBLE) ((DataSet_double*)inputSets[i])->AddElement( atof(token) ); else if (inputSets[i]->Type() == DataSet::INTEGER) ((DataSet_integer*)inputSets[i])->AddElement( atoi(token) ); else ((DataSet_string*)inputSets[i])->AddElement( std::string(token) ); } } //Ndata++; linebuffer = buffer.Line(); } buffer.CloseFile(); mprintf("\tDataFile %s has %i columns, %i lines.\n", buffer.Filename().full(), ntoken, buffer.LineNumber()); // Create list containing only data sets. DataSetList::DataListType mySets; DataSet_double* Xptr = 0; for (int idx = 0; idx != (int)inputSets.size(); idx++) { if (inputSets[idx] != 0) { if ( idx != indexcol_ ) mySets.push_back( inputSets[idx] ); else Xptr = (DataSet_double*)inputSets[idx]; } } mprintf("\tRead %zu data sets.\n", mySets.size()); std::string Xlabel; if (indexcol_ != -1 && indexcol_ < labels.Nargs()) Xlabel = labels[indexcol_]; if (Xptr == 0) datasetlist.AddOrAppendSets(Xlabel, DataSetList::Darray(), mySets); else { datasetlist.AddOrAppendSets(Xlabel, Xptr->Data(), mySets); delete Xptr; } return 0; }