void optimize() { if (use_selection) { Log.info() << "SELECT: " << selection << endl; Selector selector(selection); S.apply(selector); // count selected vs. unselected atoms Size selected = 0; AtomConstIterator ai = S.beginAtom(); for (; +ai; ++ai) { selected += (ai->isSelected() ? 1 : 0); } Log.info() << "selected " << selected << " out of " << S.countAtoms() << " atoms." << endl; } // minimize Log.info() << "starting minimization"; EnergyMinimizer* minimizer; if (sd_minimizer) { minimizer = new SteepestDescentMinimizer(amber); } else { minimizer = new ConjugateGradientMinimizer(amber); } if (verbose) { minimizer->setEnergyOutputFrequency(1); } else { minimizer->setEnergyOutputFrequency(20); } minimizer->setEnergyDifferenceBound(1e-9); minimizer->setMaxSameEnergy(20); minimizer->setMaxGradient(max_gradient); minimizer->minimize(max_iterations); Log.info() << "minimization complete" << endl; Log.info() << "final gradient: " << amber.getRMSGradient() << " kJ/mol A" << endl; S.deselect(); amber.updateEnergy(); Log.info() << "final energy: " << amber.getEnergy() << " kJ/mol" << endl; // dump the minimizer and force field options // for documentation purposes amber.options.dump(Log); minimizer->options.dump(Log); Log.info() << "done." << endl; }
void singlePoint() { double energy = amber.updateEnergy(); amber.updateForces(); Gradient grad; grad.set(amber.getAtoms()); grad.normalize(); Log.info() << "single point energy: " << energy << " kJ/mol" << endl; Log.info() << " - stretch :" << amber.getStretchEnergy() << " kJ/mol" << endl; Log.info() << " - bend :" << amber.getBendEnergy() << " kJ/mol" << endl; Log.info() << " - torsion :" << amber.getTorsionEnergy() << " kJ/mol" << endl; Log.info() << " - VdW :" << amber.getVdWEnergy() << " kJ/mol" << endl; Log.info() << " - electrostatic:" << amber.getESEnergy() << " kJ/mol" << endl; Log.info() << "grad: " << grad.rms << endl; }
void checkStructures() { // fragment DB if (frag_db == 0) { frag_db = new FragmentDB; } Log.info() << "system contains " << S.countAtoms() << " atoms." << endl; // building bonds S.apply(frag_db->build_bonds); // checking residues Log.info() << "checking system" << endl; ResidueChecker check(*frag_db); S.apply(check); // Check residue energies double energy_limit = 500.0; S.deselect(); amber.setup(S); ResidueIterator it = S.beginResidue(); for (; +it; ++it) { it->select(); amber.updateEnergy(); double residue_energy = amber.getStretchEnergy() + amber.getBendEnergy() + amber.getVdWEnergy(); if (residue_energy > energy_limit) { Log.info() << "suspicious energies in residue " << it->getFullName() << ":" << it->getID() << " " << residue_energy << " kJ/mol (bend: " << amber.getBendEnergy() << " kJ/mol, stretch: " << amber.getStretchEnergy() << " kJ/mol, vdW: " << amber.getVdWEnergy() << " kJ/mol)" << endl; } it->deselect(); double quality = std::max(0.0, std::min(1.0, (energy_limit - residue_energy) / energy_limit)); for (PDBAtomIterator ai = it->beginPDBAtom(); +ai; ++ai) { ai->setOccupancy(quality); } } }
int main(int argc, char** argv) { Log.setPrefix(cout, "[%T] "); Log.setPrefix(cerr, "[%T] ERROR: "); // issue a usage hint if called without parameters if (argc != 3) { Log << argv[0] << " <PDB infile> <PDB outfile>" << endl; return 1; } // open a PDB file with the name of the first argument PDBFile file(argv[1]); if (!file) { // if file does not exist: complain and abort Log.error() << "error opening " << argv[1] << " for input." << endl; return 2; } // create a system and read the contents of the PDB file System S; file >> S; file.close(); // print the number of atoms read from the file Log << "read " << S.countAtoms() << " atoms." << endl; // now we open a fragment database Log << "reading fragment DB..." << endl; FragmentDB fragment_db(""); // and normalize the atom names, i.e. we convert different // naming standards to the PDB naming scheme - just in case! Log << "normalizing names..." << endl; S.apply(fragment_db.normalize_names); // now we add any missing hydrogens to the residues // the data on the hydrogen positions stems from the // fragment database. However the hydrogen positions // created in this way are only good estimates Log << "creating missing atoms..." << endl; S.apply(fragment_db.add_hydrogens); Log << "added " << fragment_db.add_hydrogens.getNumberOfInsertedAtoms() << " atoms" << endl; // now we create the bonds between the atoms (PDB files hardly // ever contain a complete set of CONECT records) Log << "building bonds..." << endl; S.apply(fragment_db.build_bonds); // now we check whether the model we built is consistent // The ResidueChecker checks for charges, bond lengths, // and missing atoms Log << "checking the built model..." << endl; ResidueChecker checker(fragment_db); S.apply(checker); // now we create an AMBER force field Log << "setting up force field..." << endl; AmberFF FF; // we then select all hydrogens (element(H)) // using a specialized processor (Selector) S.deselect(); FF.setup(S); Selector selector("element(H)"); S.apply(selector); // just for curiosity: check how many atoms we are going // to optimize Log << "optimizing " << FF.getNumberOfMovableAtoms() << " out of " << S.countAtoms() << " atoms" << endl; // now we create a minimizer object that uses a conjugate // gradient algorithm to optimize the atom positions ConjugateGradientMinimizer minimizer; // calculate the total energy of the system float initial_energy = FF.updateEnergy(); Log << "initial energy: " << initial_energy << " kJ/mol" << endl; // initialize the minimizer and perform (up to) // 1000 optimization steps minimizer.setup(FF); minimizer.setEnergyOutputFrequency(1); minimizer.minimize(50); // calculate the terminal energy and print it float terminal_energy = FF.getEnergy(); Log << "energy before/after minimization: " << initial_energy << "/" << terminal_energy << " kJ/mol" << endl; // write the optimized structure to a file whose // name is given as the second command line argument Log << "writing PBD file " << argv[2] << endl; file.open(argv[2], ios::out); file << S; file.close(); // done. return 0; }
int main(int argc, char** argv) { if (argc != 3) { Log.error() << argv[0] << " <pdb file A> <pdb file B>" << endl; return 1; } // open the first PDB file PDBFile pdb(argv[1]); if (pdb.bad()) { // if the file could not be opened, print error message and exit Log.error() << "cannot open PBD file " << argv[1] << endl; return 2; } // read the contents of the file A into a system System A; pdb >> A; pdb.close(); // open the second PDB file pdb.open(argv[2]); if (pdb.bad()) { // if the file could not be opened, print error message and exit Log.error() << "cannot open PBD file " << argv[2] << endl; return 2; } // read the contents of the file B into a system System B; pdb >> B; pdb.close(); // normalize the names and build all bonds Log.info() << "normalizing names and building bonds..." << endl; FragmentDB db(""); A.apply(db.normalize_names); A.apply(db.build_bonds); B.apply(db.normalize_names); B.apply(db.build_bonds); // calculate the atomic contact energies of A and B float ACE_A = calculateACE(A); float ACE_B = calculateACE(B); // calculate the electrostatic energies of A and B AmberFF amber; amber.options[AmberFF::Option::ASSIGN_CHARGES] = "true"; amber.options[AmberFF::Option::OVERWRITE_CHARGES] = "true"; amber.setup(A); amber.updateEnergy(); float ES_A = amber.getESEnergy(); float C_A = calculateCoulomb(A); amber.setup(B); amber.updateEnergy(); float ES_B = amber.getESEnergy(); float C_B = calculateCoulomb(B); // finally, join the to systems into a single system cout << "atoms in A: " << A.countAtoms() << endl; cout << "atoms in B: " << B.countAtoms() << endl; A.splice(B); cout << "final atoms: " << A.countAtoms() << endl; float ACE_AB = calculateACE(A); amber.setup(A); amber.updateEnergy(); float ES_AB = amber.getESEnergy(); float C_AB = calculateCoulomb(A); // print the resulting energies cout << "ES energy of A: " << ES_A << endl; cout << "ES energy of B: " << ES_B << endl; cout << "ES energy of AB:" << ES_AB << endl; cout << "C energy of A: " << C_A << endl; cout << "C energy of B: " << C_B << endl; cout << "C energy of AB:" << C_AB << endl; cout << "change in atomic contact energy on binding: " << (ACE_AB - ACE_A - ACE_B) << " kJ/mol" << endl; cout << "change in electrostatic energy on binding: " << (ES_AB - ES_A - ES_B) << " kJ/mol" << endl; cout << "total binding free energy: " << (ACE_AB - ACE_A - ACE_B) + (ES_AB - ES_A - ES_B) << " kJ/mol" << endl; // done return 0; }