// 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; }
/** Determine from selected mask atoms which dihedrals will be rotated. */ Action::RetType Action_DihedralScan::Setup(ActionSetup& setup) { DihedralScanType dst; // If range is empty (i.e. no resrange arg given) look through all // solute residues. Range actualRange; if (resRange_.Empty()) actualRange = setup.Top().SoluteResidues(); else actualRange = resRange_; // Search for dihedrals if (dihSearch_.FindDihedrals(setup.Top(), actualRange)) return Action::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(setup.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 = setup.Top()[dih->A1()].ResNum(); for (int maskatom = setup.Top().Res(a1res).FirstAtom(); maskatom < setup.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", setup.Top().TruncResAtomName(dih->A0()).c_str(), setup.Top().TruncResAtomName(dih->A1()).c_str(), setup.Top().TruncResAtomName(dih->A2()).c_str(), setup.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 CheckStructure for this parm (false = nobondcheck) if (checkStructure_.SeparateSetup(setup.Top(), setup.CoordInfo().TrajBox().Type(), false) != Action::OK) return Action::ERR; // Set the overall max number of rotations to try max_rotations_ = (int) BB_dihedrals_.size(); max_rotations_ *= max_factor_; // 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 = setup.Top().ResStart(); residue != setup.Top().ResEnd(); ++residue) { rct.resnum = res++; rct.start = residue->FirstAtom(); rct.stop = residue->LastAtom(); rct.checkatom = rct.start; ResCheck_.push_back(rct); } } if (!outfilename_.empty() && CurrentParm_ == 0) // FIXME: Correct frames for # of rotations outtraj_.SetupTrajWrite(setup.TopAddress(), setup.CoordInfo(), setup.Nframes()); CurrentParm_ = setup.TopAddress(); return Action::OK; }
// Exec_RotateDihedral::Execute() Exec::RetType Exec_RotateDihedral::Execute(CpptrajState& State, ArgList& argIn) { // 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; } if (CRD->Size() < 1) { mprinterr("Error: COORDS set is empty.\n"); return CpptrajState::ERR; } int frame = argIn.getKeyInt("frame", 0); if (frame < 0 || frame >= (int)CRD->Size()) { mprinterr("Error: Specified frame %i is out of range.\n", frame+1); return CpptrajState::ERR; } mprintf(" ROTATEDIHEDRAL: Using COORDS '%s', frame %i\n", CRD->legend(), frame+1); // Get target frame Frame FRM = CRD->AllocateFrame(); CRD->GetFrame(frame, FRM); // Save as reference Frame refFrame = FRM; // Create output COORDS set if necessary DataSet_Coords* OUT = 0; int outframe = 0; std::string outname = argIn.GetStringKey("name"); if (outname.empty()) { // This will not work for TRAJ data sets if (CRD->Type() == DataSet::TRAJ) { mprinterr("Error: Using TRAJ as input set requires use of 'name' keyword for output.\n"); return CpptrajState::ERR; } OUT = CRD; outframe = frame; } else { // Create new output set with 1 empty frame. OUT = (DataSet_Coords*)State.DSL().AddSet( DataSet::COORDS, outname ); if (OUT == 0) return CpptrajState::ERR; OUT->Allocate( DataSet::SizeArray(1, 1) ); OUT->CoordsSetup( CRD->Top(), CRD->CoordsInfo() ); OUT->AddFrame( CRD->AllocateFrame() ); mprintf("\tOutput to set '%s'\n", OUT->legend()); } // Determine whether we are setting or incrementing. enum ModeType { SET = 0, INCREMENT }; ModeType mode = SET; if (argIn.Contains("value")) mode = SET; else if (argIn.Contains("increment")) mode = INCREMENT; else { mprinterr("Error: Specify 'value <value>' or 'increment <increment>'\n"); return CpptrajState::ERR; } double value = argIn.getKeyDouble(ModeStr[mode], 0.0); switch (mode) { case SET: mprintf("\tDihedral will be set to %g degrees.\n", value); break; case INCREMENT: mprintf("\tDihedral will be incremented by %g degrees.\n", value); break; } // Convert to radians value *= Constants::DEGRAD; // Select dihedral atoms int A1, A2, A3, A4; if (argIn.Contains("type")) { // By type ArgList typeArg = argIn.GetStringKey("type"); if (typeArg.empty()) { mprinterr("Error: No dihedral type specified after 'type'\n"); return CpptrajState::ERR; } DihedralSearch dihSearch; dihSearch.SearchForArgs( typeArg ); if (dihSearch.NoDihedralTokens()) { mprinterr("Error: Specified dihedral type not recognized.\n"); return CpptrajState::ERR; } // Get residue int res = argIn.getKeyInt("res", -1); if (res <= 0) { mprinterr("Error: If 'type' specified 'res' must be specified and > 0.\n"); return CpptrajState::ERR; } // Search for dihedrals. User residue #s start from 1. if (dihSearch.FindDihedrals(CRD->Top(), Range(res-1))) return CpptrajState::ERR; DihedralSearch::mask_it dih = dihSearch.begin(); A1 = dih->A0(); A2 = dih->A1(); A3 = dih->A2(); A4 = dih->A3(); } else { // By masks AtomMask m1( argIn.GetMaskNext() ); AtomMask m2( argIn.GetMaskNext() ); AtomMask m3( argIn.GetMaskNext() ); AtomMask m4( argIn.GetMaskNext() ); if (CRD->Top().SetupIntegerMask( m1 )) return CpptrajState::ERR; if (CRD->Top().SetupIntegerMask( m2 )) return CpptrajState::ERR; if (CRD->Top().SetupIntegerMask( m3 )) return CpptrajState::ERR; if (CRD->Top().SetupIntegerMask( m4 )) return CpptrajState::ERR; if (m1.Nselected() != 1) return MaskError( m1 ); if (m2.Nselected() != 1) return MaskError( m2 ); if (m3.Nselected() != 1) return MaskError( m3 ); if (m4.Nselected() != 1) return MaskError( m4 ); A1 = m1[0]; A2 = m2[0]; A3 = m3[0]; A4 = m4[0]; } mprintf("\tRotating dihedral defined by atoms '%s'-'%s'-'%s'-'%s'\n", CRD->Top().AtomMaskName(A1).c_str(), CRD->Top().AtomMaskName(A2).c_str(), CRD->Top().AtomMaskName(A3).c_str(), CRD->Top().AtomMaskName(A4).c_str()); // Set mask of atoms that will move during dihedral rotation AtomMask Rmask = DihedralSearch::MovingAtoms(CRD->Top(), A2, A3); // Calculate current value of dihedral double torsion = Torsion( FRM.XYZ(A1), FRM.XYZ(A2), FRM.XYZ(A3), FRM.XYZ(A4) ); // Calculate delta needed to get to target value. double delta; switch (mode) { case SET: delta = value - torsion; break; case INCREMENT: delta = value; break; } mprintf("\tOriginal torsion is %g, rotating by %g degrees.\n", torsion*Constants::RADDEG, delta*Constants::RADDEG); // Set axis of rotation Vec3 axisOfRotation = FRM.SetAxisOfRotation( A2, A3 ); // Calculate rotation matrix for delta. Matrix_3x3 rotationMatrix; rotationMatrix.CalcRotationMatrix(axisOfRotation, delta); // Rotate around axis FRM.Rotate(rotationMatrix, Rmask); // RMS-fit the non-moving part of the coords back on original AtomMask refMask = Rmask; refMask.InvertMask(); FRM.Align( refFrame, refMask ); // Update coords OUT->SetCRD( outframe, FRM ); return CpptrajState::OK; }
// 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; }