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; }