Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
LigandDockProtocol.cc
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet:
3 //
4 // (c) Copyright Rosetta Commons Member Institutions.
5 // (c) This file is part of the Rosetta software suite and is made available under license.
6 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
7 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
8 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
9 
10 /// @file protocols/ligand_docking/LigandDockProtocol.cc
11 ///
12 /// @brief
13 /// @author Ian W. Davis
14 
15 
17 
18 #include <core/types.hh>
21 #include <core/graph/Graph.hh>
22 #include <core/grid/CartGrid.hh>
23 #include <core/kinematics/Edge.hh>
27 #include <basic/options/option.hh>
29 #include <core/scoring/Energies.hh>
30 #include <core/scoring/rms_util.hh>
31 #include <core/scoring/sasa.hh>
34 #include <basic/prof.hh>
35 #include <basic/Tracer.hh>
36 #include <basic/MetricValue.hh>
37 
38 //#include <protocols/relax_protocols.hh>
49 #include <protocols/moves/Mover.hh>
57 
58 
59 #include <numeric/conversions.hh>
60 #include <numeric/random/random.hh>
61 #include <numeric/xyzVector.io.hh>
62 #include <ObjexxFCL/FArray1D.hh>
63 #include <ObjexxFCL/string.functions.hh>
64 #include <utility/exit.hh>
65 #include <utility/vector1.hh>
66 #include <utility/file/FileName.hh>
67 
68 #include <utility/pointer/owning_ptr.hh>
69 #include <utility/tools/make_vector1.hh>
70 
71 // AUTO-REMOVED #include <ctime>
72 #include <fstream>
73 #include <sstream>
74 
75 
76 // option key includes
77 
78 #include <basic/options/keys/docking.OptionKeys.gen.hh>
79 #include <basic/options/keys/enzdes.OptionKeys.gen.hh>
80 
81 #include <core/pose/Pose.hh>
83 #include <utility/vector0.hh>
84 
85 
86 
87 
88 namespace protocols {
89 namespace ligand_docking {
90 
91 
92 static numeric::random::RandomGenerator my_RG(4049988); // <- Magic number, do not change it!!!
93 static basic::Tracer TR("protocols.ligand_docking.LigandDockProtocol");
94 
95 
97  //utility::pointer::ReferenceCount(),
98  protocols::moves::Mover(),
100  start_from_pts_(),
101  ligand_torsion_restraints_()
102 {
103  Mover::type( "LigandDockProtocol" );
104 
105  using basic::options::option;
106  using namespace basic::options;
107 
108  // options
109  protocol_ = option[ OptionKeys::docking::ligand::protocol ];
110  minimize_ligand_ = option[ OptionKeys::docking::ligand::minimize_ligand ];
111  minimize_backbone_ = option[ OptionKeys::docking::ligand::minimize_backbone ];
112  tether_ligand_ = option[ OptionKeys::docking::ligand::tether_ligand ].user();
113  minimize_all_rsds_ = false;
114  repack_all_rsds_ = false;
115  rottrials_all_rsds_ = false;
116  ligand_protonation_ = option[ OptionKeys::docking::ligand::mutate_same_name3 ];
117  minimize_water_ = true;
118  sc_interface_padding_ = 0.0;//5.0; // 5A ends up repacking half the protein! (literally)
119  bb_interface_cutoff_ = 7.0; //5.0;
120  ligand_chi_stddev_deg_ = option[ OptionKeys::docking::ligand::harmonic_torsions ];
121  protein_CA_stddev_Ang_ = option[ OptionKeys::docking::ligand::harmonic_Calphas ];
122  ligand_shear_moves_ = (core::Size) option[ OptionKeys::docking::ligand::shear_moves ];
123  ligand_tether_stddev_Ang_ = (tether_ligand_ ? option[ OptionKeys::docking::ligand::tether_ligand ]() : -1.0);
124 
125  if( option[ OptionKeys::docking::ligand::start_from ].user() ) {
126  utility::vector1< core::Real > start_from = option[ OptionKeys::docking::ligand::start_from ]();
127  // Make sure a whole number of triples were supplied
128  if( start_from.size() % 3 != 0 ) {
129  utility_exit_with_message("-start_from requires one or more X,Y,Z triples -- you didn't provide enough numbers!");
130  }
131  for(Size ii = 1; ii <= start_from.size(); ii += 3) {
132  start_from_pts_.push_back( core::Vector(start_from[ii], start_from[ii+1], start_from[ii+2]) );
133  }
134  }
135  if( ligand_shear_moves_ && !basic::options::option[ basic::options::OptionKeys::docking::ligand::use_ambig_constraints ]() ) {
136  utility_exit_with_message("Must use ambiguous torsion constraints with ligand shear moves!");
137  }
138 }
139 
141  std::string const protocol,
142  bool const minimize_ligand,
143  bool const minimize_backbone,
144  bool const tether_ligand,
145  bool const mutate_same_name3,
146  core::Real const ligand_chi_stddev_deg,
147  core::Real const protein_CA_stddev_Ang,
148  core::Real const ligand_tether_stddev_Ang,
149  core::Size const ligand_shear_moves
150 ):
152  protocol_(protocol),
153  minimize_ligand_(minimize_ligand),
154  minimize_backbone_(minimize_backbone),
155  tether_ligand_(tether_ligand),
156  ligand_protonation_(mutate_same_name3),
157  ligand_chi_stddev_deg_(ligand_chi_stddev_deg),
158  protein_CA_stddev_Ang_(protein_CA_stddev_Ang),
159  ligand_tether_stddev_Ang_(ligand_tether_stddev_Ang),
160  ligand_shear_moves_(ligand_shear_moves),
161  minimize_all_rsds_(false),
162  repack_all_rsds_(false),
163  rottrials_all_rsds_(false),
164  minimize_water_(true),
165  start_from_pts_(),
167 {
168  Mover::type( "LigandDockProtocol" );
169  sc_interface_padding_= 0.0;//5.0; // 5A ends up repacking half the protein! (literally)
170  bb_interface_cutoff_ = 7.0; //5.0;
171 
172  using basic::options::option;
173  using namespace basic::options;
174 
175  if( ligand_shear_moves_ && !option[ OptionKeys::docking::ligand::use_ambig_constraints ]() ) {
176  utility_exit_with_message("Must use ambiguous torsion constraints with ligand shear moves!");
177  }
178 }
179 
180 void
182  start_from_pts_.push_back( core::Vector(x, y, z) );
183 }
184 
186  //utility::pointer::ReferenceCount(),
187  protocols::moves::Mover(),
189 {
190  utility_exit_with_message("copy c-tor not allowed!");
191 }
192 
193 
195 
196 
197 /// @brief Creates a new hierarchy of Movers for each Pose passed in.
198 /// @details Some Movers (e.g. repack) require knowledge of the Pose to create,
199 /// and are only valid for that Pose and other conformations of it
200 /// (i.e. poses with the same number of residues, jumps, etc).
201 /// In general, we expect each Pose coming in here to be from a different PDB file.
202 /// The cost of creating these objects anew should be minimal compared
203 /// to the processing work they do.
204 void
206 {
207  basic::prof_reset();
208  using namespace protocols::moves;
210 
211  core::pack::dunbrack::load_unboundrot(pose); // adds scoring bonuses for the "unbound" rotamers, if any
212 
213  if( protocol_ == "rescore" ) return;
214 
215  // Run most of search with soft-rep, but do final minimization and scoring with hard-rep.
217 
218  // If we change the fold tree during the course of this run,
219  // we should restore it afterwards for scoring and output!
220  core::kinematics::FoldTree fold_tree_copy = pose.fold_tree();
221 
222  core::Size const jump_id= get_ligand_jump_id(pose);
223  core::Size const lig_id = get_ligand_id(pose, jump_id);
224 
225  // Scoring function already set up by superclass
226  // BUG: currently need to score pose explicitly to get everything initialized properly
227  (*scorefxn_)( pose );
228 
229  if( protocol_ != "unbound" )random_conformer(pose); // now only "pose" parameter is needed, actually
230 
232 
233  // Includes initial random perturbation (-dock_pert, -randomize2, etc)
234  if( protocol_ != "unbound" ) optimize_orientation3(pose, jump_id, lig_id);
235 
236  // Safer to add these after the initial rotamer juggling, especially in grid mode.
237  // However, it means there should be no minimization done before this point!!
238  // Have to do this very early, before MC or anyone else makes copies!
239  // Only turn these on if needed? used to interfere with ligand packing (e.g. proton rotamers)
241  if( minimize_ligand_ ) {
242  restrain_ligand_chis( pose);
243  }
244 
245  // Make sure ligand doesn't start out in outer space.
246  // We DO NOT start with a slide apart step -- for enclosed binding pockets,
247  // it's seriously unlikely you'll ever find it again, especially if there are small bumps!
248  if( protocol_ != "unbound" ) {
249  protocols::docking::FaDockingSlideIntoContact slideTogether(jump_id);
250  slideTogether.apply( pose );
251  }
252 
253  // Modifies pose (foldtree) and jump_id!
254  if( minimize_backbone_ ) {
256  }
257  // Put the move-map here so the interface matches up with the backbone constraints!
259 
260  // Only want to do this once the ligand is in its "final" starting place.
261  core::scoring::constraints::ConstraintOP ligand_tether( NULL );
262  if( protocol_ != "unbound" ){
263  if( tether_ligand_ ) ligand_tether = restrain_ligand_nbr_atom(pose, lig_id, ligand_tether_stddev_Ang_);
264  }
265 
266  // Create a MonteCarlo object
267  // Want to do this after perturb so we don't reset to pre-perturb state
268  MonteCarloOP monteCarlo = new MonteCarlo(pose, *scorefxn_, 2.0 /* temperature, from RosettaLigand paper */);
269 
270  if(protocol_ == "meiler2006") classic_protocol(pose, jump_id, scorefxn_, monteCarlo, 50, 8); // Meiler and Baker 2006
271  // pack - rottrials - rottrials - rottrials - pack
272  else if(protocol_ == "abbreviated") classic_protocol(pose, jump_id, scorefxn_, monteCarlo, 5, 4); // Davis ca. 2007
273  // pack - RT - RT - pack - RT - RT (avoids ending on pack to avoid noise?)
274  else if(protocol_ == "abbrev2") classic_protocol(pose, jump_id, scorefxn_, monteCarlo, 6, 3); // Davis ca. April 2008
275  else if(protocol_ == "shear_min") shear_min_protocol(pose, jump_id, scorefxn_, monteCarlo, 20);
276  else if(protocol_ == "min_only" || protocol_ == "unbound") {} // no docking steps, just minimize (mostly for debugging/testing)
277  else utility_exit_with_message("Unknown protocol '"+protocol_+"'");
278 
279  // Remove the ligand tether. Could wait until after the final minimization,
280  // but have to do it *some* time, or it will interfere with value of interface_delta.
281  if( tether_ligand_ ) pose.remove_constraint( ligand_tether );
282 
283  // keep the best structure we found, not the current one
284  monteCarlo->show_scores();
285  monteCarlo->recover_low(pose);
286 
287  // Run most of search with soft-rep, but do final minimization and scoring with hard-rep.
289 
290 
291  //movemap->show(TR, pose.n_residue());
292  // Do the final, "tight" minimization of all DOFs
293  // Set up move map for minimizing.
294  // Have to do this after initial perturb so we get the "right" interface defn.
295  // Putting it here, we will get a slightly different interface than is used during classic_protocol() ...
296  protocols::simple_moves::MinMoverOP dfpMinTightTol = new protocols::simple_moves::MinMover( movemap, scorefxn_, "dfpmin_armijo_nonmonotone_atol", 0.02, true /*use_nblist*/ );
297  dfpMinTightTol->min_options()->nblist_auto_update(true);
298  dfpMinTightTol->apply(pose);
299 
300  // Fast full-atom relax to eliminate backbone clashes
301  // This moves the whole protein around, a lot
302  //{
303  // protocols::relax::FastRelax relax( scorefxn_ );
304  // core::pack::task::PackerTaskOP relax_task;
305  // relax_task = pack::task::TaskFactory::create_packer_task( pose );
306  // //relax_task->initialize_from_command_line().restrict_to_repacking();
307  // relax_task->restrict_to_repacking(); // -ex1, -ex2, etc make this take too long for whole protein!
308  // relax_task->or_include_current( true );
309  // protocols::simple_moves::PackRotamersMoverOP relax_full_repack = new protocols::simple_moves::PackRotamersMover( scorefxn_, relax_task );
310  // relax.set_full_repack(relax_full_repack); // ligand torsions are still constrained during this...
311  // relax.apply( pose );
312  //}
313 
314  // If we change the fold tree during the course of this run,
315  // we should restore it afterwards for scoring and output!
316  pose.fold_tree( fold_tree_copy );
317 
318  basic::prof_show();
319 }
320 
323  return "LigandDockProtocol";
324 }
325 
326 
327 void
329  core::pose::Pose & pose,
330  int jump_id,
333  core::Size num_cycles,
334  core::Size repack_every_Nth
335 ) const
336 {
337  using namespace protocols::moves;
339  runtime_assert(repack_every_Nth >= 2);
340 
341  // Set up move map for minimizing.
342  // Have to do this after initial perturb so we get the "right" interface defn.
343  //core::kinematics::MoveMapOP movemap = make_movemap(pose, jump_id, sc_interface_padding_, minimize_all_rsds_, minimize_backbone_, minimize_ligand_);
345 
346  // Set up the packer task
349 
350  // Rigid body exploration
351  MoverOP simple_rigbod = new rigid::RigidBodyPerturbMover( jump_id, numeric::conversions::degrees(0.05), 0.1);
352 
353  for( core::Size cycle = 1; cycle <= num_cycles; ++cycle ) {
354  // RotamerTrialsMover actually asks for a non-const OP to scorefxn, sadly.
355  // this problem did not manifest until I fixed the ScoreFunctionCOP definition in ScoreFunction.fwd.hh
356  MoverOP pack_mover = ( (cycle % repack_every_Nth == 1) ? (Mover *) new protocols::simple_moves::PackRotamersMover(scorefxn, repack_task) : (Mover *) new protocols::simple_moves::RotamerTrialsMover(scorefxn, *rottrials_task) );
357  // Wrap it in something to disable the torsion constraints before packing!
359 
360  //MoverOP dockmcm_mover = make_dockmcm_mover(pose, jump_id, pack_mover, simple_rigbod, movemap, scorefxn, monteCarlo);
361  //dockmcm_mover->apply(pose);
362  {
363  protocols::simple_moves::MinMoverOP min_mover = new protocols::simple_moves::MinMover( movemap, scorefxn, "dfpmin_armijo_nonmonotone_atol", 1.0, true /*use_nblist*/ );
364  min_mover->min_options()->nblist_auto_update(true); // does this cost us lots of time in practice?
365 
366  core::Real const score1 = (*scorefxn)( pose );
367  simple_rigbod->apply(pose);
368 
369  pack_mover->apply(pose);
370 
371  core::Real const score2 = (*scorefxn)( pose );
372  if(score2 - score1 < 15.0) {
373  //std::cout << "YES, minimizing" << std::endl;
374  min_mover->apply(pose);
375  } else {
376  //std::cout << "NO, not minimizing" << std::endl;
377  }
378  (*scorefxn)( pose ); // no effect at all
379 
380  monteCarlo->boltzmann( pose );
381 
382  if( ligand_shear_moves_ ) shear_min_protocol(pose, jump_id, scorefxn, monteCarlo, ligand_shear_moves_);
383  }
384 
385  // We always want the option (after the initial unbiased pack)
386  // of sticking with our current nicely minimized conformation.
387  repack_task->or_include_current(true);
388  rottrials_task->or_include_current(true); // no effect -- rottrials always includes current.
389  }
390 }
391 
392 
393 void
395  core::pose::Pose & pose,
396  int jump_id,
399  core::Size num_cycles
400 ) const
401 {
402  using namespace protocols::moves;
404 
405  core::Size const lig_id = get_ligand_id(pose, jump_id);
406  core::conformation::Residue const & lig_rsd = pose.residue(lig_id);
407  if(lig_rsd.nchi() == 0) {
408  TR << "Warning! Shear minimization protocol attempted on ligand without movable chis. (Lig id " << lig_id << ")" << std::endl;
409  // Protocol is effectively a no-op for rigid ligands.
410  return;
411  }
412 
413  // Set up move map for minimizing.
414  // Have to do this after initial perturb so we get the "right" interface defn.
415  core::kinematics::MoveMapOP movemap = make_movemap(pose, jump_id, sc_interface_padding_, minimize_all_rsds_, /*minimize_backbone_=*/ false, minimize_ligand_, minimize_water_);
416  //// Really simple movemap -- just ligand DOFs
417  //// This works very poorly!
418  //core::kinematics::MoveMapOP movemap = new core::kinematics::MoveMap();
419  //movemap->set_jump(jump_id, true);
420  //movemap->set_chi(lig_id, true);
421 
422  //monteCarlo->reset_counters();
423  for( core::Size cycle = 1; cycle <= num_cycles; ++cycle ) {
424  //TR << "shear_min_protocol(), cycle " << cycle << std::endl;
425  protocols::simple_moves::MinMoverOP min_mover = new protocols::simple_moves::MinMover( movemap, scorefxn, "dfpmin_armijo_nonmonotone_atol", 1.0, true /*use_nblist*/ );
426  min_mover->min_options()->nblist_auto_update(true); // does this cost us lots of time in practice?
427  //core::Real const score1 = (*scorefxn)( pose );
428 
429  // First, dumb version: compensating changes in two dihedrals, but without checking that they're 1 bond apart!
430  // For one test case (1GWX), this is significantly better than dumb version 2, below.
431  core::Real const max_angle = 90.0; // 10 is too small, 180 is too large
432  core::Real const angle_delta = max_angle * 2. * (my_RG.uniform() - 0.5);
433  core::Size const chi1 = my_RG.random_range(1, lig_rsd.nchi());
434  core::Size const chi2 = my_RG.random_range(1, lig_rsd.nchi());
435  pose.set_chi(chi1, lig_id, lig_rsd.chi(chi1) + angle_delta);
436  pose.set_chi(chi2, lig_id, lig_rsd.chi(chi2) - angle_delta);
437 
438  //// Second dumb version: uncorrelated changes in 1-3 angles
439  //core::Real const max_angle = 90.0;
440  //core::Size const num_pert( my_RG.random_range(1, 3) );
441  //core::conformation::Residue const & lig_rsd = pose.residue(lig_id);
442  //for(core::Size i = 1; i <= num_pert; ++i) {
443  // core::Real const angle_delta = max_angle * 2. * (my_RG.uniform() - 0.5);
444  // core::Size const chi1 = my_RG.random_range(1, lig_rsd.nchi());
445  // pose.set_chi(chi1, lig_id, lig_rsd.chi(chi1) + angle_delta);
446  //}
447 
448  //core::Real const score2 = (*scorefxn)( pose );
449  //if(score2 - score1 < 15.0) {
450  //std::cout << "YES, minimizing" << std::endl;
451  min_mover->apply(pose);
452  //} else {
453  // //std::cout << "NO, not minimizing" << std::endl;
454  //}
455  (*scorefxn)( pose ); // no effect at all
456 
457  monteCarlo->boltzmann( pose );
458  }
459  //monteCarlo->show_state();
460 }
461 
462 
463 /// @brief Replace current ligand(s) with conformers picked randomly from the library.
464 void
466  core::pose::Pose & pose
467 ) const
468 {
469  using namespace basic::options;
470  using namespace protocols::moves;
472 
473  if( option[ OptionKeys::docking::ligand::random_conformer ]() ) {
474  for(core::Size i = 1; i <= pose.total_residue(); ++i ) {
475  if( pose.residue(i).is_polymer() ) continue;
476  //(*scorefxn_)( pose ); scorefxn_->accumulate_residue_total_energies( pose ); std::cout << "Constraints before: " << pose.energies().total_energies()[ core::scoring::dihedral_constraint ] << std::endl;
479  utm->apply(pose);
480  //(*scorefxn_)( pose ); scorefxn_->accumulate_residue_total_energies( pose ); std::cout << "Constraints after: " << pose.energies().total_energies()[ core::scoring::dihedral_constraint ] << std::endl;
481  }
482  }
483 
484  // Rotamer trials superimposes around the "nbr atom", which can shift the
485  // computed centroid by significant distances.
486  // Thus, after substituting, we re-center the new conformer.
487  // (Re-centering now occurs in main protocol.)
488 }
489 
490 
491 /// @brief Repeatedly randomize ligand orientation in a given location
492 /// to find where *some* ligand rotamer has minimal clashes with the backbone.
493 void
495  core::pose::Pose & pose,
496  int jump_id,
497  core::Size lig_id
498 )
499 {
500  //clock_t start_time = clock();
501  using namespace protocols::moves;
502  using namespace core::scoring;
503  using namespace core::pack::task;
504  using namespace basic::options;
505  using utility::vector1;
506 
507  // Takes about 3.5 sec to make grid for 250 residue protein,
508  // compared to 15 sec for 1000 cycles with large ligand.
509  // Given overall time cost of docking protocol and difficulty of telling when
510  // we've moved to a new starting (input) structure, it's not worth caching the grid.
511 
512  TR << "Making ligand grid ..." << std::endl;
513  //clock_t start_time = clock();
515  //clock_t end_time = clock();
516  //TR << "Elapsed time: " << double(end_time - start_time) / CLOCKS_PER_SEC << " seconds" << std::endl;
517 
518  int atr(0), rep(0);
519  grid_score_atr_rep(*grid, pose.residue(lig_id), atr, rep);
520  TR << "Input score atr = " << atr << " ; rep = " << rep << " ; ha = " << pose.residue(lig_id).nheavyatoms() << std::endl;
521 
522  // Kinemage output for debugging -- much less useful than ED map format
523  if( option[ OptionKeys::docking::ligand::grid::grid_kin ].user() ) {
524  std::ofstream of( option[ OptionKeys::docking::ligand::grid::grid_kin ]().name().c_str() );
525  of << "@kinemage\n";
526  of << "@group {grid}\n";
527  of << "@dotlist {atr} color= greentint\n";
528  grid_to_kin<int>(of, *grid, -1, -1, 2);
529  of << "@dotlist {rep} color= pinktint off\n";
530  grid_to_kin<int>(of, *grid, 1, 1, 2);
531  of.close();
532  }
533 
534  // OMap output for debugging
535  if( option[ OptionKeys::docking::ligand::grid::grid_map ].user() ) {
536  grid->write_to_BRIX( option[ OptionKeys::docking::ligand::grid::grid_map ]().name() );
537  }
538 
539  MoverOP initialPerturb = new protocols::docking::DockingInitialPerturbation(jump_id, false /*don't slide*/);
540  // Make sure the initial perturb lands our nbr_atom in an empty space.
541  {
542  core::pose::Pose const orig_pose( pose );
543  // With no initial perturbation, this can get trapped in an endless loop otherwise!
544  //while(true) {
545  for(Size cnt = 0; cnt < 50; ++cnt) {
546  initialPerturb->apply(pose);
547  core::Vector c = pose.residue(lig_id).nbr_atom_xyz();
548  // did our nbr_atom land in an empty space on the grid?
549  // Don't want to insist the nbr_atom is in the attractive region, because it may not be!
550  if( grid->is_in_grid( c.x(), c.y(), c.z() ) && grid->getValue( c.x(), c.y(), c.z() ) <= 0 ) {
551  TR << "Accepting ligand position with nbr_atom at " << c << std::endl;
552  break;
553  }
554  TR << "Rejecting ligand position with nbr_atom at " << c << std::endl;
555  pose = orig_pose; // reset and try again
556  }
557  }
558 
559  if( ! option[ OptionKeys::docking::ligand::improve_orientation ].active() ) {
560  return;
561  }
562 
563  int const num_cycles = std::max(0, option[ OptionKeys::docking::ligand::improve_orientation ]());
564  runtime_assert( num_cycles >= 0 );
565  TR << "Doing " << num_cycles << " trials of improvement for ligand orientation..." << std::endl;
566 
567  // Want to keep the same center of rotation even after rotamer trials,
568  // so the ligand can't "walk" away from the protein!
569  // RigidBodyRandomizeMover can't do that, so we didn't use it here.
570  //core::Vector dummy_up, rot_center;
571  //protocols::geometry::centroids_by_jump(pose, jump_id, dummy_up, rot_center);
572  // Better to rotate around the nbr_atom, because that's where rotamer trials are centered.
573  // Yes, I know this code will ONLY work for single residue ligands. Tough.
574  core::Vector const rot_center = pose.residue(lig_id).nbr_atom_xyz();
575 
576  // Can't refer to starting position (e.g. in case we're not using -randomize2, makes it too easy)
577  // As long as we're doing at least one cycle, these will be overwritten by the first random.
578  // These are kept here so we get the expected behavior if the user asks for 0 cycles.
579  // Scale back the "perfect" values a little to avoid over-convergence.
580  int const perfect_rep = 0, perfect_atr = -(int)(0.85 * pose.residue(lig_id).nheavyatoms());
581  int best_rep(0), best_atr(0); // dummy initial values for compiler
582  grid_score_atr_rep(*grid, pose.residue(lig_id), best_atr, best_rep);
583  TR << "Starting orientation energy atr = " << best_atr << " ; rep = " << best_rep << std::endl;
584  core::kinematics::Jump best_jump = pose.jump( jump_id );
585 
586  // Many poses will fall into broad energy wells, and a few will fall into narrow ones.
587  // By collecting "perfect" poses and enforcing a minimum level of diversity,
588  // we should be able to pick from them randomly and enrich for rare poses.
589  // These next two parameters are wild-ass heuristic guesses that seem OK for the Meiler x-dock set.
590  core::Real const diverse_rms = 0.65 * std::sqrt( (double)pose.residue_type(lig_id).nheavyatoms() );
591  // Setting this too low leads to little enrichment in rare poses,
592  // but setting it too high wastes a lot of time in rms calculation:
593  core::Size const max_diversity = 5 * (pose.residue_type(lig_id).nchi()+1);
594  vector1< core::kinematics::Jump > perfect_jumps;
596  core::Size perfect_count(0), diverse_count(0);
597 
598  // If we have constraints, we may want to use them as a filter.
599  // Since we're not storing poses, though, we have to score as we go.
600  bool const score_csts = option[ OptionKeys::enzdes::cstfile ].user();
601  core::scoring::ScoreFunction cst_scorefxn;
603  cst_scorefxn.set_weight(core::scoring::atom_pair_constraint, 1.0 );
604  cst_scorefxn.set_weight(core::scoring::angle_constraint, 1.0 );
605  cst_scorefxn.set_weight(core::scoring::dihedral_constraint, 1.0 );
606  vector1< core::Real > perfect_cstscores;
607 
608  for(int i = 0; i < num_cycles; ++i) {
609  //randomize2->apply(pose);
610  // Randomize orientation: copied from RigidBodyRandomizeMover.apply()
611  core::kinematics::Jump flexible_jump = pose.jump( jump_id );
612  core::kinematics::Stub upstream_stub = pose.conformation().upstream_jump_stub( jump_id );
613  core::kinematics::Stub downstream_stub = pose.conformation().downstream_jump_stub( jump_id );
614  // comments for set_rb_center() explain which stub to use when!
615  flexible_jump.set_rb_center( 1 /* n2c -- isn't defd in any .hh file :( */, downstream_stub, rot_center );
616  flexible_jump.rotation_by_matrix( upstream_stub, rot_center, protocols::geometry::random_reorientation_matrix() );
617  pose.set_jump_now( jump_id, flexible_jump );
618 
619  grid_rotamer_trials_atr_rep(*grid, pose, lig_id);
620  int curr_rep(0), curr_atr(0); // dummy initial values for compiler
621  grid_score_atr_rep(*grid, pose.residue(lig_id), curr_atr, curr_rep);
622  // Always accept first try as best so far ... sort of a do-while loop.
623  if( i == 0 || curr_rep < best_rep || (curr_rep == best_rep && curr_atr < best_atr) ) {
624  best_rep = curr_rep;
625  best_atr = curr_atr;
626  best_jump = pose.jump( jump_id );
627  //if(best_rep <= perfect_rep && best_atr <= perfect_atr) {
628  // TR << "Aborting after " << i+1 << " cycles because score is perfect!" << std::endl;
629  // break; // can't do any better than this!
630  //}
631  }
632  // Accumulate poses with a certain minimum level of diversity
633  if(curr_rep <= perfect_rep && curr_atr <= perfect_atr) {
634  perfect_count += 1;
635  core::Real min_rms = 9999;
636  for(Size j = 1, j_end = perfect_rsds.size(); j <= j_end; ++j) {
637  core::Real rms = automorphic_rmsd(pose.residue(lig_id), *perfect_rsds[j], false /*don't superimpose*/);
638  if( rms < min_rms ) min_rms = rms;
639  }
640  if( min_rms >= diverse_rms ) {
641  diverse_count += 1;
642  perfect_rsds.push_back( pose.residue(lig_id).clone() );
643  perfect_jumps.push_back( pose.jump( jump_id ) );
644  perfect_cstscores.push_back( cst_scorefxn(pose) );
645  if( diverse_count >= max_diversity ) {
646  TR << "Aborting after " << i+1 << " cycles with " << diverse_count << " diverse 'perfect' poses" << std::endl;
647  break; // can't do any better than this!
648  }
649  }
650  }
651  TR.Debug << " Randomize energy atr = " << curr_atr << " ; rep = " << curr_rep << std::endl;
652  TR.Debug << " NBR_ATOM at " << pose.residue(lig_id).nbr_atom_xyz() << std::endl;
653  }
654  TR << "Best random orientation energy atr = " << best_atr << " ; rep = " << best_rep << std::endl;
655  TR << "Found " << perfect_count << " 'perfect' poses, kept " << diverse_count << " with rms >= " << diverse_rms << std::endl;
656 
657  if( !perfect_rsds.empty() ) {
658  // Found multiple diverse and high-quality poses. Choose one at random.
659  core::Size which_perfect = (core::Size) numeric::random::RG.random_range(1, perfect_rsds.size());
660  // If we have constraints, take the perfect pose with the best constraint score
661  if( score_csts ) {
662  core::Real min_cstscore = 1e99;
663  for(core::Size j = 1, j_end = perfect_rsds.size(); j <= j_end; ++j) {
664  if( perfect_cstscores[j] < min_cstscore ) {
665  min_cstscore = perfect_cstscores[j];
666  which_perfect = j;
667  //std::cout << "*** choosing perfect pose " << j << " with cstscore = " << min_cstscore << std::endl;
668  }
669  }
670  }
671  pose.set_jump( jump_id, perfect_jumps[which_perfect] );
672  // Just copy over XYZ coordinates
673  for(core::Size j = 1, j_end = pose.residue_type(lig_id).natoms(); j <= j_end; ++j) { // no refolds required
674  core::id::AtomID atom_id(j, lig_id); // atom, residue
675  pose.set_xyz(atom_id, perfect_rsds[which_perfect]->xyz(j));
676  }
677  } else {
678  // Found only one, half-decent pose
679  // recover best jump
680  pose.set_jump( jump_id, best_jump );
681  // recover best ligand pose
682  // Not *guaranteed* to be the same one if multiple confs are iso-energetic, actually.
683  // Not that that matters for our purposes.
684  grid_rotamer_trials_atr_rep(*grid, pose, lig_id);
685  }
686 
687  //clock_t end_time = clock();
688  //TR << "Elapsed time: " << double(end_time - start_time) / CLOCKS_PER_SEC << " seconds" << std::endl;
689 }
690 
691 
692 /// @brief Build Mover for Monte Carlo Minimization protocol
695  core::pose::Pose const & /*pose*/,
696  int /*jump_id*/,
697  protocols::moves::MoverOP repack_mover,
698  protocols::moves::MoverOP rigbod_mover,
699  core::kinematics::MoveMapOP movemap, //< would be COP but MinMover wants OP
702 ) const
703 {
704  using namespace protocols::moves;
705 
706  protocols::simple_moves::MinMoverOP min_mover = new protocols::simple_moves::MinMover( movemap, scorefxn, "dfpmin_armijo_nonmonotone_atol", 1.0, true /*use_nblist*/ );
707  min_mover->min_options()->nblist_auto_update(true); // does this cost us lots of time in practice?
708 
709  TrialMoverOP mctrial = new TrialMover(
710  new JumpOutMover(
711  new SequenceMover(
712  rigbod_mover,
713  repack_mover
714  ),
715  min_mover,
716  scorefxn,
717  15.0 // energy units, taken from Rosetta++ docking_minimize.cc
718  ),
719  monteCarlo
720  );
721  //mctrial->set_keep_stats(false); // big time sink for MC
722  mctrial->keep_stats_type( no_stats );
723  return mctrial;
724 }
725 
726 
727 /// @brief Helper function to tame the PoseMetricCalculator madness.
729 {
730  using namespace protocols::toolbox::pose_metric_calculators;
731  // Despite the name, it's counting H-bonders, not any old polars.
732  BuriedUnsatisfiedPolarsCalculator calc("default", "default");
733  basic::MetricValue< core::Size > val;
734  calc.get("all_bur_unsat_polars", val, pose);
735  return val.value();
736 }
737 
738 
739 /// Because inquiring minds want to know: what Hbonds are precluded by this docking?
740 void print_buried_unsat_Hbonds(core::pose::Pose const & bound, core::pose::Pose const & unbound)
741 {
742  using namespace protocols::toolbox::pose_metric_calculators;
743  using core::id::AtomID_Map;
744  // Despite the name, it's counting H-bonders, not any old polars.
745  BuriedUnsatisfiedPolarsCalculator calc_bound("default", "default"), calc_unbound("default", "default");
746  basic::MetricValue< AtomID_Map< bool > > map_bound, map_unbound;
747  calc_bound.get("atom_bur_unsat", map_bound, bound);
748  calc_unbound.get("atom_bur_unsat", map_unbound, unbound);
749  // This is ridiculously inefficient but I don't see a better way...
750  for(core::Size r = 1; r <= map_bound.value().n_residue(); ++r) {
751  for(core::Size a = 1; a <= map_bound.value().n_atom(r); ++a) {
752  if( map_bound.value()(r,a) && !map_unbound.value()(r,a) ) {
753  TR << "Unsatisfied interface H-bond: " << bound.residue_type(r).name3() << " " << r << " " << bound.residue_type(r).atom_name(a) << std::endl;
754  }
755  }
756  }
757 }
758 
759 
760 /// @brief Scores to be output that aren't normal scorefunction terms.
761 void
763  core::pose::Pose const & before,
764  core::pose::Pose const & after,
766  std::map< std::string, core::Real > & scores, //< appended to for output
768 ) const
769 {
770  using namespace core::scoring;
771  Size const jump_id = get_ligand_jump_id(after);
772 
773  // Figure out energy across the interface.
774  // A truer "binding energy" would allow the components to relax (repack)
775  // once separated, but Chu's JMB paper found this doesn't really help,
776  // at least for protein-protein docking.
777  // Also, it's very slow, requiring 10+ independent repacks.
778  core::pose::PoseOP after_unbound = new core::pose::Pose( after );
779  // If constraints aren't removed, pulling the components apart gives big penalties.
780  if( constraint_io ) constraint_io->remove_constraints_from_pose(*after_unbound, /*keep_covalent=*/ false, /*fail_on_constraints_missing=*/ true);
781 
782  // A very hacky way of guessing whether the components are touching:
783  // if pushed together by 1A, does fa_rep change at all?
784  // (The docking rb_* score terms aren't implemented as of this writing.)
785  core::Real const together_score = (*scorefxn)( *after_unbound );
786  EnergyMap const together_energies = after_unbound->energies().total_energies();
787  core::Real const initial_fa_rep = after_unbound->energies().total_energies()[ fa_rep ];
788  protocols::rigid::RigidBodyTransMover trans_mover( *after_unbound, jump_id );
789  trans_mover.trans_axis( trans_mover.trans_axis().negate() ); // now move together
790  trans_mover.step_size(1);
791  trans_mover.apply( *after_unbound );
792  (*scorefxn)( *after_unbound );
793  core::Real const push_together_fa_rep = after_unbound->energies().total_energies()[ fa_rep ];
794  bool const are_touching = (std::abs(initial_fa_rep - push_together_fa_rep) > 1e-4);
795  scores["ligand_is_touching"] = are_touching;
796 
797  // Now pull apart by 500 A to determine the reference E for calculating interface E.
798  trans_mover.trans_axis( trans_mover.trans_axis().negate() ); // now move apart
799  trans_mover.step_size(500); // make sure they're fully separated!
800  trans_mover.apply( *after_unbound );
801  core::Real const separated_score = (*scorefxn)( *after_unbound );
802  EnergyMap const separated_energies = after_unbound->energies().total_energies();
803  scores["interface_delta"] = together_score - separated_score;
804 
805  // Interface delta, broken down by component
806  for(int i = 1; i <= n_score_types; ++i) {
807  ScoreType ii = ScoreType(i);
808  if ( !scorefxn->has_nonzero_weight(ii) ) continue;
809  scores[ "if_"+name_from_score_type(ii) ] = ( scorefxn->get_weight(ii) * (together_energies[ii] - separated_energies[ii]) );
810  }
811 
812  // Fun stuff from the pose metrics calculators:
813  core::Real const sasa_radius = 1.4;
814  // Explicit cast to Real, as you can get negative numbers when the ligand is making buried hydrogen bonds to the protein
815  scores["if_buried_unsat_hbonds"] = core::Real(count_buried_unsat_Hbonds(after)) - core::Real(count_buried_unsat_Hbonds(*after_unbound));
816  scores["if_buried_sasa"] = -( core::scoring::calc_total_sasa(after, sasa_radius) - core::scoring::calc_total_sasa(*after_unbound, sasa_radius) );
817  print_buried_unsat_Hbonds(after, *after_unbound);
818 
819  // Another interesting metric -- how far does the ligand centroid move?
820  // Large values indicate we're outside of the intended binding site.
821  core::Vector upstream_dummy, downstream_before, downstream_after;
822  protocols::geometry::centroids_by_jump(before, jump_id, upstream_dummy, downstream_before);
823  protocols::geometry::centroids_by_jump(after, jump_id, upstream_dummy, downstream_after);
824  if( start_from_pts_.empty() ) {
825  // Compare to starting position or...
826  core::Real const ligand_centroid_travel = downstream_before.distance( downstream_after );
827  scores["ligand_centroid_travel"] = ligand_centroid_travel;
828  } else {
829  // Compare to *nearest* -start_from point
830  core::Real min_travel = 1e99;
831  for(Size ii = 1; ii <= start_from_pts_.size(); ++ii) {
832  core::Real travel = start_from_pts_[ii].distance( downstream_after );
833  min_travel = std::min( min_travel, travel );
834  }
835  scores["ligand_centroid_travel"] = min_travel;
836  }
837 
838  // Calculate radius of gyration for downstream non-H atoms
839  // Ligands tend to bind in outstretched conformations...
840  core::Real lig_rg = 0;
841  int lig_rg_natoms = 0;
842  FArray1D_bool is_upstream ( before.total_residue(), false );
843  before.fold_tree().partition_by_jump( jump_id, is_upstream );
844  for(core::Size i = 1, i_end = before.total_residue(); i <= i_end; ++i) {
845  if( is_upstream(i) ) continue; // only downstream residues
846  core::conformation::Residue const & rsd = before.residue(i);
847  for(core::Size j = 1, j_end = rsd.nheavyatoms(); j <= j_end; ++j) {
848  lig_rg += downstream_before.distance_squared( rsd.xyz(j) );
849  lig_rg_natoms += 1;
850  }
851  }
852  lig_rg = std::sqrt( lig_rg / lig_rg_natoms );
853  scores["ligand_radius_of_gyration"] = lig_rg;
854 
855  // These RMSD values don't account for symmetry (e.g. phenyl rings)
856  //scores["ligand_rms_no_super"] = rmsd_no_super(before, after, is_ligand_heavyatom);
857  //scores["ligand_rms_with_super"] = rmsd_with_super(before, after, is_ligand_heavyatom);
858 
859  core::Size const lig_id = get_ligand_id(before, jump_id);
860  runtime_assert( !before.residue(lig_id).is_polymer() );
861  scores["ligand_auto_rms_with_super"] = automorphic_rmsd(before.residue(lig_id), after.residue(lig_id), true /*superimpose*/);
862  scores["ligand_auto_rms_no_super"] = automorphic_rmsd(before.residue(lig_id), after.residue(lig_id), false /*don't superimpose*/);
863 
864  // These might be interesting for cases where we get part of the ligand
865  // in the right place, but not all of it.
866  utility::vector1< core::Real > cuts = utility::tools::make_vector1(0.5, 1.0, 2.0);
868  protocols::ligand_docking::frac_atoms_within(before.residue(lig_id), after.residue(lig_id), cuts, fracs);
869  scores["frac_atoms_within_0.5"] = fracs[1];
870  scores["frac_atoms_within_1.0"] = fracs[2];
871  scores["frac_atoms_within_2.0"] = fracs[3];
872 
873  // This might be useful in understanding entropic effects:
874  scores["ligand_num_chi"] = before.residue(lig_id).nchi();
875 }
876 
877 void
879  core::pose::Pose & pose
880 ){
881  using basic::options::option;
882  using namespace basic::options;
883 
884  if( option[ OptionKeys::docking::ligand::use_ambig_constraints ] ) {
886  } else {
887  for(core::Size i = 1; i <= pose.total_residue(); ++i ) {
888  if( pose.residue(i).is_polymer() ) continue;
890  }
891  }
892 }
893 
894 
895 
896 } // namespace ligand_docking
897 } // namespace protocols