// Action_Spam::setup() Action::RetType Action_Spam::Setup(Topology* currentParm, Topology** parmAddress) { // We need box info if (currentParm->BoxType() == Box::NOBOX) { mprinterr("Error: SPAM: Must have explicit solvent with periodic boundaries!"); return Action::ERR; } // See if our box dimensions are too small for our cutoff... if (currentParm->ParmBox().BoxX() < doublecut_ || currentParm->ParmBox().BoxY() < doublecut_ || currentParm->ParmBox().BoxZ() < doublecut_) { mprinterr("Error: SPAM: The box appears to be too small for your cutoff!\n"); return Action::ERR; } // Set up the solvent_residues_ vector int resnum = 0; for (Topology::res_iterator res = currentParm->ResStart(); res != currentParm->ResEnd(); res++) { if (res->Name().Truncated() == solvname_) { solvent_residues_.push_back(*res); // Tabulate COM double mass = 0.0; for (int i = res->FirstAtom(); i < res->LastAtom(); i++) mass += (*currentParm)[i].Mass(); } resnum++; } // DEBUG mprintf("SPAM: Found %d solvent residues [%s]\n", solvent_residues_.size(), solvname_.c_str()); // Set up the charge array and check that we have enough info if (SetupParms(currentParm)) return Action::ERR; // Back up the parm // NOTE: This is a full copy - use reference instead? CurrentParm_ = *currentParm; return Action::OK; }
/** An atom pair list consists of 2 values for each entry, a beginning * index and ending index. For molecules and residues this is the first * and just beyond the last atom; for atoms it is just the atom itself * twice. */ Image::PairType Image::CreatePairList(Topology const& Parm, Mode modeIn, std::string const& maskExpression) { PairType atomPairs; // Set up mask based on desired imaging mode. if ( modeIn == BYMOL || modeIn == BYRES ) { CharMask cmask( maskExpression ); if ( Parm.SetupCharMask( cmask ) ) return atomPairs; cmask.MaskInfo(); if (cmask.None()) return atomPairs; // Set up atom range for each entity to be imaged. if (modeIn == BYMOL) { atomPairs.reserve( Parm.Nmol()*2 ); for (Topology::mol_iterator mol = Parm.MolStart(); mol != Parm.MolEnd(); ++mol) CheckRange( atomPairs, cmask, mol->BeginAtom(), mol->EndAtom()); } else { // BYRES atomPairs.reserve( Parm.Nres()*2 ); for (Topology::res_iterator residue = Parm.ResStart(); residue != Parm.ResEnd(); ++residue) CheckRange( atomPairs, cmask, residue->FirstAtom(), residue->LastAtom() ); } } else { // BYATOM AtomMask imask( maskExpression ); if ( Parm.SetupIntegerMask( imask ) ) return atomPairs; imask.MaskInfo(); if (imask.None()) return atomPairs; atomPairs.reserve( Parm.Natom()*2 ); for (AtomMask::const_iterator atom = imask.begin(); atom != imask.end(); ++atom) { atomPairs.push_back( *atom ); atomPairs.push_back( (*atom)+1 ); } } // mprintf("\tNumber of %ss to be imaged is %zu based on mask '%s'\n", // ModeString[modeIn], atomPairs.size()/2, maskIn.MaskString()); return atomPairs; }
// 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; }
/** Search for bonds between atoms in residues and atoms in adjacent residues * using distance-based criterion that depends on atomic elements. * \param top Topology to add bonds to. * \param frameIn Frame containing atomic coordinates. * \param offset Offset to add when determining if a bond is present. * \param debug If > 0 print extra info. */ int BondSearch( Topology& top, Frame const& frameIn, double offset, int debug) { mprintf("\tDetermining bond info from distances.\n"); if (frameIn.empty()) { mprinterr("Internal Error: No coordinates set; cannot search for bonds.\n"); return 1; } # ifdef TIMER Timer time_total, time_within, time_between; time_total.Start(); time_within.Start(); # endif // ----- STEP 1: Determine bonds within residues for (Topology::res_iterator res = top.ResStart(); res != top.ResEnd(); ++res) { int stopatom = res->LastAtom(); // Check for bonds between each atom in the residue. for (int atom1 = res->FirstAtom(); atom1 != stopatom; ++atom1) { Atom::AtomicElementType a1Elt = top[atom1].Element(); // If this is a hydrogen and it already has a bond, move on. if (a1Elt==Atom::HYDROGEN && top[atom1].Nbonds() > 0 ) continue; for (int atom2 = atom1 + 1; atom2 != stopatom; ++atom2) { Atom::AtomicElementType a2Elt = top[atom2].Element(); double D2 = DIST2_NoImage(frameIn.XYZ(atom1), frameIn.XYZ(atom2) ); double cutoff2 = Atom::GetBondLength(a1Elt, a2Elt) + offset; cutoff2 *= cutoff2; if (D2 < cutoff2) { top.AddBond(atom1, atom2); // Once a bond has been made to hydrogen move on. if (a1Elt==Atom::HYDROGEN) break; } } } } # ifdef TIMER time_within.Stop(); time_between.Start(); # endif // ----- STEP 2: Determine bonds between adjacent residues Topology::mol_iterator nextmol = top.MolStart(); if (top.Nmol() > 0) ++nextmol; for (Topology::res_iterator res = top.ResStart() + 1; res != top.ResEnd(); ++res) { // If molecule information is already present, check if first atom of // this residue >= first atom of next molecule, which indicates this // residue and the previous residue are in different molecules. if ( (nextmol != top.MolEnd()) && (res->FirstAtom() >= nextmol->BeginAtom()) ) { ++nextmol; continue; } // If this residue is recognized as solvent, no need to check previous or // next residue if ( res->NameIsSolvent() ) { ++res; if (res == top.ResEnd()) break; continue; } // Get previous residue Topology::res_iterator previous_res = res - 1; // If previous residue is recognized as solvent, no need to check previous. if ( previous_res->NameIsSolvent() ) continue; // Get previous residue start atom int startatom = previous_res->FirstAtom(); // Previous residue stop atom, this residue start atom int midatom = res->FirstAtom(); // This residue stop atom int stopatom = res->LastAtom(); // Check for bonds between adjacent residues for (int atom1 = startatom; atom1 != midatom; atom1++) { Atom::AtomicElementType a1Elt = top[atom1].Element(); if (a1Elt==Atom::HYDROGEN) continue; for (int atom2 = midatom; atom2 != stopatom; atom2++) { Atom::AtomicElementType a2Elt = top[atom2].Element(); if (a2Elt==Atom::HYDROGEN) continue; double D2 = DIST2_NoImage(frameIn.XYZ(atom1), frameIn.XYZ(atom2) ); double cutoff2 = Atom::GetBondLength(a1Elt, a2Elt) + offset; cutoff2 *= cutoff2; if (D2 < cutoff2) top.AddBond(atom1, atom2); } } } # ifdef TIMER time_between.Stop(); time_total.Stop(); time_within.WriteTiming(2, "Distances within residues", time_total.Total()); time_between.WriteTiming(2, "Distances between residues", time_total.Total()); time_total.WriteTiming(1, "Total for determining bonds via distances"); # endif if (debug > 0) mprintf("\t%s: %zu bonds to hydrogen, %zu other bonds.\n", top.c_str(), top.BondsH().size(), top.Bonds().size()); return 0; }
/** 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; }