// Action_NativeContacts::Init()
Action::RetType Action_NativeContacts::Init(ArgList& actionArgs, ActionInit& init, int debugIn)
{
# ifdef MPI
  trajComm_ = init.TrajComm();
# endif
  masterDSL_ = init.DslPtr();
  debug_ = debugIn;
  // Get Keywords
  image_.InitImaging( !(actionArgs.hasKey("noimage")) );
  double dist = actionArgs.getKeyDouble("distance", 7.0);
  byResidue_ = actionArgs.hasKey("byresidue");
  resoffset_ = actionArgs.getKeyInt("resoffset", 0) + 1;
  if (resoffset_ < 1) {
    mprinterr("Error: Residue offset must be >= 0\n");
    return Action::ERR;
  }
  includeSolvent_ = actionArgs.hasKey("includesolvent");
  series_ = actionArgs.hasKey("series");
  saveNonNative_ = actionArgs.hasKey("savenonnative");
  if (actionArgs.hasKey("skipnative"))
    determineNativeContacts_ = false;
  if (!determineNativeContacts_ && !saveNonNative_) {
    mprintf("Warning: 'skipnative' specified; implies 'savenonnative'.\n");
    saveNonNative_ = true;
  }
# ifdef MPI
  if (saveNonNative_) {
    mprinterr("Error: Saving non-native contact data not yet supported for MPI\n");
    return Action::ERR;
  }
# endif
  distance_ = dist * dist; // Square the cutoff
  first_ = actionArgs.hasKey("first");
  DataFile* outfile = init.DFL().AddDataFile( actionArgs.GetStringKey("out"), actionArgs );
  Rseries_ = NO_RESSERIES;
  if (series_) {
    seriesout_ = init.DFL().AddDataFile(actionArgs.GetStringKey("seriesout"), actionArgs);
    init.DSL().SetDataSetsPending( true );
    if (saveNonNative_)
      seriesNNout_ = init.DFL().AddDataFile(actionArgs.GetStringKey("seriesnnout"), actionArgs);
    std::string rs_arg = actionArgs.GetStringKey("resseries");
    if (!rs_arg.empty()) {
      if (rs_arg == "present")
        Rseries_ = RES_PRESENT;
      else if (rs_arg == "sum")
        Rseries_ = RES_SUM;
      else {
        mprinterr("Error: '%s' is not a valid 'resseries' keyword.\n", rs_arg.c_str());
        return Action::ERR;
      }
      seriesRout_ = init.DFL().AddDataFile(actionArgs.GetStringKey("resseriesout"), actionArgs);
    }
  } else {
    if (KeywordError(actionArgs,"seriesout")) return Action::ERR;
    if (KeywordError(actionArgs,"seriesnnout")) return Action::ERR;
    if (KeywordError(actionArgs,"resseries")) return Action::ERR;
    if (KeywordError(actionArgs,"resseriesout")) return Action::ERR;
  }
  cfile_ = init.DFL().AddCpptrajFile(actionArgs.GetStringKey("writecontacts"), "Native Contacts",
                               DataFileList::TEXT, true);
  pfile_ = init.DFL().AddCpptrajFile(actionArgs.GetStringKey("contactpdb"), "Contact PDB",
                               DataFileList::PDB);
  if (saveNonNative_)
    nfile_ = init.DFL().AddCpptrajFile(actionArgs.GetStringKey("nncontactpdb"),
                                       "Non-native Contact PDB", DataFileList::PDB);
  rfile_ = init.DFL().AddCpptrajFile(actionArgs.GetStringKey("resout"), "Contact Res Pairs",
                               DataFileList::TEXT, true);
  if (cfile_ == 0 || rfile_ == 0) return Action::ERR;
  pdbcut_ = (float)actionArgs.getKeyDouble("pdbcut", -1.0);
  usepdbcut_ = (pdbcut_ > -1.0);
  // Get reference for native contacts. Do this even if we wont be
  // determining native contacts in order to set up contact lists.
  ReferenceFrame REF = init.DSL().GetReferenceFrame( actionArgs );
  if (!first_) {
    if (REF.error()) return Action::ERR;
    if (REF.empty()) {
      mprintf("Warning: No reference structure specified. Defaulting to first.\n");
      first_ = true;
    }
  } else {
    if (!REF.empty()) {
      mprinterr("Error: Must only specify 'first' or a reference structure, not both.\n");
      return Action::ERR;
    }
  }
  
  // Create data sets
  std::string name = actionArgs.GetStringKey("name");
  if (name.empty())
    name = init.DSL().GenerateDefaultName("Contacts");
  numnative_ = init.DSL().AddSet(DataSet::INTEGER, MetaData(name, "native"));
  nonnative_ = init.DSL().AddSet(DataSet::INTEGER, MetaData(name, "nonnative"));
  if (outfile != 0) {
    outfile->AddDataSet(numnative_);
    outfile->AddDataSet(nonnative_);
  }
  if (numnative_ == 0 || nonnative_ == 0) return Action::ERR;
  if (actionArgs.hasKey("mindist")) {
    mindist_ = init.DSL().AddSet(DataSet::DOUBLE, MetaData(name, "mindist"));
    if (mindist_ == 0) return Action::ERR;
    if (outfile != 0) outfile->AddDataSet(mindist_);
  }
  if (actionArgs.hasKey("maxdist")) {
    maxdist_ = init.DSL().AddSet(DataSet::DOUBLE, MetaData(name, "maxdist"));
    if (maxdist_ == 0) return Action::ERR;
    if (outfile != 0) outfile->AddDataSet(maxdist_);
  }
  DataFile *natmapfile = 0, *nonmapfile = 0;
  if (actionArgs.hasKey("map")) {
    nativeMap_ = (DataSet_MatrixDbl*)init.DSL().AddSet(DataSet::MATRIX_DBL, MetaData(name, "nativemap"));
    if (nativeMap_ == 0) return Action::ERR;
    nonnatMap_ = (DataSet_MatrixDbl*)init.DSL().AddSet(DataSet::MATRIX_DBL, MetaData(name, "nonnatmap"));
    if (nonnatMap_ == 0) return Action::ERR;
    FileName mapFilename;
    mapFilename.SetFileName( actionArgs.GetStringKey("mapout") );
    if (!mapFilename.empty()) {
      natmapfile = init.DFL().AddDataFile(mapFilename.PrependFileName("native."));
      if (natmapfile != 0) natmapfile->AddDataSet(nativeMap_);
      nonmapfile = init.DFL().AddDataFile(mapFilename.PrependFileName("nonnative."));
      if (nonmapfile != 0) nonmapfile->AddDataSet(nonnatMap_);
    }
  }
  // Get Masks
  if (Mask1_.SetMaskString( actionArgs.GetMaskNext() )) return Action::ERR;
  std::string mask2 = actionArgs.GetMaskNext();
  if (!mask2.empty()) {
    if (Mask2_.SetMaskString( mask2 )) return Action::ERR;
  }
  mprintf("    NATIVECONTACTS: Mask1='%s'", Mask1_.MaskString());
  if (Mask2_.MaskStringSet())
    mprintf(" Mask2='%s'", Mask2_.MaskString());
  if (determineNativeContacts_) {
    mprintf(", native contacts set up based on");
    if (first_)
      mprintf(" first frame.\n");
    else
      mprintf("'%s'.\n", REF.refName());
  } else {
    mprintf(", skipping native contacts set up.\n");
  }
  if (byResidue_) {
    mprintf("\tContacts will be ignored for residues spaced < %i apart.\n", resoffset_);
    if (nativeMap_ != 0)
      mprintf("\tMap will be printed by residue.\n");
  }
  if (saveNonNative_)
    mprintf("\tSaving non-native contacts as well (may use a lot of memory).\n");
  mprintf("\tDistance cutoff is %g Angstroms,", sqrt(distance_));
  if (!image_.UseImage())
    mprintf(" imaging is off.\n");
  else
    mprintf(" imaging is on.\n");
  if (includeSolvent_)
    mprintf("\tMask selection will including solvent.\n");
  else
    mprintf("\tMask selection will not include solvent.\n");
  mprintf("\tData set name: %s\n", name.c_str());
  if (maxdist_ != 0)
    mprintf("\tSaving maximum observed distances in set '%s'\n", maxdist_->legend());
  if (mindist_ != 0)
    mprintf("\tSaving minimum observed distances in set '%s'\n", mindist_->legend());
  if (outfile != 0)
    mprintf("\tOutput to '%s'\n", outfile->DataFilename().full());
  mprintf("\tContact stats will be written to '%s'\n", cfile_->Filename().full());
  mprintf("\tContact res pairs will be written to '%s'\n", rfile_->Filename().full());
  if (pfile_ != 0) {
    mprintf("\tContact PDB will be written to '%s'\n", pfile_->Filename().full());
    if (usepdbcut_) mprintf("\tOnly atoms with values > %g will be written to PDB.\n", pdbcut_);
  }
  if (nfile_ != 0) {
    mprintf("\tNon-native contact PDB will be written to '%s'\n", nfile_->Filename().full());
    if (usepdbcut_) mprintf("\tOnly atoms with values > %g will be written to PDB.\n", pdbcut_);
  }
  if (nativeMap_ != 0) {
    mprintf("\tNative contacts map will be saved as set '%s'\n"
            "\tNon-native contacts map will be saved as set '%s'\n",
            nativeMap_->legend(), nonnatMap_->legend());
    if (natmapfile!=0) mprintf("\tNative map output to '%s'\n",natmapfile->DataFilename().full());
    if (nonmapfile!=0) mprintf("\tNative map output to '%s'\n",nonmapfile->DataFilename().full());
  }
  if (series_) {
    mprintf("\tSaving native contact time series %s[NC].\n", name.c_str());
    if (seriesout_ != 0) mprintf("\tWriting native contact time series to %s\n",
                                 seriesout_->DataFilename().full());
    if (saveNonNative_) {
      mprintf("\tSaving non-native contact time series %s[NN]\n", name.c_str());
      if (seriesNNout_ != 0) mprintf("\tWriting non-native contact time series to %s\n",
                                     seriesNNout_->DataFilename().full());
    }
    if (Rseries_ != NO_RESSERIES) {
      if (Rseries_ == RES_PRESENT)
        mprintf("\tResidue contact time series will reflect presence of individual contacts.\n");
      else if (Rseries_ == RES_SUM)
        mprintf("\tResidue contact time series will reflect sum of individual contacts.\n");
      if (seriesRout_ != 0) mprintf("\tWriting residue contact time series to %s\n",
                                    seriesRout_->DataFilename().full());
    }
  }
  // Set up reference if necessary.
  if (!first_) {
    // Set up imaging info for ref parm
    image_.SetupImaging( REF.CoordsInfo().TrajBox().Type() );
    if (image_.ImageType() == NONORTHO)
      REF.Coord().BoxCrd().ToRecip(ucell_, recip_);
    if (DetermineNativeContacts( REF.Parm(), REF.Coord() )) return Action::ERR;
  }
  return Action::OK;
}
Example #2
0
// Action_Spam::init()
Action::RetType Action_Spam::Init(ArgList& actionArgs, TopologyList* PFL, DataSetList* DSL, DataFileList* DFL, int debugIn)
{
  // Always use imaged distances
  InitImaging(true);
  // This is needed everywhere in this function scope
  FileName filename;

  // See if we're doing pure water. If so, we don't need a peak file
  purewater_ = actionArgs.hasKey("purewater");

  if (purewater_) {
    // We still need the cutoff
    double cut = actionArgs.getKeyDouble("cut", 12.0);
    cut2_ = cut * cut;
    doublecut_ = 2 * cut;
    onecut2_ = 1 / cut2_;
    // See if we write to a data file
    datafile_ = actionArgs.GetStringKey("out");
    // Generate the data set name, and hold onto the master data set list
    std::string ds_name = actionArgs.GetStringKey("name");
    if (ds_name.empty())
      ds_name = myDSL_.GenerateDefaultName("SPAM");
    // We only have one data set averaging over every water. Add it here
    myDSL_.AddSet(DataSet::DOUBLE, ds_name, NULL);
    solvname_ = actionArgs.GetStringKey("solv");
    if (solvname_.empty())
      solvname_ = std::string("WAT");
  }else {
    // Get the file name with the peaks defined in it
    filename.SetFileName( actionArgs.GetStringNext() );

    if (filename.empty() || !File::Exists(filename)) {
      mprinterr("Spam: Error: Peak file [%s] does not exist!\n", filename.full());
      return Action::ERR;
    }

    // Get the remaining optional arguments
    solvname_ = actionArgs.GetStringKey("solv");
    if (solvname_.empty())
      solvname_ = std::string("WAT");
    reorder_ = actionArgs.hasKey("reorder");
    bulk_ = actionArgs.getKeyDouble("bulk", 0.0);
    double cut = actionArgs.getKeyDouble("cut", 12.0);
    cut2_ = cut * cut;
    doublecut_ = 2 * cut;
    onecut2_ = 1 / cut2_;
    std::string infoname = actionArgs.GetStringKey("info");
    if (infoname.empty())
      infoname = std::string("spam.info");
    infofile_ = DFL->AddCpptrajFile(infoname, "SPAM info");
    if (infofile_ == 0) return Action::ERR;
    // The default maskstr is the Oxygen atom of the solvent
    summaryfile_ = actionArgs.GetStringKey("summary");
    // Divide site size by 2 to make it half the edge length (or radius)
    site_size_ = actionArgs.getKeyDouble("site_size", 2.5) / 2.0;
    sphere_ = actionArgs.hasKey("sphere");
    // If it's a sphere, square the radius to compare with
    if (sphere_)
      site_size_ *= site_size_;
    datafile_ = actionArgs.GetStringKey("out");
    std::string ds_name = actionArgs.GetStringKey("name");
    if (ds_name.empty())
      ds_name = myDSL_.GenerateDefaultName("SPAM");

    // Parse through the peaks file and extract the peaks
    CpptrajFile peakfile;
    if (peakfile.OpenRead(filename)) {
      mprinterr("SPAM: Error: Could not open %s for reading!\n", filename.full());
      return Action::ERR;
    }
    std::string line = peakfile.GetLine();
    int npeaks = 0;
    while (!line.empty()) {
      if (sscanf(line.c_str(), "%d", &npeaks) != 1) {
        line = peakfile.GetLine();
        continue;
      }
      line = peakfile.GetLine();
      break;
    }
    while (!line.empty()) {
      double x, y, z, dens;
      if (sscanf(line.c_str(), "C %lg %lg %lg %lg", &x, &y, &z, &dens) != 4) {
        line = peakfile.GetLine();
        continue;
      }
      line = peakfile.GetLine();
      peaks_.push_back(Vec3(x, y, z));
    }
    peakfile.CloseFile();
    // Check that our initial number of peaks matches our parsed peaks. Warn
    // otherwise
    if (npeaks != (int)peaks_.size())
      mprinterr("SPAM: Warning: %s claims to have %d peaks, but really has %d!\n",
                filename.full(), npeaks, peaks_.size());
    // Now add all of the data sets
    MetaData md(ds_name);
    for (int i = 0; i < (int)peaks_.size(); i++) {
      md.SetAspect( integerToString(i+1) ); // TODO: Should this be Idx?
      if (myDSL_.AddSet(DataSet::DOUBLE, md) == 0) return Action::ERR;
      // Add a new list of integers to keep track of omitted frames
      std::vector<int> vec;
      peakFrameData_.push_back(vec);
    }
  }

  // Print info now
  if (purewater_) {
    mprintf("SPAM: Calculating bulk value for pure solvent\n");
    if (!datafile_.empty())
      mprintf("SPAM: Printing solvent energies to %s\n", datafile_.c_str());
    mprintf("SPAM: Using a %.2f Angstrom non-bonded cutoff with shifted EEL.\n",
            sqrt(cut2_));
    if (reorder_)
      mprintf("SPAM: Warning: Re-ordering makes no sense for pure solvent.\n");
    if (!summaryfile_.empty())
      mprintf("SPAM: Printing solvent SPAM summary to %s\n", summaryfile_.c_str());
  }else {
    mprintf("SPAM: Solvent [%s] density peaks taken from %s.\n",
            solvname_.c_str(), filename.base());
    mprintf("SPAM: %d density peaks will be analyzed from %s.\n",
            peaks_.size(), filename.base());
    mprintf("SPAM: Occupation information printed to %s.\n", infofile_->Filename().full());
    mprintf("SPAM: Sites are ");
    if (sphere_)
      mprintf("spheres with diameter %.3lf\n", site_size_);
    else
      mprintf("boxes with edge length %.3lf\n", site_size_);
    if (reorder_) {
      mprintf("SPAM: Re-ordering trajectory so each site always has ");
      mprintf("the same water molecule.\n");
    }
    if (summaryfile_.empty() && datafile_.empty()) {
      if (!reorder_) {
        mprinterr("SPAM: Error: Not re-ordering trajectory or calculating energies. ");
        mprinterr("Nothing to do!\n");
        return Action::ERR;
      }
      mprintf("SPAM: Not calculating any SPAM energies\n");
    }else {
      mprintf("SPAM: Using a non-bonded cutoff of %.2lf Ang. with a EEL shifting function.\n",
              sqrt(cut2_));
      mprintf("SPAM: Bulk solvent SPAM energy taken as %.3lf kcal/mol\n", bulk_);
    }
  }
  mprintf("#Citation: Cui, G.; Swails, J.M.; Manas, E.S.; \"SPAM: A Simple Approach\n"
          "#          for Profiling Bound Water Molecules\"\n"
          "#          J. Chem. Theory Comput., 2013, 9 (12), pp 5539–5549.\n");

  return Action::OK;
}