Пример #1
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_);
}
bool parametersChecking(TYPE &n, TYPE &k) {

	TYPE *nPtr = &n;
	TYPE *kPtr = &k;
    int typeCheckInt = 0;

    if(typeid(*nPtr).name() == typeid(typeCheckInt).name() &&
    		typeid(*kPtr).name() == typeid(typeCheckInt).name()){

    	// If given parameters integer, then these integers are checked for validity
    	// if they qualify to calculate binomial coefficient
    	if (validInteger(n,k)){
    		return true;
    	}
    	else{
    		return false;
    	}

    }
    else {
    		return false;
    }

    return false;
}
Пример #3
0
bool Traj_Gro::ID_TrajFormat(CpptrajFile& infile) {
    // Title line, atoms line, then resnum, resname, atomname, atomnum, X, Y, Z
    if (infile.OpenFile()) return false;
    int nread = 0;
    if (infile.NextLine() != 0) { // Title
        const char* ptr = infile.NextLine(); // Natom
        if (ptr != 0) {
            // Ensure only a single value on # atoms line
            std::string natom_str( ptr );
            RemoveTrailingWhitespace( natom_str );
            if (validInteger(natom_str)) {
                ptr = infile.NextLine(); // First atom
                if (ptr != 0) {
                    char resnum[6], resname[6], atname[6], atnum[6];
                    float XYZ[3];
                    nread = sscanf(ptr, "%5c%5c%5c%5c%f %f %f", resnum, resname,
                                   atname, atnum, XYZ, XYZ+1, XYZ+2);
                }
            }
        }
    }
    infile.CloseFile();
    return (nread == 7);
}
Пример #4
0
/** 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;
}
Пример #5
0
// Exec_DataSetCmd::Remove()
Exec::RetType Exec_DataSetCmd::Remove(CpptrajState& State, ArgList& argIn) {
  std::string status;
  // Get criterion type
  CriterionType criterion = UNKNOWN_C;
  for (int i = 1; i < (int)N_C; i++)
    if (argIn.hasKey( CriterionKeys[i] )) {
      criterion = (CriterionType)i;
      status.assign( CriterionKeys[i] );
      break;
    }
  if (criterion == UNKNOWN_C) {
    mprinterr("Error: No criterion specified for 'remove'.\n");
    return CpptrajState::ERR;
  }
  // Get select type
  SelectType select = UNKNOWN_S;
  std::string val1, val2;
  for (const SelectPairType* ptr = SelectKeys; ptr->key_ != 0; ptr++)
    if (argIn.Contains( ptr->key_ )) {
      select = ptr->type_;
      val1 = argIn.GetStringKey( ptr->key_ );
      status.append( " " + std::string(ptr->key_) + " " + val1 );
      // Get 'and' value for between/outside. TODO put nargs in SelectPairType?
      if (select == BETWEEN || select == OUTSIDE) {
        val2 = argIn.GetStringKey("and");
        if (val2.empty()) {
          mprinterr("Error: Missing 'and' value for selection '%s'\n", ptr->key_);
          return CpptrajState::ERR;
        }
        status.append(" and " + val2);
      }
      break;
    }
  if (select == UNKNOWN_S || val1.empty()) {
    mprinterr("Error: No selection specified for 'remove'.\n");
    return CpptrajState::ERR;
  }
  if ( (criterion == SMODE || criterion == STYPE) &&
       (select != EQUAL && select != NOT_EQUAL) )
  {
    mprinterr("Error: Specified select not valid for criterion '%s'\n", CriterionKeys[criterion]);
    return CpptrajState::ERR;
  }
  mprintf("\tRemoving data sets");
  std::string setSelectArg = argIn.GetStringNext();
  if (setSelectArg.empty())
    setSelectArg.assign("*");
  else
    mprintf(" within selection '%s'", setSelectArg.c_str());
  mprintf(" %s\n", status.c_str());
  DataSetList tempDSL = State.DSL().GetMultipleSets( setSelectArg );
  if (tempDSL.empty()) {
    mprinterr("Error: No data sets selected.\n");
    return CpptrajState::ERR;
  }
  // Remove sets
  unsigned int Nremoved = 0;
  if ( criterion == AVERAGE ) {
    if (!validDouble( val1 )) {
      mprinterr("Error: '%s' is not a valid number\n", val1.c_str());
      return CpptrajState::ERR;
    }
    double d_val1 = convertToDouble( val1 );
    double d_val2  = d_val1;
    if (!val2.empty()) {
      if (!validDouble( val2 )) {
        mprinterr("Error: '%s' is not a valid number\n", val2.c_str());
        return CpptrajState::ERR;
      }
      d_val2 = convertToDouble( val2 );
    }
    for (DataSetList::const_iterator ds = tempDSL.begin(); ds != tempDSL.end(); ++ds)
    {
      if ( (*ds)->Group() != DataSet::SCALAR_1D )
        mprintf("Warning: '%s' is not a valid data set for 'average' criterion.\n", (*ds)->legend());
      else {
        DataSet_1D const& ds1 = static_cast<DataSet_1D const&>( *(*ds) );
        double avg = ds1.Avg();
        bool remove = false;
        switch (select) {
          case EQUAL        : remove = (avg == d_val1); break;
          case NOT_EQUAL    : remove = (avg != d_val1); break;
          case LESS_THAN    : remove = (avg < d_val1); break;
          case GREATER_THAN : remove = (avg > d_val1); break;
          case BETWEEN      : remove = (avg > d_val1 && avg < d_val2); break;
          case OUTSIDE      : remove = (avg < d_val1 || avg > d_val2); break;
          case UNKNOWN_S:
          case N_S      : return CpptrajState::ERR; // Sanity check
        }
        if (remove) {
          mprintf("\t  Removing set '%s' (avg is %g)\n", (*ds)->legend(), avg);
          State.RemoveDataSet( *ds );
          ++Nremoved;
        }
      }
    }
  } else if ( criterion == SIZE ) {
    if (!validInteger( val1 )) {
      mprinterr("Error: '%s' is not a valid number\n", val1.c_str());
      return CpptrajState::ERR;
    }
    unsigned int i_val1 = (unsigned int)convertToInteger( val1 );
    unsigned int i_val2 = i_val1;
    if (!val2.empty()) {
      if (!validInteger( val2 )) {
        mprinterr("Error: '%s' is not a valid number\n", val2.c_str());
        return CpptrajState::ERR;
      }
      i_val2 = convertToInteger( val2 );
    }
    for (DataSetList::const_iterator ds = tempDSL.begin(); ds != tempDSL.end(); ++ds)
    {
      unsigned int size = (*ds)->Size();
      bool remove = false;
      switch ( select ) {
        case EQUAL        : remove = (size == i_val1); break;
        case NOT_EQUAL    : remove = (size != i_val1); break;
        case LESS_THAN    : remove = (size < i_val1); break;
        case GREATER_THAN : remove = (size > i_val1); break;
        case BETWEEN      : remove = (size > i_val1 && size < i_val2); break;
        case OUTSIDE      : remove = (size < i_val1 || size > i_val2); break;
        case UNKNOWN_S:
        case N_S      : return CpptrajState::ERR; // Sanity check
      }
      if (remove) {
        mprintf("\t  Removing set '%s' (size is %u)\n", (*ds)->legend(), size);
        State.RemoveDataSet( *ds );
        ++Nremoved;
      }
    }
  } else if ( criterion == SMODE ) {
    MetaData::scalarMode mode_val = MetaData::ModeFromKeyword( val1 );
    if (mode_val == MetaData::UNKNOWN_MODE) {
      mprinterr("Error: '%s' is not a valid mode.\n", val1.c_str());
      return CpptrajState::ERR;
    }
    for (DataSetList::const_iterator ds = tempDSL.begin(); ds != tempDSL.end(); ++ds)
    {
      bool remove = false;
      MetaData::scalarMode mode = (*ds)->Meta().ScalarMode();
      if      (select == EQUAL    ) remove = ( mode == mode_val );
      else if (select == NOT_EQUAL) remove = ( mode != mode_val );
      else return CpptrajState::ERR; // Sanity check
      if (remove) {
        mprintf("\t  Removing set '%s' (mode is '%s')\n", (*ds)->legend(), MetaData::ModeString(mode));
        State.RemoveDataSet( *ds );
        ++Nremoved;
      }
    }
  } else if ( criterion == STYPE ) {
    MetaData::scalarType type_val = MetaData::TypeFromKeyword( val1, MetaData::UNKNOWN_MODE );
    if (type_val == MetaData::UNDEFINED) {
      mprinterr("Error: '%s' is not a valid type.\n", val1.c_str());
      return CpptrajState::ERR;
    }
    for (DataSetList::const_iterator ds = tempDSL.begin(); ds != tempDSL.end(); ++ds)
    {
      bool remove = false;
      MetaData::scalarType type = (*ds)->Meta().ScalarType();
      if      (select == EQUAL    ) remove = ( type == type_val );
      else if (select == NOT_EQUAL) remove = ( type != type_val );
      else return CpptrajState::ERR; // Sanity check
      if (remove) {
        mprintf("\t  Removing set '%s' (typeis '%s')\n", (*ds)->legend(), MetaData::TypeString(type));
        State.RemoveDataSet( *ds );
        ++Nremoved;
      }
    }
  } else {
    mprinterr("Internal Error: Criterion not yet implemented.\n");
    return CpptrajState::ERR;
  }
  mprintf("\tRemoved %u of %zu sets.\n", Nremoved, tempDSL.size());
  return CpptrajState::OK;
}
Пример #6
0
// 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;
}
// Action_MakeStructure::Init()
Action::RetType Action_MakeStructure::Init(ArgList& actionArgs, TopologyList* PFL, DataSetList* DSL, DataFileList* DFL, int debugIn)
{
  debug_ = debugIn;
  secstruct_.clear();
  // Get all arguments 
  std::string ss_expr = actionArgs.GetStringNext();
  while ( !ss_expr.empty() ) {
    ArgList ss_arg(ss_expr, ":");
    if (ss_arg.Nargs() < 2) {
      mprinterr("Error: Malformed SS arg.\n");
      Help();
      return Action::ERR;
    }
    // Type is 1st arg, range is 2nd arg.
    SecStructHolder ss_holder(ss_arg[1], FindSStype(ss_arg[0]));

    if (ss_arg.Nargs() == 2) {
    // Find SS type: <ss type>:<range>
      if (ss_holder.sstype_idx == SS_EMPTY) {
        mprinterr("Error: SS type %s not found.\n", ss_arg[0].c_str());
        return Action::ERR;
      } 
      ss_holder.dihSearch_.SearchFor(MetaData::PHI);
      ss_holder.dihSearch_.SearchFor(MetaData::PSI);
      secstruct_.push_back( ss_holder );

    } else if (ss_arg[0] == "ref") {
    // Use dihedrals from reference structure
      if (ss_arg.Nargs() < 3) {
        mprinterr("Error: Invalid 'ref' arg. Requires 'ref:<range>:<refname>[:<ref range>]'\n");
        return Action::ERR;
      }
      ss_arg.MarkArg(0);
      ss_arg.MarkArg(1);
      // Sanity check: Currently only unique args of this type are allowed
      if (ss_holder.sstype_idx != SS_EMPTY) {
        mprinterr("Error: Ref backbone types must be unique [%s]\n", ss_arg[0].c_str());
        return Action::ERR;
      }
      // Use backbone phi/psi from reference structure
      ss_holder.dihSearch_.SearchFor(MetaData::PHI);
      ss_holder.dihSearch_.SearchFor(MetaData::PSI);
      // Get reference structure
      DataSet_Coords_REF* REF = (DataSet_Coords_REF*)
                                DSL->FindSetOfType(ss_arg.GetStringNext(),
                                                   DataSet::REF_FRAME); // ss_arg[2]
      if (REF == 0) {
        mprinterr("Error: Could not get reference structure [%s]\n", ss_arg[2].c_str());
        return Action::ERR;
      }
      // Get reference residue range, or use resRange
      Range refRange(ss_arg.GetStringNext(), -1); // ss_arg[3]
      if (!refRange.Empty()) {
        if (ss_holder.resRange.Size() != refRange.Size()) {
          mprinterr("Error: Reference range [%s] must match residue range [%s]\n",
                    refRange.RangeArg(), ss_holder.resRange.RangeArg());
          return Action::ERR;
        }
      } else
        refRange = ss_holder.resRange;
      // Look for phi/psi only in reference
      DihedralSearch refSearch;
      refSearch.SearchFor(MetaData::PHI);
      refSearch.SearchFor(MetaData::PSI);
      if (refSearch.FindDihedrals( REF->Top(), refRange )) return Action::ERR;
      // For each found dihedral, set theta 
      for (DihedralSearch::mask_it dih = refSearch.begin(); dih != refSearch.end(); ++dih)
      {
        double torsion = Torsion( REF->RefFrame().XYZ(dih->A0()),
                                  REF->RefFrame().XYZ(dih->A1()),
                                  REF->RefFrame().XYZ(dih->A2()),
                                  REF->RefFrame().XYZ(dih->A3()) );
        ss_holder.thetas_.push_back( (float)torsion );
      }
      secstruct_.push_back( ss_holder );

    } else if (ss_arg.Nargs() == 4 && isalpha(ss_arg[2][0])) {
    // Single dihedral type: <name>:<range>:<dih type>:<angle>
      DihedralSearch::DihedralType dtype = DihedralSearch::GetType(ss_arg[2]);
      if (ss_holder.sstype_idx == SS_EMPTY) {
        // Type not yet defined. Create new type. 
        if (dtype == MetaData::UNDEFINED) {
          mprinterr("Error: Dihedral type %s not found.\n", ss_arg[2].c_str());
          return Action::ERR;
        }
        if (!validDouble(ss_arg[3])) {
          mprinterr("Error: 4th arg (angle) is not a valid number.\n");
          return Action::ERR;
        }
        SS.push_back( SS_TYPE(convertToDouble(ss_arg[3]), 0.0, 0.0, 0.0, 2, ss_arg[0]) );
        ss_holder.sstype_idx = (int)(SS.size() - 1);
      }
      ss_holder.dihSearch_.SearchFor( dtype ); 
      secstruct_.push_back( ss_holder );

    } else if (ss_arg.Nargs() == 7 || ss_arg.Nargs() == 8) {
    // Single custom dihedral type: <name>:<range>:<at0>:<at1>:<at2>:<at3>:<angle>[:<offset>]
      if (ss_holder.sstype_idx == SS_EMPTY) {
        // Type not yet defined. Create new type.
        if (!validDouble(ss_arg[6])) {
          mprinterr("Error: 7th arg (angle) is not a valid number.\n");
          return Action::ERR;
        }
        SS.push_back( SS_TYPE(convertToDouble(ss_arg[6]), 0.0, 0.0, 0.0, 2, ss_arg[0]) );
        ss_holder.sstype_idx = (int)(SS.size() - 1);
      }
      int offset = 0;
      if (ss_arg.Nargs() == 8) {
        if (!validInteger(ss_arg[7])) {
          mprinterr("Error: 8th arg (offset) is not a valid number.\n");
          return Action::ERR;
        }
        offset = convertToInteger(ss_arg[7]);
      }
      ss_holder.dihSearch_.SearchForNewType(offset,ss_arg[2],ss_arg[3],ss_arg[4],ss_arg[5],
                                            ss_arg[0]);
      secstruct_.push_back( ss_holder );

    } else if (ss_arg.Nargs() == 4 || ss_arg.Nargs() == 6) {
    // Custom SS/turn type: <name>:<range>:<phi1>:<psi1>[:<phi2>:<psi2>]
      if (ss_holder.sstype_idx == SS_EMPTY) {
        // Type not yet defined. Create new type.
        if (!validDouble(ss_arg[2]) || !validDouble(ss_arg[3])) {
          mprinterr("Error: 3rd or 4th arg (phi1/psi1) is not a valid number.\n");
          return Action::ERR;
        }
        double phi1 = convertToDouble(ss_arg[2]);
        double psi1 = convertToDouble(ss_arg[3]);
        int isTurn = 0;
        double phi2 = 0.0;
        double psi2 = 0.0;
        if (ss_arg.Nargs() == 6) {
          isTurn = 1;
          if (!validDouble(ss_arg[4]) || !validDouble(ss_arg[5])) {
            mprinterr("Error: 5th or 6th arg (phi2/psi2) is not a valid number.\n");
            return Action::ERR;
          }
          phi2 = convertToDouble(ss_arg[4]);
          psi2 = convertToDouble(ss_arg[5]);
        }
        SS.push_back(SS_TYPE(phi1, psi1, phi2, psi2, isTurn, ss_arg[0] ));
        ss_holder.sstype_idx = (int)(SS.size() - 1);
      }
      ss_holder.dihSearch_.SearchFor(MetaData::PHI);
      ss_holder.dihSearch_.SearchFor(MetaData::PSI);
      secstruct_.push_back( ss_holder );

    } else {
      mprinterr("Error: SS arg type [%s] not recognized.\n", ss_arg[0].c_str());
      return Action::ERR;
    }
    ss_expr = actionArgs.GetStringNext();
  } // End loop over args
  if (secstruct_.empty()) {
    mprinterr("Error: No SS types defined.\n");
    return Action::ERR;
  }
  mprintf("    MAKESTRUCTURE:\n");
  for (std::vector<SecStructHolder>::iterator ss = secstruct_.begin();
                                              ss != secstruct_.end(); ++ss)
  {
    if (ss->sstype_idx != SS_EMPTY) {
      const SS_TYPE& myType = SS[ss->sstype_idx];
      switch ( myType.isTurn ) {
        case 0:
          mprintf("\tSS type %s will be applied to residue(s) %s\n",
                 myType.type_arg.c_str(), ss->resRange.RangeArg());
          break;
        case 1:
          mprintf("\tTurn type %s will be applied to residue(s) %s\n",
                  myType.type_arg.c_str(), ss->resRange.RangeArg());
          break;
        case 2:
          mprintf("\tDihedral value of %.2f will be applied to %s dihedrals in residue(s) %s\n",
                  myType.phi, myType.type_arg.c_str(), ss->resRange.RangeArg());
      }
    } else 
      mprintf("\tBackbone angles from reference will be applied to residue(s) %s\n",
              ss->resRange.RangeArg());
  }
  return Action::OK;
}