/** 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; }
/** 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; }
// Exec_DataSetCmd::ModifyPoints() Exec::RetType Exec_DataSetCmd::ModifyPoints(CpptrajState& State, ArgList& argIn, bool drop) { const char* mode; if (drop) mode = "Drop"; else mode = "Kee"; // Keywords std::string name = argIn.GetStringKey("name"); int start = argIn.getKeyInt("start", 0) - 1; int stop = argIn.getKeyInt("stop", -1); int offset = argIn.getKeyInt("offset", -1); Range points; if (start < 0 && stop < 0 && offset < 0) { std::string rangearg = argIn.GetStringKey("range"); if (rangearg.empty()) { mprinterr("Error: Must specify range or start/stop/offset.\n"); return CpptrajState::ERR; } points.SetRange( rangearg ); if (points.Empty()) { mprinterr("Error: Range '%s' is empty.\n", rangearg.c_str()); return CpptrajState::ERR; } mprintf("\t%sping points in range %s\n", mode, rangearg.c_str()); // User args start from 1 points.ShiftBy(-1); } // Get data set to drop/keep points from // Loop over all DataSet arguments std::string ds_arg = argIn.GetStringNext(); while (!ds_arg.empty()) { DataSetList dsl = State.DSL().GetMultipleSets( ds_arg ); for (DataSetList::const_iterator it = dsl.begin(); it != dsl.end(); ++it) { DataSet* DS = *it; if (DS->Size() < 1) { mprinterr("Error: Set '%s' is empty.\n", DS->legend()); return CpptrajState::ERR; } // Restrict to 1D sets for now TODO more types if (DS->Group() != DataSet::SCALAR_1D) { mprinterr("Error: Currently only works for 1D scalar data sets.\n"); return CpptrajState::ERR; } DataSet_1D* ds1 = (DataSet_1D*)DS; // Output data set DataSet* out = 0; if (name.empty()) { // Modifying this set. Create new temporary set. out = State.DSL().Allocate( ds1->Type() ); if (out == 0) return CpptrajState::ERR; *out = *ds1; mprintf("\tOverwriting set '%s'\n", ds1->legend()); } else { // Write to new set MetaData md = ds1->Meta(); md.SetName( name ); out = State.DSL().AddSet(ds1->Type(), md); if (out == 0) return CpptrajState::ERR; mprintf("\tNew set is '%s'\n", out->Meta().PrintName().c_str()); } out->Allocate(DataSet::SizeArray(1, ds1->Size())); if (points.Empty()) { // Drop by start/stop/offset. Set defaults if needed if (start < 0) start = 0; if (stop < 0) stop = ds1->Size(); if (offset < 0) offset = 1; mprintf("\t%sping points from %i to %i, step %i\n", mode, start+1, stop, offset); for (int idx = start; idx < stop; idx += offset) points.AddToRange( idx ); } // TODO check that range values are valid? if (State.Debug() > 0) mprintf("DEBUG: Keeping points:"); Range::const_iterator pt = points.begin(); int idx = 0; int odx = 0; if (drop) { // Drop points for (; idx < (int)ds1->Size(); idx++) { if (pt == points.end()) break; if (*pt != idx) { if (State.Debug() > 0) mprintf(" %i", idx + 1); KeepPoint(ds1, out, idx, odx); } else ++pt; } // Keep all remaining points for (; idx < (int)ds1->Size(); idx++) { if (State.Debug() > 0) mprintf(" %i", idx + 1); KeepPoint(ds1, out, idx, odx); } } else { // Keep points for (; pt != points.end(); pt++) { if (*pt >= (int)ds1->Size()) break; if (State.Debug() > 0) mprintf(" %i", *pt + 1); KeepPoint(ds1, out, *pt, odx); } } if (State.Debug() > 0) mprintf("\n"); if (name.empty()) { // Replace old set with new set State.DSL().RemoveSet( ds1 ); State.DSL().AddSet( out ); } } // END loop over sets ds_arg = argIn.GetStringNext(); } // END loop over set args return CpptrajState::OK; }
/** Given an array of already set up data sets (from e.g. input data files) * and optional X values, add the sets to this list if they do not exist * or append any existing sets. */ int DataSetList::AddOrAppendSets(std::string const& XlabelIn, Darray const& Xvals, DataListType const& Sets) { if (debug_ > 0) mprintf("DEBUG: Calling AddOrAppendSets for %zu sets, %zu X values, Xlabel= %s.\n", Sets.size(), Xvals.size(), XlabelIn.c_str()); if (Sets.empty()) return 0; // No error for now. // If no X label assume 'Frame' for backwards compat. std::string Xlabel; if (XlabelIn.empty()) Xlabel.assign("Frame"); else Xlabel = XlabelIn; Dimension Xdim; // First determine if X values increase monotonically with a regular step bool isMonotonic = true; double xstep = 1.0; if (Xvals.size() > 1) { xstep = (Xvals.back() - Xvals.front()) / (double)(Xvals.size() - 1); for (Darray::const_iterator X = Xvals.begin()+2; X != Xvals.end(); ++X) if ((*X - *(X-1)) - xstep > Constants::SMALL) { isMonotonic = false; break; } // Set dim even for non-monotonic sets so Label is correct. FIXME is this ok? Xdim = Dimension( Xvals.front(), xstep, Xlabel ); } else // No X values. set generic X dim. Xdim = Dimension(1.0, 1.0, Xlabel); if (debug_ > 0) { mprintf("DEBUG: xstep %g xmin %g\n", Xdim.Step(), Xdim.Min()); if (isMonotonic) mprintf("DEBUG: Xdim is monotonic.\n"); } for (const_iterator ds = Sets.begin(); ds != Sets.end(); ++ds) { if (*ds == 0) continue; // TODO: Warn about blanks? if (debug_ > 0) mprintf("DEBUG: AddOrAppend set '%s'", (*ds)->legend()); if (isMonotonic) (*ds)->SetDim(Dimension::X, Xdim); DataSet* existingSet = CheckForSet( (*ds)->Meta() ); if (existingSet == 0) { // New set. If set is scalar 1D but X values are not monotonic, // convert to XY mesh if necessary. if ( !isMonotonic && (*ds)->Group() == DataSet::SCALAR_1D && (*ds)->Type() != DataSet::XYMESH ) { DataSet* xyptr = AddSet( DataSet::XYMESH, (*ds)->Meta() ); if (xyptr == 0) { mprinterr("Error: Could not convert set %s to XY mesh.\n", (*ds)->legend()); continue; // TODO exit instead? } if ( (*ds)->Size() != Xvals.size() ) { // Sanity check mprinterr("Error: # of X values does not match set %s size.\n", (*ds)->legend()); continue; } DataSet_1D const& set = static_cast<DataSet_1D const&>( *(*ds) ); DataSet_Mesh& xy = static_cast<DataSet_Mesh&>( *xyptr ); for (unsigned int i = 0; i != set.Size(); i++) xy.AddXY( Xvals[i], set.Dval(i) ); xy.SetDim(Dimension::X, Xdim); if (debug_ > 0) mprintf(", New set, converted to XY-MESH\n"); // Free memory since set has now been converted. delete *ds; } else { // No conversion. Just add. (*ds)->SetDim(Dimension::X, Xdim); AddSet( *ds ); if (debug_ > 0) mprintf(", New set\n"); } } else { if (debug_ > 0) mprintf(", appending to existing set\n"); // Set exists. Try to append this set to existing set. bool canAppend = true; if ( (*ds)->Group() == DataSet::GENERIC ) { // For GENERIC sets, base Type must match. // TODO: Should this logic be in DataSets? if ( (*ds)->Type() != existingSet->Type() ) canAppend = false; } else { // For non-GENERIC sets, Group must match if ( (*ds)->Group() != existingSet->Group() ) canAppend = false; } if (!canAppend) mprinterr("Error: Cannot append set of type %s to set of type %s\n", DataArray[(*ds)->Type()].Description, DataArray[existingSet->Type()].Description); // If cannot append or attempt to append fails, rename and add as new set. if (!canAppend || existingSet->Append( *ds )) { // TODO Dimension check? if (canAppend) mprintf("Warning: Append currently not supported for type %s\n", DataArray[existingSet->Type()].Description); MetaData md = (*ds)->Meta(); md.SetName( GenerateDefaultName("X") ); mprintf("Warning: Renaming %s to %s\n", (*ds)->Meta().PrintName().c_str(), md.PrintName().c_str()); (*ds)->SetMeta( md ); AddSet( *ds ); } else // Set was appended to existing set; memory can be freed. delete *ds; } } // END loop over input sets return 0; }
// DataIO_Std::Read_3D() int DataIO_Std::Read_3D(std::string const& fname, DataSetList& datasetlist, std::string const& dsname) { BufferedLine buffer; if (buffer.OpenFileRead( fname )) return 1; mprintf("\tData will be read as 3D grid: X Y Z Value\n"); if (binCorners_) mprintf("\tAssuming X Y Z are bin corners\n"); else mprintf("\tAssuming X Y Z are bin centers\n"); const char* ptr = buffer.Line(); // Check if #counts is present if (strncmp(ptr,"#counts",7)==0) { mprintf("\tReading grid dimensions.\n"); unsigned int counts[3]; sscanf(ptr+7,"%u %u %u", counts, counts+1, counts+2); for (int i = 0; i < 3; i++) { if (dims_[i] == 0) dims_[i] = counts[i]; else if (dims_[i] != (size_t)counts[i]) mprintf("Warning: Specified size for dim %i (%zu) differs from size in file (%u)\n", i, dims_[i], counts[i]); } ptr = buffer.Line(); } if (dims_[0] == 0 || dims_[1] == 0 || dims_[2] == 0) { mprinterr("Error: 'dims' not specified for 'read3d' and no dims in file\n"); return 1; } // Check if #origin is present if (strncmp(ptr,"#origin",7)==0) { mprintf("\tReading grid origin.\n"); double oxyz[3]; sscanf(ptr+7,"%lf %lf %lf", oxyz, oxyz+1, oxyz+2); for (int i = 0; i < 3; i++) { if (!originSpecified_) origin_[i] = oxyz[i]; else if (origin_[i] != oxyz[i]) mprintf("Warning: Specified origin for dim %i (%g) differs from origin in file (%g)\n", i, origin_[i], oxyz[i]); } ptr = buffer.Line(); } // Check if #delta is present bool nonortho = false; Box gridBox; if (strncmp(ptr,"#delta",6)==0) { mprintf("\tReading grid deltas.\n"); double dvals[9]; int ndvals = sscanf(ptr+6,"%lf %lf %lf %lf %lf %lf %lf %lf %lf", dvals, dvals+1, dvals+2, dvals+3, dvals+4, dvals+5, dvals+6, dvals+7, dvals+8); if (ndvals == 3) { for (int i = 0; i < 3; i++) { if (!deltaSpecified_) delta_[i] = dvals[i]; else if (delta_[i] != dvals[i]) mprintf("Warning: Specified delta for dim %i (%g) differs from delta in file (%g)\n", i, delta_[i], dvals[i]); } } else { nonortho = true; dvals[0] *= (double)dims_[0]; dvals[1] *= (double)dims_[0]; dvals[2] *= (double)dims_[0]; dvals[3] *= (double)dims_[1]; dvals[4] *= (double)dims_[1]; dvals[5] *= (double)dims_[1]; dvals[6] *= (double)dims_[2]; dvals[7] *= (double)dims_[2]; dvals[8] *= (double)dims_[2]; gridBox = Box(Matrix_3x3(dvals)); } ptr = buffer.Line(); } // Get or allocate data set DataSet::DataType dtype; if (prec_ == DOUBLE) { dtype = DataSet::GRID_DBL; mprintf("\tGrid is double precision.\n"); } else { dtype = DataSet::GRID_FLT; mprintf("\tGrid is single precision.\n"); } MetaData md( dsname ); DataSet_3D* ds = 0; DataSet* set = datasetlist.CheckForSet( md ); if (set == 0) { ds = (DataSet_3D*)datasetlist.AddSet(dtype, dsname); if (ds == 0) return 1; int err = 0; if (nonortho) err = ds->Allocate_N_O_Box(dims_[0], dims_[1], dims_[2], origin_, gridBox); else err = ds->Allocate_N_O_D(dims_[0], dims_[1], dims_[2], origin_, delta_); if (err != 0) return 1; } else { mprintf("\tAppending to existing set '%s'\n", set->legend()); if (set->Group() != DataSet::GRID_3D) { mprinterr("Error: Set '%s' is not a grid set, cannot append.\n", set->legend()); return 1; } ds = (DataSet_3D*)set; // Check that dimensions line up. TODO check origin etc too? if (dims_[0] != ds->NX() || dims_[1] != ds->NY() || dims_[2] != ds->NZ()) { mprintf("Warning: Specified grid dimensions (%zu %zu %zu) do not match\n" "Warning: '%s' dimensions (%zu %zu %zu)\n", dims_[0], dims_[1], dims_[2], ds->legend(), dims_[0], dims_[1], dims_[2]); } } ds->GridInfo(); // Determine if an offset is needed Vec3 offset(0.0); if (binCorners_) { // Assume XYZ coords are of bin corners. Need to offset coords by half // the voxel size. if (!ds->Bin().IsOrthoGrid()) { GridBin_Nonortho const& b = static_cast<GridBin_Nonortho const&>( ds->Bin() ); offset = b.Ucell().TransposeMult(Vec3( 1/(2*(double)ds->NX()), 1/(2*(double)ds->NY()), 1/(2*(double)ds->NZ()) )); } else { GridBin_Ortho const& b = static_cast<GridBin_Ortho const&>( ds->Bin() ); offset = Vec3(b.DX()/2, b.DY()/2, b.DZ()/2); } } if (debug_ > 0) mprintf("DEBUG: Offset: %E %E %E\n", offset[0], offset[1], offset[2]); // Read file unsigned int nvals = 0; while (ptr != 0) { if (ptr[0] != '#') { int ntokens = buffer.TokenizeLine( SEPARATORS ); if (ntokens != 4) { mprinterr("Error: Expected 4 columns (X, Y, Z, data), got %i\n", ntokens); return 1; } nvals++; double xyzv[4]; xyzv[0] = atof( buffer.NextToken() ); xyzv[1] = atof( buffer.NextToken() ); xyzv[2] = atof( buffer.NextToken() ); xyzv[3] = atof( buffer.NextToken() ); size_t ix, iy, iz; if ( ds->Bin().Calc(xyzv[0]+offset[0], xyzv[1]+offset[1], xyzv[2]+offset[2], ix, iy, iz ) ) ds->UpdateVoxel(ds->CalcIndex(ix, iy, iz), xyzv[3]); else mprintf("Warning: Coordinate out of bounds (%g %g %g, ), line %i\n", xyzv[0], xyzv[1], xyzv[2], buffer.LineNumber()); } ptr = buffer.Line(); } mprintf("\tRead %u values.\n", nvals); return 0; }