// Action_MultiVector::Setup();
Action::RetType Action_MultiVector::Setup(Topology* currentParm, Topology** parmAddress) {
  Range actualRange;
  // If range is empty (i.e. no resrange arg given) look through all 
  // solute residues.
  if (resRange_.Empty())
    actualRange = currentParm->SoluteResidues();
  else {
    // If user range specified, create new range shifted by -1 since internal
    // resnums start from 0.
    actualRange = resRange_;
    actualRange.ShiftBy(-1);
  }
  // Exit if no residues specified
  if (actualRange.Empty()) {
    mprinterr("Error: No residues specified for %s\n",currentParm->c_str());
    return Action::ERR;
  }
  // Set default DataSet name if not specified.
  if (dsetname_.empty())
    dsetname_ = masterDSL_->GenerateDefaultName( "MVEC" );
  // Search for specified atom names in each residue in the range
  CrdIdx1_.clear();
  CrdIdx2_.clear();
  for (Range::const_iterator res = actualRange.begin(); res != actualRange.end(); ++res)
  {
    int atom1 = currentParm->FindAtomInResidue( *res, name1_ );
    int atom2 = currentParm->FindAtomInResidue( *res, name2_ );
    if (atom1 != -1 && atom2 != -1) {
      MetaData md(dsetname_, atom1+1);
      md.SetScalarMode( MetaData::M_VECTOR );
      if (ired_) md.SetScalarType( MetaData::IREDVEC );
      DataSet_Vector* ds = (DataSet_Vector*)masterDSL_->CheckForSet( md );
      if (ds == 0) {
        // Create DataSet
        ds = (DataSet_Vector*)masterDSL_->AddSet( DataSet::VECTOR, md );
        if (ds == 0) return Action::ERR;
        ds->SetLegend( "v" + currentParm->AtomMaskName(atom1) + "->" +
                             currentParm->AtomMaskName(atom2) );
        if (outfile_ != 0) outfile_->AddDataSet( ds );
      }
      data_.push_back( ds );
      CrdIdx1_.push_back( atom1 * 3 ); // Pre calc coordinate index
      CrdIdx2_.push_back( atom2 * 3 );
    } else if ((atom1==-1) != (atom2==-1)) {
      if (atom1==-1)
        mprintf("Warning: '%s' not found but '%s' found for residue %i.\n", 
                *name1_, *name2_, *res + 1);
      else // atom2==-1
        mprintf("Warning: '%s' not found but '%s' found for residue %i.\n",
                *name2_, *name1_, *res + 1);
    }
  }
  mprintf("\tSelected %zu vectors.\n", CrdIdx1_.size());
  for (std::vector<DataSet_Vector*>::const_iterator it = data_.begin();
                                                    it != data_.end(); ++it)
    mprintf("\t  %s\n", (*it)->legend());

  return Action::OK;
}
// Action_MultiDihedral::Setup();
Action::RetType Action_MultiDihedral::Setup(Topology* currentParm, Topology** parmAddress) {
  Range actualRange;
  // If range is empty (i.e. no resrange arg given) look through all 
  // solute residues.
  if (resRange_.Empty())
    actualRange.SetRange(0, currentParm->FinalSoluteRes());
  else {
    // If user range specified, create new range shifted by -1 since internal
    // resnums start from 0.
    actualRange = resRange_;
    actualRange.ShiftBy(-1);
  }
  // Exit if no residues specified
  if (actualRange.Empty()) {
    mprinterr("Error: multidihedral: No residues specified for %s\n",currentParm->c_str());
    return Action::ERR;
  }
  // Search for specified dihedrals in each residue in the range
  if (dihSearch_.FindDihedrals(*currentParm, actualRange))
    return Action::ERR;
  mprintf("\tResRange=[%s]", resRange_.RangeArg());
  dihSearch_.PrintTypes();
  mprintf(", %i dihedrals.\n", dihSearch_.Ndihedrals());

  // Print selected dihedrals, set up DataSets
  data_.clear();
  if (dsetname_.empty())
    dsetname_ = masterDSL_->GenerateDefaultName("MDIH");
  for (DihedralSearch::mask_it dih = dihSearch_.begin();
                               dih != dihSearch_.end(); ++dih)
  {
    int resNum = (*dih).ResNum() + 1;
    // See if Dataset already present
    DataSet* ds = masterDSL_->GetSet(dsetname_, resNum, (*dih).Name());
    if (ds == 0) {
      // Create new DataSet
      ds = masterDSL_->AddSetIdxAspect( DataSet::DOUBLE, dsetname_, resNum, (*dih).Name());
      // Add to outfile
      if (outfile_ != 0)
        outfile_->AddSet( ds );
    }
    // TODO: SetScalar
    if (ds != 0)
      data_.push_back( ds );
    if (debug_ > 0) {
      mprintf("\tDIH [%s]:", ds->Legend().c_str());
      mprintf(" :%i@%i",   (*currentParm)[(*dih).A0()].ResNum()+1, (*dih).A0() + 1);
      mprintf(" :%i@%i",   (*currentParm)[(*dih).A1()].ResNum()+1, (*dih).A1() + 1);
      mprintf(" :%i@%i",   (*currentParm)[(*dih).A2()].ResNum()+1, (*dih).A2() + 1);
      mprintf(" :%i@%i\n", (*currentParm)[(*dih).A3()].ResNum()+1, (*dih).A3() + 1);
    }
  }
  return Action::OK;
}
// Exec_PermuteDihedrals::Execute()
Exec::RetType Exec_PermuteDihedrals::Execute(CpptrajState& State, ArgList& argIn) {
  debug_ = State.Debug();
  mode_ = INTERVAL;
  // Get Keywords - first determine mode
  if (argIn.hasKey("random"))
    mode_ = RANDOM;
  else if (argIn.hasKey("interval"))
    mode_ = INTERVAL;
  // Get input COORDS set
  std::string setname = argIn.GetStringKey("crdset");
  if (setname.empty()) {
    mprinterr("Error: Specify COORDS dataset name with 'crdset'.\n");
    return CpptrajState::ERR;
  }
  DataSet_Coords* CRD = (DataSet_Coords*)State.DSL().FindCoordsSet( setname );
  if (CRD == 0) {
    mprinterr("Error: Could not find COORDS set '%s'\n", setname.c_str());
    return CpptrajState::ERR;
  }
  mprintf("    PERMUTEDIHEDRALS: Using COORDS '%s'\n", CRD->legend());

  // Get residue range
  Range resRange;
  resRange.SetRange(argIn.GetStringKey("resrange"));
  if (!resRange.Empty())
    resRange.ShiftBy(-1); // User res args start from 1
  mprintf("\tPermutating dihedrals in");
  if (resRange.Empty())
    mprintf(" all solute residues.\n");
  else
    mprintf(" residue range [%s]\n", resRange.RangeArg());

  // Determine which angles to search for
  DihedralSearch dihSearch;
  dihSearch.SearchForArgs(argIn);
  // If nothing is enabled, enable all 
  dihSearch.SearchForAll();
  mprintf("\tSearching for types:");
  dihSearch.PrintTypes();
  mprintf("\n");

  // Setup output trajectory
  outframe_ = 0; 
  std::string outfilename = argIn.GetStringKey("outtraj");
  if (!outfilename.empty()) {
    mprintf("\tCoordinates output to '%s'\n", outfilename.c_str());
    Topology* outtop = State.DSL().GetTopology( argIn );
    if (outtop == 0) {
      mprinterr("Error: No topology for output traj.\n");
      return CpptrajState::ERR;
    }
    // Setup output trajectory FIXME: Correct frames for # of rotations
    if (outtraj_.PrepareTrajWrite(outfilename, argIn, CRD->TopPtr(), CRD->CoordsInfo(),
                                  CRD->Size(), TrajectoryFile::UNKNOWN_TRAJ))
      return CpptrajState::ERR;
  }

  // Setup output coords
  outfilename = argIn.GetStringKey("crdout");
  if (!outfilename.empty()) {
    mprintf("\tCoordinates saved to set '%s'\n", outfilename.c_str());
    crdout_ = (DataSet_Coords_CRD*)State.DSL().AddSet(DataSet::COORDS, outfilename);
    if (crdout_ == 0) return CpptrajState::ERR;
    crdout_->CoordsSetup( CRD->Top(), CRD->CoordsInfo() );
  }

  // Get specific mode options.
  double interval_in_deg = 60.0;
  if ( mode_ == INTERVAL ) {
    interval_in_deg = argIn.getNextDouble(60.0);
    mprintf("\tDihedrals will be rotated at intervals of %.2f degrees.\n", interval_in_deg);
  } else if (mode_ == RANDOM) {
    check_for_clashes_ = argIn.hasKey("check");
    checkAllResidues_ = argIn.hasKey("checkallresidues");
    cutoff_ = argIn.getKeyDouble("cutoff",0.8);
    rescutoff_ = argIn.getKeyDouble("rescutoff",10.0);
    backtrack_ = argIn.getKeyInt("backtrack",4);
    increment_ = argIn.getKeyInt("increment",1);
    max_factor_ = argIn.getKeyInt("maxfactor",2);
    int iseed = argIn.getKeyInt("rseed",-1);
    // Output file for # of problems
    DataFile* problemFile = State.DFL().AddDataFile(argIn.GetStringKey("out"), argIn);
    // Dataset to store number of problems
    number_of_problems_ = State.DSL().AddSet(DataSet::INTEGER, argIn.GetStringNext(),"Nprob");
    if (number_of_problems_==0) return CpptrajState::ERR;
   // Add dataset to data file list
    if (problemFile != 0) problemFile->AddDataSet(number_of_problems_);
    // Check validity of args
    if (cutoff_ < Constants::SMALL) {
      mprinterr("Error: cutoff too small.\n");
      return CpptrajState::ERR;
    }
    if (rescutoff_ < Constants::SMALL) {
      mprinterr("Error: rescutoff too small.\n");
      return CpptrajState::ERR;
    }
    if (backtrack_ < 0) {
      mprinterr("Error: backtrack value must be >= 0\n");
      return CpptrajState::ERR;
    }
    if ( increment_<1 || (360 % increment_)!=0 ) {
      mprinterr("Error: increment must be a factor of 360.\n");
      return CpptrajState::ERR;
    }
    // Calculate max increment
    max_increment_ = 360 / increment_;
    // Seed random number gen
    RN_.rn_set( iseed );
    // Print info
    mprintf("\tDihedrals will be rotated to random values.\n");
    if (iseed==-1)
      mprintf("\tRandom number generator will be seeded using time.\n");
    else
      mprintf("\tRandom number generator will be seeded using %i\n",iseed);
    if (check_for_clashes_) {
      mprintf("\tWill attempt to recover from bad steric clashes.\n");
      if (checkAllResidues_)
        mprintf("\tAll residues will be checked.\n");
      else
        mprintf("\tResidues up to the currenly rotating dihedral will be checked.\n");
      mprintf("\tAtom cutoff %.2f, residue cutoff %.2f, backtrack = %i\n",
              cutoff_, rescutoff_, backtrack_);
      mprintf("\tWhen clashes occur dihedral will be incremented by %i\n",increment_);
      mprintf("\tMax # attempted rotations = %i times number dihedrals.\n",
              max_factor_);
    }
    // Square cutoffs to compare to dist^2 instead of dist
    cutoff_ *= cutoff_;
    rescutoff_ *= rescutoff_;
    // Increment backtrack by 1 since we need to skip over current res
    ++backtrack_;
    // Initialize CheckStructure
    if (checkStructure_.SetOptions( false, false, false, State.Debug(), "*", "", 0.8, 1.15, 4.0 )) {
      mprinterr("Error: Could not set up structure check.\n");
      return CpptrajState::ERR;
    }
    // Set up CheckStructure for this parm (false = nobondcheck)
    if (checkStructure_.Setup(CRD->Top(), CRD->CoordsInfo().TrajBox()))
      return CpptrajState::ERR;
  }

  // Determine from selected mask atoms which dihedrals will be rotated.
  PermuteDihedralsType dst;
  // If range is empty (i.e. no resrange arg given) look through all 
  // solute residues.
  Range actualRange;
  if (resRange.Empty())
    actualRange = CRD->Top().SoluteResidues();
  else 
    actualRange = resRange;
  // Search for dihedrals
  if (dihSearch.FindDihedrals(CRD->Top(), actualRange))
    return CpptrajState::ERR;
  // For each found dihedral, set up mask of atoms that will move upon 
  // rotation. Also set up mask of atoms in this residue that will not
  // move, including atom2.
  if (debug_>0)
    mprintf("DEBUG: Dihedrals:\n");
  for (DihedralSearch::mask_it dih = dihSearch.begin();
                               dih != dihSearch.end(); ++dih)
  {
    dst.checkAtoms.clear();
    // Set mask of atoms that will move during dihedral rotation.
    dst.Rmask = DihedralSearch::MovingAtoms(CRD->Top(), dih->A1(), dih->A2());
    // If randomly rotating angles, check for atoms that are in the same
    // residue as A1 but will not move. They need to be checked for clashes
    // since further rotations will not help them.
    if (mode_ == RANDOM && check_for_clashes_) {
      CharMask cMask( dst.Rmask.ConvertToCharMask(), dst.Rmask.Nselected() );
      int a1res = CRD->Top()[dih->A1()].ResNum();
      for (int maskatom = CRD->Top().Res(a1res).FirstAtom();
               maskatom < CRD->Top().Res(a1res).LastAtom(); ++maskatom)
        if (!cMask.AtomInCharMask(maskatom))
          dst.checkAtoms.push_back( maskatom );
      dst.checkAtoms.push_back(dih->A1()); // TODO: Does this need to be added first?
      // Since only the second atom and atoms it is bonded to move during 
      // rotation, base the check on the residue of the second atom.
      dst.resnum = a1res;
    }
    dst.atom0 = dih->A0(); // FIXME: This duplicates info
    dst.atom1 = dih->A1();
    dst.atom2 = dih->A2();
    dst.atom3 = dih->A3();
    BB_dihedrals_.push_back(dst);
    // DEBUG: List dihedral info.
    if (debug_ > 0) {
      mprintf("\t%s-%s-%s-%s\n", 
              CRD->Top().TruncResAtomName(dih->A0()).c_str(),
              CRD->Top().TruncResAtomName(dih->A1()).c_str(),
              CRD->Top().TruncResAtomName(dih->A2()).c_str(),
              CRD->Top().TruncResAtomName(dih->A3()).c_str() );
      if (debug_ > 1 && mode_ == RANDOM && check_for_clashes_) {
        mprintf("\t\tCheckAtoms=");
        for (std::vector<int>::const_iterator ca = dst.checkAtoms.begin();
                                              ca != dst.checkAtoms.end(); ++ca)
          mprintf(" %i", *ca + 1);
        mprintf("\n");
      }
      if (debug_ > 2) {
        mprintf("\t\t");
        dst.Rmask.PrintMaskAtoms("Rmask:");
      }
    }
  }

  // Set up simple structure check. First step is coarse; check distances 
  // between a certain atom in each residue (first, COM, CA, some other atom?)
  // to see if residues are in each others neighborhood. Second step is to 
  // check the atoms in each close residue.
  if (check_for_clashes_) {
    ResidueCheckType rct;
    int res = 0;
    for (Topology::res_iterator residue = CRD->Top().ResStart();
                                residue != CRD->Top().ResEnd(); ++residue)
    {
      rct.resnum = res++;
      rct.start = residue->FirstAtom();
      rct.stop = residue->LastAtom();
      rct.checkatom = rct.start;
      ResCheck_.push_back(rct);
    }
  }

  // Perform dihedral permute
  Frame currentFrame = CRD->AllocateFrame();
  for (unsigned int set = 0; set != CRD->Size(); set++)
  {
    CRD->GetFrame(set, currentFrame);
    int n_problems = 0;
    switch (mode_) {
      case RANDOM:
        RandomizeAngles(currentFrame, CRD->Top());
        // Check the resulting structure
        n_problems = checkStructure_.CheckOverlaps( currentFrame );
        //mprintf("%i\tResulting structure has %i problems.\n",frameNum,n_problems);
        number_of_problems_->Add(set, &n_problems);
        if (outtraj_.IsInitialized()) outtraj_.WriteSingle(outframe_++, currentFrame);
        if (crdout_ != 0) crdout_->AddFrame( currentFrame );
        break;
      case INTERVAL: IntervalAngles(currentFrame, CRD->Top(), interval_in_deg); break;
    }
  }
  if (outtraj_.IsInitialized()) outtraj_.EndTraj();
  return CpptrajState::OK;
}
Beispiel #4
0
void dirSeedsReg2::dirSweep(Datareg2& reg2)
{
    u_int i, j;
    Range resp;
    float min, max, t;
    float gradx;
    float grad1ya, grad1yb;
    float grad2ya, grad2yb;
    int keepflat;
    int prev;
    for(i=0; i<reg2.dim[0]-1; i++)
    {
        keepflat = 1;
        prev = -1;
        for(j=0; j<reg2.dim[1]-1; j++)
        {
            resp.MakeEmpty();
            // test responsiblity for each face
            // left
            if(i == 0)
            {
                min = max = reg2.getValue(reg2.index2vert(i,j));
                if((t=reg2.getValue(reg2.index2vert(i,j+1))) < min)
                {
                    min = t;
                }
                if(t > max)
                {
                    max = t;
                }
                if(min != max)
                {
                    resp += Range(min,max);
                }
            }
            else
            {
                // never do anything other than on boundary
            }
            // right
            if(i == reg2.dim[0]-2)
            {
                // never keep a right boundary seed
            }
            else
            {
                // never keep a right boundary seed
            }
            // general case: bottom edge in middle
            // cell (i,j) and (i,j-1) share this x-grad
            gradx = reg2.getValue(reg2.index2vert(i+1,j)) -
                    reg2.getValue(reg2.index2vert(i,j));
            // compute y-grad at (i,j) and (i+1,j)
            grad1ya = reg2.getValue(reg2.index2vert(i,j+1)) -
                      reg2.getValue(reg2.index2vert(i,j));
            grad1yb = reg2.getValue(reg2.index2vert(i+1,j+1)) -
                      reg2.getValue(reg2.index2vert(i+1,j));
            if(keepflat)
            {
                // check to see if gradient has 'turned'
                // only a seed if gradx & grady disagree in sign
                // note that 0 gradient is not considered opposite
                if(sgn(grad1ya) == 0 && sgn(grad1yb) == 0)
                {
                    // flat cell (in y dim) - continue
                }
                else if(sgn(gradx) == -sgn(grad1ya) || sgn(gradx) == -sgn(grad1yb))
                {
                    // extreme occurs if y components oppose each other
                    // note that 0 gradient is not considered opposite
                    min = max = reg2.getValue(reg2.index2vert(i,j));
                    if((t=reg2.getValue(reg2.index2vert(i+1,j))) < min)
                    {
                        min = t;
                    }
                    if(t > max)
                    {
                        max = t;
                    }
                    resp += Range(min,max);
                    keepflat = 0;
                }
            }
            // top
            if(j == reg2.dim[1]-2)
            {
                if(keepflat)
                {
                    min = max = reg2.getValue(reg2.index2vert(i,j+1));
                    if((t=reg2.getValue(reg2.index2vert(i+1,j+1))) < min)
                    {
                        min = t;
                    }
                    if(t > max)
                    {
                        max = t;
                    }
                    resp += Range(min,max);
                }
            }
            else
            {
                // only consider the top at the boundary
                if(!keepflat)
                {
                    gradx = reg2.getValue(reg2.index2vert(i+1,j+1)) -
                            reg2.getValue(reg2.index2vert(i,j+1));
                    grad2ya = reg2.getValue(reg2.index2vert(i,j+1)) -
                              reg2.getValue(reg2.index2vert(i,j));
                    grad2yb = reg2.getValue(reg2.index2vert(i+1,j+1)) -
                              reg2.getValue(reg2.index2vert(i+1,j));
                    if(sgn(gradx) != 0 && (sgn(gradx) == sgn(grad2ya) || sgn(gradx) == sgn(grad2yb)))
                    {
                        keepflat=1;
                    }
                }
                else
                {
                    gradx = reg2.getValue(reg2.index2vert(i+1,j+1)) -
                            reg2.getValue(reg2.index2vert(i,j+1));
                    grad2ya = reg2.getValue(reg2.index2vert(i,j+1)) -
                              reg2.getValue(reg2.index2vert(i,j));
                    grad2yb = reg2.getValue(reg2.index2vert(i+1,j+1)) -
                              reg2.getValue(reg2.index2vert(i+1,j));
                    if(sgn(gradx) == -sgn(grad2ya) || sgn(gradx) == -sgn(grad2yb))
                    {
                        keepflat=0;
                    }
                }
            }
            if(!resp.Empty())
            {
                if(prev == -1)
                {
                    if(i!=0)
                        prev = seeds.AddSeed(reg2.index2cell(i,j), resp.MinAll(),
                                             resp.MaxAll());
                    else
                        seeds.AddSeed(reg2.index2cell(i,j), resp.MinAll(),
                                      resp.MaxAll());
                }
                else
                {
                    seeds.AddToRange(prev, resp.MinAll(), resp.MaxAll());
                    prev = -1;
                }
            }
            else
            {
                prev = -1;
            }
        }
    }
}
Beispiel #5
0
// Preprocess() - build a segment tree for O(log n) queries
void regProp2::compSeeds(void)
{
	Datareg2& reg2 = (Datareg2&)data;
	int i, j;
	int xdim, ydim;
	float val[4];
	Range* _prop_x, *prop_x;
	Range prop_y;
	Range propagated;
	Range c_prop;
	Range responsibility, c_respons;
	Range delay;
	Range y_comp;
	float min_x, min_y, max_x, max_y;
	float min_in, max_in, min4, max4;
	int nseed;
	xdim = reg2.dim[0];
	ydim = reg2.dim[1];
	_prop_x = new Range[ydim];
	// proceed through the slices computing seeds
	nseed=0;
	// process the k'th slab
	for(i=0; i<xdim-1; i++)
		for(j=0; j<ydim-1; j++)
		{
			prop_x = &_prop_x[j];
			// load the voxel data
			reg2.getCellValues(i, j, val);
			min_x = MIN2(val[0], val[3]);
			max_x = MAX2(val[0], val[3]);
			min_y = MIN2(val[0], val[1]);
			max_y = MAX2(val[0], val[1]);
			// set the incoming values if on a border
			if(i==0)
			{
				prop_x->Set(min_x, max_x);
			}
			if(j==0)
			{
				prop_y.Set(min_y, max_y);
			}
			// merge incoming information
			y_comp = prop_y.Complement(min_y, max_y);
			propagated = prop_y + ((*prop_x)-y_comp);
			// compute complement of incoming ranges
			min_in = MIN2(min_x, min_y);
			max_in = MAX2(max_x, max_y);
			c_prop.Set(min_in,max_in);
			c_prop -= propagated;
			// compute responsibility ranges
			min4 = MIN2(min_in, val[2]);
			max4 = MAX2(max_in, val[2]);
			responsibility.Set(min4, max4);
			responsibility-=c_prop;
			c_respons = responsibility.Complement(min4, max4);
			// determine range which can be delayed
			delay.MakeEmpty();
			if(i < xdim-2)
				delay+=Range(MIN2(val[1], val[2]),
							 MAX2(val[1], val[2]));
			if(j < ydim-2)
				delay+=Range(MIN2(val[2], val[3]),
							 MAX2(val[2], val[3]));
			// test for propagation of entire responsibility range
			if(responsibility.Empty() || (!delay.Empty() &&
										  delay.MinAll() <= responsibility.MinAll() &&
										  delay.MaxAll() >= responsibility.MaxAll()))
			{
				// propagate first to the next x-slice
				if(i == xdim-2)
				{
					prop_x->MakeEmpty();
				}
				else
				{
					prop_x->Set(MIN2(val[1], val[2]), MAX2(val[1], val[2]));
					*prop_x-=c_respons;
				}
				c_respons += *prop_x;
				// all remaining propagated in y-dir
				if(j == ydim-2)
				{
					prop_y.MakeEmpty();
				}
				else
				{
					prop_y.Set(MIN2(val[2], val[3]), MAX2(val[2], val[3]));
					prop_y-= c_respons;
				}
			}
			else
			{
				// can't propagate all responsiblity, cell must be a seed
				seeds.AddSeed(reg2.index2cell(i,j), responsibility.MinAll(),
							  responsibility.MaxAll());
				nseed++;
				prop_y.MakeEmpty();
				prop_x->MakeEmpty();
			}
		}
	if(verbose)
	{
		printf("computed %d seeds\n", nseed);
	}
}
Beispiel #6
0
// 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;
}