// Action_MultiDihedral::DoAction() Action::RetType Action_MultiDihedral::DoAction(int frameNum, Frame* currentFrame, Frame** frameAddress) { std::vector<DataSet*>::iterator ds = data_.begin(); for (DihedralSearch::mask_it dih = dihSearch_.begin(); dih != dihSearch_.end(); ++dih, ++ds) { double torsion = Torsion( currentFrame->XYZ((*dih).A0()), currentFrame->XYZ((*dih).A1()), currentFrame->XYZ((*dih).A2()), currentFrame->XYZ((*dih).A3()) ); torsion *= RADDEG; (*ds)->Add(frameNum, &torsion); } return Action::OK; }
// Action_ClusterDihedral::DoAction() Action::RetType Action_ClusterDihedral::DoAction(int frameNum, Frame* currentFrame, Frame** frameAddress) { // For each dihedral, calculate which bin it should go into and store bin# int bidx = 0; for (std::vector<DCmask>::const_iterator dih = DCmasks_.begin(); dih != DCmasks_.end(); ++dih) { double PHI = Torsion( currentFrame->XYZ(dih->A1()), currentFrame->XYZ(dih->A2()), currentFrame->XYZ(dih->A3()), currentFrame->XYZ(dih->A4()) ); // NOTE: Torsion is in radians; should bins be converted to rads as well? PHI *= Constants::RADDEG; //mprintf("[%6i]Dihedral=%8.3f", dih->A1(), PHI); // DEBUG PHI -= dih->Min(); //mprintf(" Shifted=%8.3f", PHI); // DEBUG if (PHI < 0) PHI += 360; //mprintf(" Wrapped=%8.3f", PHI); // DEBUG PHI /= dih->Step(); int phibin = (int)PHI; //mprintf(" Bin=%3i\n", phibin); // DEBUG Bins_[bidx++] = phibin; } // DEBUG - print bins //mprintf("["); //for (std::vector<int>::const_iterator bin = Bins_.begin(); bin != Bins_.end(); ++bin) // mprintf("%3i,",*bin); //mprintf("]\n"); // Now search for this bin combo in the DCarray std::vector<DCnode>::iterator DC = dcarray_.begin(); for (; DC != dcarray_.end(); ++DC) { if ( DC->BinMatch( Bins_ ) ) break; } if (DC == dcarray_.end()) { // No match; create new bin combo and store frame num //mprintf("NEW DCNODE.\n"); dcarray_.push_back( DCnode( Bins_, frameNum ) ); } else { // Match; increment bin count and store frame num //mprintf("DCNODE ALREADY PRESENT.\n"); DC->Increment(); DC->AddFrame( frameNum ); } // Store frame number lastframe_ = frameNum; return Action::OK; }
// Action_MakeStructure::DoAction() Action::RetType Action_MakeStructure::DoAction(int frameNum, Frame* currentFrame, Frame** frameAddress) { Matrix_3x3 rotationMatrix; for (std::vector<SecStructHolder>::iterator ss = secstruct_.begin(); ss != secstruct_.end(); ++ss) { std::vector<float>::iterator theta = ss->thetas_.begin(); std::vector<AtomMask>::iterator Rmask = ss->Rmasks_.begin(); for (DihedralSearch::mask_it dih = ss->dihSearch_.begin(); dih != ss->dihSearch_.end(); ++dih, ++theta, ++Rmask) { double theta_in_radians = (double)*theta; // Calculate current value of dihedral double torsion = Torsion( currentFrame->XYZ( (*dih).A0() ), currentFrame->XYZ( (*dih).A1() ), currentFrame->XYZ( (*dih).A2() ), currentFrame->XYZ( (*dih).A3() ) ); // Calculate delta needed to get to theta double delta = theta_in_radians - torsion; // Set axis of rotation Vec3 axisOfRotation = currentFrame->SetAxisOfRotation((*dih).A1(), (*dih).A2()); // Calculate rotation matrix for delta rotationMatrix.CalcRotationMatrix(axisOfRotation, delta); if (debug_ > 0) { std::string a0name = CurrentParm_->TruncResAtomName( (*dih).A0() ); std::string a1name = CurrentParm_->TruncResAtomName( (*dih).A1() ); std::string a2name = CurrentParm_->TruncResAtomName( (*dih).A2() ); std::string a3name = CurrentParm_->TruncResAtomName( (*dih).A3() ); mprintf("\tRotating Dih %i:%s (%i-%i-%i-%i) (@%.2f) by %.2f deg to get to %.2f.\n", (*dih).ResNum()+1, (*dih).Name().c_str(), (*dih).A0() + 1, (*dih).A1() + 1, (*dih).A2() + 1, (*dih).A3() + 1, torsion*Constants::RADDEG, delta*Constants::RADDEG, theta_in_radians*Constants::RADDEG); } // Rotate around axis currentFrame->Rotate(rotationMatrix, *Rmask); } } return Action::OK; }
/** For each dihedral defined in JcouplingInfo, perform the dihedral and * Jcoupling calculation. */ Action::RetType Action_Jcoupling::DoAction(int frameNum, ActionFrame& frm) { double Jval; if (outputfile_ != 0) outputfile_->Printf("#Frame %i\n",frameNum+1); for (std::vector<jcouplingInfo>::iterator jc = JcouplingInfo_.begin(); jc !=JcouplingInfo_.end(); ++jc) { double phi = Torsion(frm.Frm().XYZ(jc->atom[0]), frm.Frm().XYZ(jc->atom[1]), frm.Frm().XYZ(jc->atom[2]), frm.Frm().XYZ(jc->atom[3]) ); if (jc->type==1) { //phitemp = phi + jc->C[3]; // Only necessary if offsets become used in perez-type calc Jval = jc->C[0] + (jc->C[1] * cos(phi)) + (jc->C[2] * cos(phi * 2.0)); } else { double phitemp = cos( phi + jc->C[3] ); Jval = (jc->C[0] * phitemp * phitemp) + (jc->C[1] * phitemp) + jc->C[2]; } float fval = (float)Jval; jc->data_->Add(frameNum, &fval); int residue = jc->residue; // Output if (outputfile_ != 0) outputfile_->Printf("%5i %4s%4s%4s%4s%4s%12f%12f\n", residue+1, CurrentParm_->Res(residue).c_str(), (*CurrentParm_)[jc->atom[0]].c_str(), (*CurrentParm_)[jc->atom[1]].c_str(), (*CurrentParm_)[jc->atom[2]].c_str(), (*CurrentParm_)[jc->atom[3]].c_str(), phi*Constants::RADDEG, Jval); } return Action::OK; }
// Action_Dihedral::action() Action::RetType Action_Dihedral::DoAction(int frameNum, Frame* currentFrame, Frame** frameAddress) { Vec3 a1, a2, a3, a4; if (useMass_) { a1 = currentFrame->VCenterOfMass( M1_ ); a2 = currentFrame->VCenterOfMass( M2_ ); a3 = currentFrame->VCenterOfMass( M3_ ); a4 = currentFrame->VCenterOfMass( M4_ ); } else { a1 = currentFrame->VGeometricCenter( M1_ ); a2 = currentFrame->VGeometricCenter( M2_ ); a3 = currentFrame->VGeometricCenter( M3_ ); a4 = currentFrame->VGeometricCenter( M4_ ); } double torsion = Torsion(a1.Dptr(), a2.Dptr(), a3.Dptr(), a4.Dptr()); torsion *= RADDEG; dih_->Add(frameNum, &torsion); //fprintf(outfile,"%10i %10.4lf\n",frameNum,D); 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; }
/** Given two atommaps and a map relating the two, find chiral centers for * which at least 3 of the atoms have been mapped. Assign the remaining * two atoms based on improper dihedrals. * \return the total number of mapped atoms. * NOTE: ONLY WORKS FOR SP3 */ int Action_AtomMap::mapChiral(AtomMap& Ref, AtomMap& Tgt) { int uR[5], uT[5], nR[4], nT[4]; double dR[4], dT[4]; int numMappedAtoms=0; for (int ratom=0; ratom < Ref.Natom(); ratom++) { // Skip non-mapped atoms if (!Ref[ratom].IsMapped()) continue; //mprintf("DBG: mapChiral: Ref atom %i:%s\n",atom,Ref->P->names[atom]); int tatom = AMap_[ratom]; // Check that map value is valid if (tatom<0) { mprintf(" Error: mapChiral: Ref atom %i:%s map value is invalid.\n", ratom+1, Ref[ratom].c_str()); return -1; } // If this Ref atom already completely mapped, skip if (Ref[ratom].Complete()) { // Sanity check - if Ref atom is completely mapped, target should be // unless # atoms in Tgt and Ref are different. if (!Tgt[tatom].Complete()) { mprintf("Warning: mapChiral: Ref atom %i:%s is complete but Tgt atom %i:%s is not.\n", ratom+1, Ref[ratom].c_str(), tatom+1, Tgt[tatom].c_str()); //return 1; } continue; } // Check if this is a chiral center if (!Ref[ratom].IsChiral()) continue; // If target atom is not a chiral center (e.g. due to diff # atoms) // mapping by chirality is not important for this reference, let // mapByIndex handle it. if (!Tgt[tatom].IsChiral()) { mprintf("Warning: mapChiral: Ref atom %i:%s is chiral but Tgt atom %i:%s is not!\n", ratom+1, Ref[ratom].c_str(), tatom+1, Tgt[tatom].c_str()); mprintf(" Marking Ref atom as non-chiral to try and map Tgt.\n"); Ref[ratom].SetNotChiral(); continue; } // Both atoms are chiral centers. Place bonded atoms (starting with // central atom) in R and T. uR[0] = ratom; uT[0] = tatom; int nunique = 1; int notunique_r = 0; // Look for mapped bonded ref and target atoms, and nonmapped reference atoms for (Atom::bond_iterator r = Ref[ratom].bondbegin(); r != Ref[ratom].bondend(); r++) { int t = AMap_[*r]; if (!Ref[*r].IsMapped()) { // Bonded atom r is not mapped nR[notunique_r++] = *r; } else { // Bonded atom r is mapped. If a target was mapped to it // (i.e. it is the same atom) store it. if (t>=0) { if (Ref[*r].IsMapped() && Tgt[t].IsMapped()) { uR[nunique] = *r; uT[nunique] = t; ++nunique; } } } } // Fill nT with nonmapped atoms from target int notunique_t = 0; for (Atom::bond_iterator tt = Tgt[tatom].bondbegin(); tt != Tgt[tatom].bondend(); tt++) { if (!Tgt[*tt].IsMapped()) nT[notunique_t++] = *tt; } // notunique_r may not be the same as notunique_t if the # atoms is different if (notunique_r != notunique_t) mprintf("Warning: Ref and Tgt do not have the same # of nonmapped atoms.\n"); if (debug_>0) { mprintf(" Potential Chiral center Ref=%i:%s Tgt=%i:%s Mapped atoms=%i, non-Mapped=%i/%i\n", ratom+1, Ref[ratom].c_str(), tatom+1, Tgt[tatom].c_str(), nunique, notunique_r, notunique_t); for (int i=0; i<nunique; i++) mprintf("\t Mapped\t%4i:%s %4i:%s\n", uR[i]+1, Ref[uR[i]].c_str(), uT[i]+1, Tgt[uT[i]].c_str()); for (int i=0; i<notunique_r; i++) mprintf("\tNotMappedRef\t%4i:%s\n", nR[i]+1, Ref[nR[i]].c_str()); for (int i=0; i<notunique_t; i++) mprintf("\tNotMappedTgt\t %4i:%4s\n", nT[i]+1, Tgt[nT[i]].c_str()); } // If all atoms are unique no need to map // NOTE: Should be handled by complete check above. //if (nunique==5) continue; // Require at least 3 unique atoms for dihedral calc. if (nunique<3) { if (debug_>0) mprintf(" Warning: Center has < 3 mapped atoms, dihedral cannot be calcd.\n"); continue; } // Calculate reference improper dihedrals for (int i=0; i<notunique_r; i++) { dR[i] = Torsion( RefFrame_->RefFrame().XYZ(uR[0]), RefFrame_->RefFrame().XYZ(uR[1]), RefFrame_->RefFrame().XYZ(uR[2]), RefFrame_->RefFrame().XYZ(nR[i]) ); if (debug_>1) mprintf(" Ref Improper %i [%3i,%3i,%3i,%3i]= %lf\n",i, uR[0]+1, uR[1]+1, uR[2]+1, nR[i]+1, dR[i]+1); } // Calculate target improper dihedrals for (int i=0; i<notunique_t; i++) { dT[i] = Torsion( TgtFrame_->RefFrame().XYZ(uT[0]), TgtFrame_->RefFrame().XYZ(uT[1]), TgtFrame_->RefFrame().XYZ(uT[2]), TgtFrame_->RefFrame().XYZ(nT[i]) ); if (debug_>1) mprintf(" Tgt Improper %i [%3i,%3i,%3i,%3i]= %lf\n",i, uR[0]+1, uR[1]+1, uR[2]+1, nT[i]+1, dT[i]+1); } // Match impropers to each other using a cutoff. Note that all torsions // are in radians. // NOTE: 10.0 degrees seems reasonable? Also there is currently no // check for repeated deltas. for (int i=0; i<notunique_r; i++) { for (int j=0; j<notunique_t; j++) { double delta = dR[i] - dT[j]; if (delta<0.0) delta=-delta; if (delta<0.17453292519943295769236907684886) { if (debug_>0) mprintf(" Mapping tgt atom %i:%s to ref atom %i:%s based on chirality.\n", nT[j]+1, Tgt[nT[j]].c_str(), nR[i]+1, Ref[nR[i]].c_str() ); AMap_[ nR[i] ] = nT[j]; ++numMappedAtoms; // Once an atom has been mapped set its mapped flag Ref[nR[i]].SetMapped(); Tgt[nT[j]].SetMapped(); } else if (notunique_r == 1 && notunique_t == 1) { // This is the only non-mapped atom of the chiral center but for // some reason the improper dihedral doesnt match. Map it but warn // the user. mprintf("Warning: Ref %i:%s and Tgt %i:%s are the only unmapped atoms of chiral\n" "Warning: centers %i:%s | %i:%s, but the improper dihedral angles do not\n" "Warning: match (%.4f rad != %.4f rad). This can indicate structural problems\n" "Warning: in either the target or reference. Mapping atoms, but it is\n" "Warning: recommended the structures be visually inspected for problems.\n", nR[i]+1, Ref[nR[i]].c_str(), nT[j]+1, Tgt[nT[j]].c_str(), ratom+1, Ref[ratom].c_str(), tatom+1, Tgt[tatom].c_str(), dR[i], dT[j]); AMap_[ nR[i] ] = nT[j]; ++numMappedAtoms; Ref[nR[i]].SetMapped(); Tgt[nT[j]].SetMapped(); } } } // Check if ref atom or tgt atom is now completely mapped Ref.MarkAtomComplete(ratom,false); Tgt.MarkAtomComplete(tatom,false); } // End loop over ratom return numMappedAtoms; }
// 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; }