bool OBConformerSearch::Setup(const OBMol &mol, int numConformers, int numChildren, int mutability, int convergence) { // copy some variables m_mol = mol; m_numConformers = numConformers; m_numChildren = numChildren; m_mutability = mutability; m_convergence = convergence; if (m_mol.GetCoordinates() == NULL) return false; // Initialize the OBRotorList m_rotorList.SetFixedBonds(m_fixedBonds); m_rotorList.Setup(m_mol); if (!m_rotorList.Size()) { // only one conformer return false; } // create initial population OBRandom generator; generator.TimeSeed(); RotorKey rotorKey(m_rotorList.Size() + 1, 0); // indexed from 1 if (IsGood(rotorKey)) m_rotorKeys.push_back(rotorKey); else { cout << "Initial conformer does not pass filter!" << endl; } int tries = 0; while (m_rotorKeys.size() < m_numConformers && tries < numConformers * 1000) { tries++; // perform random mutation(s) OBRotorIterator ri; OBRotor *rotor = m_rotorList.BeginRotor(ri); for (int i = 1; i < m_rotorList.Size() + 1; ++i, rotor = m_rotorList.NextRotor(ri)) { if (generator.NextInt() % m_mutability == 0) rotorKey[i] = generator.NextInt() % rotor->GetResolution().size(); } // duplicates are always rejected if (!IsUniqueKey(m_rotorKeys, rotorKey)) continue; // execute filter(s) if (!IsGood(rotorKey)) continue; // add the key m_rotorKeys.push_back(rotorKey); } // print out initial conformers cout << "Initial conformer count: " << m_rotorKeys.size() << endl; for (unsigned int i = 0; i < m_rotorKeys.size(); ++i) { for (unsigned int j = 1; j < m_rotorKeys[i].size(); ++j) std::cout << m_rotorKeys[i][j] << " "; std::cout << std::endl; } return true; }
bool OBRotorList::FindRotors(OBMol &mol, bool sampleRingBonds) { // Find ring atoms & bonds // This function will set OBBond::IsRotor(). mol.FindRingAtomsAndBonds(); obErrorLog.ThrowError(__FUNCTION__, "Ran OpenBabel::FindRotors", obAuditMsg); // // Score the bonds using the graph theoretical distance (GTD). // The GTD is the distance from atom i to every other atom j. // Atoms on the "inside" of the molecule will have a lower GTD // value than atoms on the "outside" // // The scoring will rank "inside" bonds first. // vector<int> gtd; mol.GetGTDVector(gtd); // compute the scores vector<OBBond*>::iterator i; vector<pair<OBBond*,int> > vtmp; for (OBBond *bond = mol.BeginBond(i);bond;bond = mol.NextBond(i)) { // check if the bond is "rotatable" if (bond->IsRotor(sampleRingBonds)) { // check if the bond is fixed (using deprecated fixed atoms or new fixed bonds) if ((HasFixedAtoms() || HasFixedBonds()) && IsFixedBond(bond)) continue; if (bond->IsInRing()) { //otherwise mark that we have them and add it to the pile _ringRotors = true; } int score = gtd[bond->GetBeginAtomIdx()-1] + gtd[bond->GetEndAtomIdx()-1]; // compute the GTD bond score as sum of atom GTD scores vtmp.push_back(pair<OBBond*,int> (bond,score)); } } // sort the rotatable bonds by GTD score sort(vtmp.begin(),vtmp.end(),CompareRotor); // create rotors for the bonds int count = 0; vector<pair<OBBond*,int> >::iterator j; for (j = vtmp.begin(); j != vtmp.end(); ++j, ++count) { OBRotor *rotor = new OBRotor; rotor->SetBond((*j).first); rotor->SetIdx(count); rotor->SetNumCoords(mol.NumAtoms()*3); _rotor.push_back(rotor); } return true; }
void OBRotorList::RemoveSymVals(OBMol &mol) { OBGraphSym gs(&mol); vector<unsigned int> sym_classes; gs.GetSymmetry(sym_classes); OBRotor *rotor; vector<OBRotor*>::iterator i; std::set<unsigned int> syms; for (rotor = BeginRotor(i);rotor;rotor = NextRotor(i)) { OBBond* bond = rotor->GetBond(); OBAtom* end = bond->GetEndAtom(); OBAtom* begin = bond->GetBeginAtom(); int N_fold_symmetry = 1; for (int here=0; here <= 1; ++here) { // Try each side of the bond in turn OBAtom *this_side, *other_side; if (here == 0) { this_side = begin; other_side = end; } else { this_side = end; other_side = begin; } for (int hyb=2; hyb<=3; ++hyb) { // sp2 and sp3 carbons, with explicit Hs if (this_side->GetAtomicNum() == 6 && this_side->GetHyb() == hyb && this_side->GetValence() == (hyb + 1) ) { syms.clear(); FOR_NBORS_OF_ATOM(nbr, this_side) { if ( &(*nbr) == other_side ) continue; syms.insert(sym_classes[nbr->GetIdx() - 1]); } if (syms.size() == 1) // All of the rotated atoms have the same symmetry class N_fold_symmetry *= hyb; } } } if (N_fold_symmetry > 1) { size_t old_size = rotor->Size(); rotor->RemoveSymTorsionValues(N_fold_symmetry); if (!_quiet) { cout << "...." << N_fold_symmetry << "-fold symmetry at rotor between " << begin->GetIdx() << " and " << end->GetIdx(); cout << " - reduced from " << old_size << " to " << rotor->Size() << endl; } } }
void testOBRotorSetToAngle() { // 1 2 3 4 5 6 7 8 // C-C-C-C-C-C-C-C // 0 1 2 3 4 5 6 OBMolPtr mol = OBTestUtil::ReadFile("octane.cml"); OBBond *bond = mol->GetBond(3); OBRotor rotor; // set the bond to rotate rotor.SetBond(bond); // set the dihedral indexes (these start from 1) int ref[4] = {3, 4, 5, 6}; rotor.SetDihedralAtoms(ref); // find atoms to rotate std::vector<int> atoms; mol->FindChildren(atoms, 4, 5); // convert to coordinate indexes (start from 0, multiplied by 3) for (unsigned int i = 0; i < atoms.size(); ++i) atoms[i] = (atoms[i] - 1) * 3; rotor.SetRotAtoms(atoms); OB_ASSERT(IsNear_mod(fabs(RAD_TO_DEG * rotor.CalcTorsion(mol->GetCoordinates())), 180.0, 360.0, 1.0)); // rotate rotor.SetToAngle(mol->GetCoordinates(), 60.0 * DEG_TO_RAD); OB_ASSERT(IsNear(RAD_TO_DEG * rotor.CalcTorsion(mol->GetCoordinates()), 60.0, 1.0)); }
void OBConformerSearch::NextGeneration() { // create next generation population OBRandom generator; generator.TimeSeed(); // generate the children int numConformers = m_rotorKeys.size(); for (int c = 0; c < numConformers; ++c) { for (int child = 0; child < m_numChildren; ++child) { bool foundKey = false; int tries = 0; while (!foundKey) { tries++; if (tries > 1000) foundKey = true; RotorKey rotorKey = m_rotorKeys[c]; // copy parent gene // perform random mutation(s) OBRotorIterator ri; OBRotor *rotor = m_rotorList.BeginRotor(ri); for (int i = 1; i < m_rotorList.Size() + 1; ++i, rotor = m_rotorList.NextRotor(ri)) { if (generator.NextInt() % m_mutability == 0) rotorKey[i] = generator.NextInt() % rotor->GetResolution().size(); // permutate gene } // duplicates are always rejected if (!IsUniqueKey(m_rotorKeys, rotorKey)) continue; // execute the filter(s) if (!IsGood(rotorKey)) continue; // add the key m_rotorKeys.push_back(rotorKey); // append child to population // set foundKey to generate the next child foundKey = true; } } } }
int main(int argc,char *argv[]) { if (argc != 2) { cout << "Usage: obrotamer <file>" << endl; cout << " Outputs the number of rotable bonds and generate a random" << " rotamer" << endl; return(-1); } ifstream ifs(argv[1]); if (!ifs) { cerr << "Error! Cannot read input file!" << endl; return(-1); } OBConversion conv(&ifs, &cout); OBFormat* pFormat; pFormat = conv.FormatFromExt(argv[1]); if ( pFormat == NULL ) { cerr << "Error! Cannot read file format!" << endl; return(-1); } // Finally, we can do some work! OBMol mol; if (! conv.SetInAndOutFormats(pFormat, pFormat)) { cerr << "Error! File format isn't loaded" << endl; return (-1); } OBRotorList rl; OBRotamerList rotamers; int *rotorKey = NULL; OBRandom rand; rand.TimeSeed(); while(ifs.peek() != EOF && ifs.good()) { mol.Clear(); conv.Read(&mol); rl.Setup(mol); cerr << " Number of rotatable bonds: " << rl.Size() << endl; // indexed from 1, rotorKey[0] = 0 std::vector<int> rotorKey(rl.Size() + 1, 0); // each entry represents the configuration of a rotor // e.g. indexes into OBRotor::GetResolution() // (the different angles to sample from the OBRotorRules database) OBRotorIterator ri; OBRotor *rotor = rl.BeginRotor(ri); for (int i = 1; i < rl.Size() + 1; ++i, rotor = rl.NextRotor(ri)) rotorKey[i] = rand.NextInt() % rotor->GetResolution().size(); rotamers.SetBaseCoordinateSets(mol); rotamers.Setup(mol, rl); rotamers.AddRotamer(rotorKey); // This is more useful when you have added many rotamers // rather than the one in this example rotamers.ExpandConformerList(mol, mol.GetConformers()); // Change the molecule conformation -- from 0 .. rotamers.NumRotamers() mol.SetConformer(0); conv.Write(&mol); } // while reading molecules return(0); }
void testOBRotorGetSet() { OBBond bond; OBRotor rotor; // SetBond/GetBond rotor.SetBond(&bond); OB_ASSERT(rotor.GetBond()->GetIdx() == bond.GetIdx()); // SetIdx/GetIdx rotor.SetIdx(45); OB_ASSERT(rotor.GetIdx() == 45); // SetDihedralAtoms/GetDihedralAtoms int ref_ptr[4] = {1, 2, 3, 4}; rotor.SetDihedralAtoms(ref_ptr); rotor.GetDihedralAtoms(ref_ptr); OB_ASSERT(ref_ptr[0] == 1); OB_ASSERT(ref_ptr[1] == 2); OB_ASSERT(ref_ptr[2] == 3); OB_ASSERT(ref_ptr[3] == 4); std::vector<int> ref_vector = rotor.GetDihedralAtoms(); OB_ASSERT(ref_vector[0] == 1); OB_ASSERT(ref_vector[1] == 2); OB_ASSERT(ref_vector[2] == 3); OB_ASSERT(ref_vector[3] == 4); rotor.SetDihedralAtoms(ref_vector); ref_vector = rotor.GetDihedralAtoms(); OB_ASSERT(ref_vector[0] == 1); OB_ASSERT(ref_vector[1] == 2); OB_ASSERT(ref_vector[2] == 3); OB_ASSERT(ref_vector[3] == 4); // SetTorsionValues/GetTorsionValues/Size std::vector<double> angles; angles.push_back(0.0); angles.push_back(3.1415); rotor.SetTorsionValues(angles); OB_ASSERT(rotor.GetTorsionValues().size() == 2); OB_ASSERT(rotor.Size() == 2); }
int OBForceField::DiverseConfGen(double rmsd, unsigned int nconfs, double energy_gap, bool verbose) { _energies.clear(); // Wipe any energies from previous conformer generators // Remove all conformers (e.g. from previous conformer generators) even the current conformer double *initialCoord = new double [_mol.NumAtoms() * 3]; // initial state double *store_initial = new double [_mol.NumAtoms() * 3]; // store the initial state memcpy((char*)initialCoord,(char*)_mol.GetCoordinates(),sizeof(double)*3*_mol.NumAtoms()); memcpy((char*)store_initial,(char*)_mol.GetCoordinates(),sizeof(double)*3*_mol.NumAtoms()); std::vector<double *> newConfs(1, initialCoord); _mol.SetConformers(newConfs); if (_mol.NumRotors() == 0) { SetupPointers(); _energies.push_back(Energy(false)); delete [] store_initial; return 0; } // Get estimate of lowest energy conf using FastRotorSearch FastRotorSearch(true); double lowest_energy = Energy(false); OBRotorList rl; OBBitVec fixed = _constraints.GetFixedBitVec(); rl.SetFixAtoms(fixed); if (_loglvl == 0) rl.SetQuiet(); // Don't print info on symmetry removal rl.Setup(_mol); OBRotorIterator ri; OBRotamerList rotamerlist; rotamerlist.SetBaseCoordinateSets(_mol); rotamerlist.Setup(_mol, rl); // Can take shortcut later, as 4 components of the energy will be constant SetupPointers(); double energy_offset = E_Bond(false) + E_Angle(false) + E_StrBnd(false) + E_OOP(false); lowest_energy -= energy_offset; _energies.push_back(lowest_energy); OBRotorKeys rotorKeys; OBRotor* rotor = rl.BeginRotor(ri); unsigned int combinations = 1; vector<size_t> rotor_sizes; for (unsigned int i = 1; i < rl.Size() + 1; ++i, rotor = rl.NextRotor(ri)) { // foreach rotor size_t size = rotor->GetResolution().size(); rotorKeys.AddRotor(size); combinations *= size; rotor_sizes.push_back(size); if(verbose) { cout << "....rotor " << i << " from " << rotor->GetBond()->GetBeginAtomIdx() << " to " << rotor->GetBond()->GetEndAtomIdx() << " has " << size << " values" << endl; } } if (rotor_sizes.size() > 0 && combinations == 0) { // Overflow! combinations = UINT_MAX; } cout << "..tot conformations = " << combinations << "\n"; if (nconfs == 0) nconfs = 1 << 20; unsigned int max_combinations = min<unsigned int>(nconfs , combinations); LFSR lfsr(max_combinations); // Systematic random number generator if (verbose && combinations > max_combinations) { cout << "....Using a cutoff of " << nconfs << " we will only explore " << std::fixed << setprecision(1) << static_cast<float>(nconfs * 100)/static_cast<float>(combinations) << "% of these\n"; } unsigned int combination; OBDiversePoses divposes(_mol, rmsd, false); vector<int> my_rotorkey(rotor_sizes.size() + 1, 0); unsigned int counter = 0; // Main loop over rotamers unsigned int N_low_energy = 0; do { _mol.SetCoordinates(store_initial); combination = lfsr.GetNext(); unsigned int t = combination; // Convert the combination number into a rotorkey for (unsigned int i = 0 ; i < rotor_sizes.size(); ++i) { my_rotorkey[i + 1] = t % rotor_sizes[i]; t /= rotor_sizes[i]; } rotamerlist.SetCurrentCoordinates(_mol, my_rotorkey); SetupPointers(); double currentE = E_VDW(false) + E_Torsion(false) + E_Electrostatic(false); if (currentE < lowest_energy + energy_gap) { // Don't retain high energy poses divposes.AddPose(_mol.GetCoordinates(), currentE); N_low_energy++; if (currentE < lowest_energy) lowest_energy = currentE; } counter++; } while (combination != 1 && counter < nconfs); // The LFSR always terminates with a 1 cout << "..tot confs tested = " << counter << "\n..below energy threshold = " << N_low_energy << "\n"; // Reset the coordinates to those of the initial structure _mol.SetCoordinates(store_initial); // Get results from the tree UpdateConformersFromTree(&_mol, _energies, &divposes, verbose); // Add back the energy offset transform(_energies.begin(), _energies.end(), _energies.begin(), bind2nd(plus<double>(), energy_offset)); // Clean up delete [] store_initial; return 0; }
void OBForceField::SystematicRotorSearch() { OBRotorList rl; OBRotamerList rotamers; rl.Setup(_mol); rotamers.SetBaseCoordinateSets(_mol); rotamers.Setup(_mol, rl); IF_OBFF_LOGLVL_LOW { OBFFLog("\nS Y S T E M A T I C R O T O R S E A R C H\n\n"); sprintf(logbuf, " NUMBER OF ROTATABLE BONDS: %d\n", rl.Size()); OBFFLog(logbuf); } if (!rl.Size()) { // only one conformer IF_OBFF_LOGLVL_LOW OBFFLog(" GENERATED ONLY ONE CONFORMER\n\n"); ConjugateGradients(2500); // final energy minimizatin for best conformation return; } std::vector<int> rotorKey(rl.Size() + 1, 0); // indexed from 1 OBRotorIterator ri; OBRotor *rotor = rl.BeginRotor(ri); for (int i = 1; i < rl.Size() + 1; ++i, rotor = rl.NextRotor(ri)) { // foreach rotor for (unsigned int j = 0; j < rotor->GetResolution().size(); j++) { // foreach torsion rotorKey[i] = j; rotamers.AddRotamer(rotorKey); } } rotamers.ExpandConformerList(_mol, _mol.GetConformers()); IF_OBFF_LOGLVL_LOW { sprintf(logbuf, " GENERATED %d CONFORMERS\n\n", _mol.NumConformers()); OBFFLog(logbuf); OBFFLog("CONFORMER ENERGY\n"); OBFFLog("--------------------\n"); } // Calculate energy for all conformers char logbuf[100]; std::vector<double> energies(_mol.NumConformers(), 0.0); for (int i = 0; i < _mol.NumConformers(); i++) { _mol.SetConformer(i); // select conformer energies[i] = Energy(); // calculate and store energy IF_OBFF_LOGLVL_LOW { sprintf(logbuf, " %3d %8.3f\n", (i + 1), energies[i]); OBFFLog(logbuf); } } // Select conformer with lowest energy int best_conformer = 0; for (int i = 1; i < _mol.NumConformers(); i++) { if (energies[i] < energies[best_conformer]) best_conformer = i; } IF_OBFF_LOGLVL_LOW { sprintf(logbuf, "\n CONFORMER %d HAS THE LOWEST ENERGY\n\n", best_conformer + 1); OBFFLog(logbuf); } _mol.SetConformer(best_conformer); current_conformer = best_conformer; }
void OBRotamerList::Setup(OBMol &mol,OBRotorList &rl) { //clear the old stuff out if necessary _vres.clear(); vector<unsigned char*>::iterator j; for (j = _vrotamer.begin();j != _vrotamer.end();++j) delete [] *j; _vrotamer.clear(); vector<pair<OBAtom**,vector<int> > >::iterator k; for (k = _vrotor.begin();k != _vrotor.end();++k) delete [] k->first; _vrotor.clear(); _vrings.clear(); _vringTors.clear(); //create the new list OBRotor *rotor; vector<OBRotor*>::iterator i; vector<int> children; int ref[4]; OBAtom **atomlist; for (rotor = rl.BeginRotor(i);rotor;rotor = rl.NextRotor(i)) { atomlist = new OBAtom* [4]; rotor->GetDihedralAtoms(ref); atomlist[0] = mol.GetAtom(ref[0]); atomlist[1] = mol.GetAtom(ref[1]); atomlist[2] = mol.GetAtom(ref[2]); atomlist[3] = mol.GetAtom(ref[3]); mol.FindChildren(children,ref[1],ref[2]); _vrotor.push_back(pair<OBAtom**,vector<int> > (atomlist,children)); _vres.push_back(rotor->GetResolution()); } // if the rotor list has ring bonds, build up an index if (rl.HasRingRotors()){ // go through rings // for each step of the path, see if there's a matching rotor vector<int> path; int pSize; vector<double> ringTorsions; vector<int> ringRotors; FOR_RINGS_OF_MOL(r, mol) { ringTorsions.clear(); ringRotors.clear(); pSize = r->Size(); if (pSize < 4) continue; // not rotatable path = r->_path; for (int j = 0; j < pSize; ++j) { double torsion = mol.GetTorsion(path[(j + pSize - 1) % pSize], path[(j + pSize) % pSize], path[(j + pSize + 1) % pSize], path[(j + pSize + 2) % pSize]); ringTorsions.push_back(torsion); // now check to see if any of these things are rotors int rotorIndex = -1; // not a rotor OBBond *bond = mol.GetBond(path[(j + pSize) % pSize], path[(j + pSize + 1) % pSize]); for (rotor = rl.BeginRotor(i);rotor;rotor = rl.NextRotor(i)) { if (bond != rotor->GetBond()) continue; // no match at all // Central bond matches, make sure 1..4 atoms are in the path rotor->GetDihedralAtoms(ref); if ( (ref[0] == path[(j + pSize - 1) % pSize] && ref[3] == path[(j + pSize + 2) % pSize]) || (ref[3] == path[(j + pSize - 1) % pSize] && ref[0] == path[(j + pSize + 2) % pSize]) ) { rotorIndex = rotor->GetIdx(); } } // end checking all the rotors ringRotors.push_back(rotorIndex); // could be -1 if it's not rotatable } _vringTors.push_back(ringTorsions); _vrings.push_back(ringRotors); } // finished with the rings