Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
LoopMover_KIC.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/loops/LoopMover_Perturb_KIC.cc
11 /// @brief kinematic loop closure main protocols
12 /// @author Chu Wang
13 /// @author Daniel J. Mandell
14 /// @author Mike Tyka
15 /// @author James Thompson
16 /// @author Roland A. Pache
17 /// @author Amelie Stein, amelie.stein@ucsf.edu, Oct 2012 -- next-generation KIC
18 
19 
22 
23 //// Unit Headers
24 #include <protocols/loops/util.hh>
26 #include <protocols/loops/Loop.hh>
27 #include <protocols/loops/Loops.hh>
32 
33 //
34 //// Rosetta Headers
36 
37 #include <core/id/TorsionID.hh>
42 #include <basic/options/option.hh>
43 #include <core/pose/Pose.hh>
44 #include <core/scoring/Energies.hh>
46 
48 // AUTO-REMOVED #include <core/conformation/symmetry/util.hh>
49 
51 
52 // AUTO-REMOVED #include <core/pack/task/TaskFactory.hh>
53 // AUTO-REMOVED #include <core/pack/task/PackerTask.hh>
54 // AUTO-REMOVED #include <core/pack/task/operation/TaskOperations.hh>
55 // AUTO-REMOVED #include <core/pack/rotamer_trials.hh>
56 // AUTO-REMOVED #include <core/pack/pack_rotamers.hh>
57 
58 #include <basic/Tracer.hh>
59 
60 //Utility Headers
61 #include <numeric/random/random.hh>
62 
63 // C++ Headers
64 #include <iostream>
65 #include <map>
66 #include <string>
67 
68 // option key includes
69 
70 #include <basic/options/keys/out.OptionKeys.gen.hh>
71 #include <basic/options/keys/loops.OptionKeys.gen.hh>
72 // AUTO-REMOVED #include <basic/options/keys/packing.OptionKeys.gen.hh>
73 #include <basic/options/keys/run.OptionKeys.gen.hh>
74 
75 #include <core/pose/util.hh>
77 #include <utility/vector0.hh>
78 #include <utility/vector1.hh>
79 #include <ObjexxFCL/format.hh>
80 #include <fstream>
81 
82 //Auto Headers
83 
84 
85 //Auto using namespaces
86 namespace ObjexxFCL { } using namespace ObjexxFCL; // AUTO USING NS
87 namespace ObjexxFCL { namespace fmt { } } using namespace ObjexxFCL::fmt; // AUTO USING NS
88 //Auto using namespaces end
89 
90 
91 namespace protocols {
92 namespace loops {
93 namespace loop_mover {
94 namespace perturb {
95 
96 ///////////////////////////////////////////////////////////////////////////////
97 using namespace core;
98 
99 static numeric::random::RandomGenerator RG(42444);
100 static basic::Tracer TR("protocols.loops.loop_mover.perturb.LoopMover_Perturb_KIC");
101 
102 LoopMover_Perturb_KIC::LoopMover_Perturb_KIC() :
104 {
107 
108  protocols::moves::Mover::type("LoopMover_Perturb_KIC");
110 }
111 
112 
115 ) : IndependentLoopMover( loops_in )
116 {
119 
120  protocols::moves::Mover::type("LoopMover_Perturb_KIC");
122 
123 }
124 
126  protocols::loops::LoopsOP loops_in,
128 ) : IndependentLoopMover( loops_in )
129 {
130  if( scorefxn ){
131  set_scorefxn( scorefxn );
132  }else{
135  }
136  protocols::moves::Mover::type("LoopMover_Perturb_KIC");
138 }
139 
140 //destructor
142 
143 //clone
145  return new LoopMover_Perturb_KIC(*this);
146 }
147 
149 {
150  if ( basic::options::option[ basic::options::OptionKeys::loops::strict_loops ].user() ) {
151  set_strict_loops( basic::options::option[ basic::options::OptionKeys::loops::strict_loops ]() );
152  }
153  else set_strict_loops(true); // obey loop definitions in kinematic mode
154  max_seglen_ = basic::options::option[basic::options::OptionKeys::loops::kic_max_seglen];
155  recover_low_ = ( ! basic::options::option[basic::options::OptionKeys::loops::kic_recover_last] );
156  max_kic_build_attempts_ = basic::options::option[basic::options::OptionKeys::loops::max_kic_build_attempts];
157  remodel_kic_attempts_ = basic::options::option[basic::options::OptionKeys::loops::remodel_kic_attempts];
158 }
159 
161  core::pose::Pose & ,
162  Loop const &
163  )
164 {
165  // do nothing for now, overriding LoopMover::set_extended_torsions()
166 }
167 
168 
169 /// @detailed
170 /// Uses kinematic_mover to remodel a protein segment. If the 'extended' flag in the loop
171 /// definition for the segment is set to '1', will idealize all bond lengths, bond angles, and phi,
172 /// psi, and omega torsions before modeling. This stage is carried out entirely with a centroid
173 /// representation. Applies to only one loop, given as an argument.
175  core::pose::Pose & pose,
176  protocols::loops::Loop const & loop
177 ){
178  static int cur_struct=0; // for movie output
179  // Dont allow loops < 3 residues.
180  if( (loop.stop() - loop.start() < 2 )){
181  tr().Error << "[WARNING] KinematicMover cannot handle loops smaller than 3 residues. Doing nothing. " << std::endl;
183  }
184 
185  // Objects representing one loop
186  Loops one_loop_loops;
187  one_loop_loops.add_loop( loop );
188 
189  using namespace scoring;
190  using namespace optimization;
191  using namespace basic::options;
192 
193  //bool const verbose( true );
194  bool const local_debug( false );
195  bool const local_movie( false );
196 
197  core::pose::Pose native_pose;
198  if( get_native_pose() ){
199  native_pose = *get_native_pose();
200  }else{
201  native_pose = pose;
202  }
203 
204  Size const loop_begin( loop.start() ), loop_end( loop.stop() ), loop_cut( loop.cut() );
205  Size const loop_size( loop_end - loop_begin + 1 );
206  runtime_assert( loop.is_terminal( pose ) || pose.fold_tree().is_cutpoint( loop_cut ) );
207  std::ofstream loop_outfile; // for movie
208 
209  tr() << "perturb_one_loop_with_KIC: " << loop_begin << ' ' << loop_size << std::endl;
210 
211  // set cutpoint variant for chainbreak scoring.
214 
215  if (local_debug) {
216  std::ofstream out("score.tmp_input_cen");
217  out << "scoring before cen_perturb: " << ( *scorefxn() )(pose) << std::endl;
218  /// Now handled automatically. scorefxn_->accumulate_residue_total_energies(pose);
219  scorefxn()->show( out );
220  out << pose.energies().total_energies().weighted_string_of( scorefxn()->weights() ) << std::endl;
221  tr() << "before cen_perturb: "
222  << pose.energies().total_energies().weighted_string_of( scorefxn()->weights() ) << std::endl;
223  out << pose.energies();
224  }
225 
226  kinematics::MoveMap mm_one_loop;
227  utility::vector1<bool> allow_sc_move_one_loop( pose.total_residue(), false );
228  loops_set_move_map( one_loop_loops, allow_sc_move_one_loop, mm_one_loop);
229  if ( core::pose::symmetry::is_symmetric( pose ) ) {
231  }
232 
233 
234  // scheduler
235  bool const fast = option[OptionKeys::loops::fast];
236  int outer_cycles( 3 );
237  if ( option[ OptionKeys::loops::outer_cycles ].user() ) {
238  outer_cycles = option[ OptionKeys::loops::outer_cycles ]();
239  }
240  if ( option[ OptionKeys::run::test_cycles ]() ) {
241  outer_cycles = 3;
242  }
243  int inner_cycles( fast ? std::min( Size(250), loop_size*5 ) : std::min( Size(1000), loop_size*20 ) );
244  if ( option[ OptionKeys::loops::max_inner_cycles ].user() ) {
245  inner_cycles = option[ OptionKeys::loops::max_inner_cycles ]();
246  }
247  if ( option[ OptionKeys::run::test_cycles ]() ) {
248  inner_cycles = 3;
249  }
250 
251  // Monte Carlo vars
252  float const init_temp( option[ OptionKeys::loops::remodel_init_temp ]() );
253  float const final_temp( option[ OptionKeys::loops::remodel_final_temp ]() );
254  float const gamma = std::pow( (final_temp/init_temp), (1.0f/(outer_cycles*inner_cycles)) );
255  float temperature = init_temp;
256  if ( local_debug ) { // hacking
257  ( *scorefxn() )(pose);
258  tr() << "before mc ctor: "
259  << pose.energies().total_energies().weighted_string_of( scorefxn()->weights() ) << std::endl;
260  }
261 
262  // minimizer
263  AtomTreeMinimizerOP minimizer;
264  float const dummy_tol( 0.001 ); // linmin sets tol internally
265  bool const use_nblist( false ), deriv_check( false ); // true ); // false );
266  MinimizerOptions options( "linmin", dummy_tol, use_nblist, deriv_check);
267  if ( core::pose::symmetry::is_symmetric( pose ) ) {
269  } else {
271  }
272 
273  // show temps
274  tr() << "remodel init temp: " << init_temp << std::endl;
275  tr() << "remodel final temp: " << final_temp << std::endl;
276 
277  // perform the initial perturbation
278  // setup the kinematic mover
279 
281 
282  //tr() << "kinematic mover generated, now setting up perturber... " << std::endl;
283 
284  // AS: select from different perturbers implemented for NGK
285  // torsion-restricted sampling
286  if ( basic::options::option[ basic::options::OptionKeys::loops::restrict_kic_sampling_to_torsion_string ].user() || basic::options::option[ basic::options::OptionKeys::loops::derive_torsion_string_from_native_pose ]() ) {
287  std::string torsion_bins = basic::options::option[ basic::options::OptionKeys::loops::restrict_kic_sampling_to_torsion_string ]();
288 
289  // derive torsion string from native/input pose, if requested -- warning: this overwrites the externally provided one
290  if ( basic::options::option[ basic::options::OptionKeys::loops::derive_torsion_string_from_native_pose ]() )
291  torsion_bins = torsion_features_string( native_pose ); // does this work at this point in the code? The loop needs to be set up!
292 
293  // check if the user-provided string has the correct length
294  runtime_assert(torsion_bins.size() == loop_end - loop_begin + 1); // this is where torsion-restricted sampling with multiple loops currently fails -- however, proper access to the torsion bins in the perturber would also be implemented
295 
297  perturber->set_vary_ca_bond_angles( ! option[ OptionKeys::loops::fix_ca_bond_angles ]() ); // to make the code cleaner this should really be a generic function, even though some classes may not use it
298  myKinematicMover.set_perturber( perturber );
299  } else if ( basic::options::option[ basic::options::OptionKeys::loops::kic_rama2b ]() && basic::options::option[ basic::options::OptionKeys::loops::taboo_sampling ]() ) { // TabooSampling with rama2b (neighbor-dependent phi/psi lookup)
301  perturber =
303  perturber->set_vary_ca_bond_angles( ! option[ OptionKeys::loops::fix_ca_bond_angles ]() );
304  myKinematicMover.set_perturber( perturber );
305  } else if ( basic::options::option[ basic::options::OptionKeys::loops::taboo_sampling ] ) { // TabooSampling (std rama)
307 
308  perturber->set_vary_ca_bond_angles( ! option[ OptionKeys::loops::fix_ca_bond_angles ]() );
309  myKinematicMover.set_perturber( perturber );
310  } else if ( basic::options::option[ basic::options::OptionKeys::loops::kic_rama2b ]() ) { // rama2b
312  perturber =
314  perturber->set_vary_ca_bond_angles( ! option[ OptionKeys::loops::fix_ca_bond_angles ]() );
315  myKinematicMover.set_perturber( perturber );
316  } else { // default behavior [for now] -- std KIC
318  perturber =
320  perturber->set_vary_ca_bond_angles( ! option[ OptionKeys::loops::fix_ca_bond_angles ]() );
321  myKinematicMover.set_perturber( perturber );
322  }
323 
324  //tr() << "perturber set!" << std::endl;
325 
326  myKinematicMover.set_vary_bondangles( true );
327  //myKinematicMover.set_vary_bondangles( false ); // trying without varying angles
328 
329  myKinematicMover.set_sample_nonpivot_torsions( option[ OptionKeys::loops::nonpivot_torsion_sampling ]());
330  myKinematicMover.set_rama_check( true );
331 
332  myKinematicMover.set_loop_begin_and_end( loop_begin, loop_end ); // AS -- for restricted torsion bin sampling, the mover needs to know about the start of the defined loop, not just the segment that is sampled in a given move
333 
334 
335  // for Taboo Sampling we need to update the sequence here every time, in case it changes (e.g. when modeling multiple loops)
336  // this setup would also allow us to combine taboo sampling with other types of sampling, e.g. to increase diversity after several rounds of standard/random KIC sampling
338  loop_sequence.resize(0); // make sure it is empty
339  for (core::Size cur_res = loop_begin; cur_res <= loop_end; cur_res++) {
340  loop_sequence.push_back(pose.aa(cur_res));
341  }
342  myKinematicMover.update_sequence( loop_sequence ); // should only have an effect on the TabooSamplingKinematicPerturber
343 
344 
345 
346  Size kic_start, kic_middle, kic_end; // three pivot residues for kinematic loop closure
347  kic_start = loop_begin;
348  kic_end = loop_end;
349  Size middle_offset = (kic_end - kic_start) / 2; // need to ensure this isn't a proline
350  kic_middle = kic_start + middle_offset;
351  tr() << "kinematic initial perturb with start_res: " << kic_start << " middle res: " << kic_middle << " end_res: "
352  << kic_end << std::endl;
353  myKinematicMover.set_pivots(kic_start, kic_middle, kic_end);
354  myKinematicMover.set_temperature(temperature);
355 
356  std::string torsion_features = torsion_features_string( pose );
357  tr() << "loop rmsd before initial kinematic perturbation:" << loop_rmsd( pose, native_pose, one_loop_loops ) /* << " -- torsion bins: " << torsion_features */ << std::endl;
358 
359  if (loop.is_extended() ) {
360  myKinematicMover.set_idealize_loop_first( true ); // start without any native angles or lengths
361  core::Size nits=0;
362 
363  core::Real previous_bump_overlap_factor=myKinematicMover.get_bump_overlap_factor();//RAP
364  if ( !option[ OptionKeys::loops::kic_bump_overlap_factor ].user() ) { // AS: allow external changes to the bump overlap factor
365  //RAP: temporarily lower the bump_overlap_factor to 0.4 to speed-up initial loop closure after centroid radii fix
366  myKinematicMover.set_bump_overlap_factor(0.4);//RAP
367  }
368  while (nits < max_kic_build_attempts_) {
369  tr() << "Attempting loop building: " << nits << " ... " << std::endl;
370  myKinematicMover.apply( pose );
371  if (myKinematicMover.last_move_succeeded()) {
373  tr() << "initial kinematic perturbation complete" << std::endl;
374  myKinematicMover.set_idealize_loop_first( false ); // now the loop is idealized
375  break;
376  }
377  nits++;
378  }
379  if ( !option[ OptionKeys::loops::kic_bump_overlap_factor ].user() ) {
380  //RAP: restore bump_overlap_factor to original value
381  myKinematicMover.set_bump_overlap_factor(previous_bump_overlap_factor);//RAP
382  }
383  if (!myKinematicMover.last_move_succeeded()) {
384  tr().Error << "[WARNING] Failed to build loop with kinematic Mover during initial kinematic perturbation after " << nits << " trials: " << loop << std::endl;
386  //pose.fold_tree( f_orig ); // DJM: doing above in LoopRelaxMover now
388  }
389  ( *scorefxn() )(pose);
390  minimizer->run( pose, mm_one_loop, *scorefxn(), options );
391  tr() << "loop rmsd after initial kinematic perturbation:" << loop_rmsd( pose, native_pose, one_loop_loops ) << std::endl;
392 
393  }
394  else {
395  tr() << "not performing initial kinematic perturbation" << std::endl;
396  if (option[ OptionKeys::loops::vicinity_sampling ]()) {
397  // AS Oct 3 2012: replace TorsionRestrictedKinematicPerturber by VicinitySamplingKinematicPerturber
400  v_perturber->set_vary_ca_bond_angles( ! option[ OptionKeys::loops::fix_ca_bond_angles ]() );
401  v_perturber->set_degree_vicinity( option[ OptionKeys::loops::vicinity_degree ]() );
402  myKinematicMover.set_perturber( v_perturber );
403 
404  }
405  }
406 
407  if (local_movie) {
408  std::string outname_base = option[ OptionKeys::loops::output_pdb ]().name();
409  std::string outname_prefix = option[ OptionKeys::out::prefix ];
410  std::string outname = outname_prefix + outname_base + "_centroid_movie_" +
411  right_string_of(cur_struct,4,'0') + ".pdb";
412  loop_outfile.open(outname.c_str(), std::ios::out | std::ios::binary);
413  loop_outfile << "MODEL" << std::endl;
414  utility::vector1<Size> indices(loop_end - loop_begin + 3);
415  for (Size i=loop_begin-1, j=1; i<=loop_end+1; i++, j++) {
416  indices[j]=i;
417  }
418  //pose.dump_pdb(loop_outfile, indices, "init_perturb");
419  loop_outfile << "ENDMDL" << std::endl;
420  }
421 
422  // Monte Carlo object
423  protocols::moves::MonteCarlo mc( pose, *scorefxn(), temperature);
424  mc.show_scores();
425 
426  for( int i=1; i<=outer_cycles; ++i ) {
427  if ( local_debug) { // debug
428  ( *scorefxn() )( pose );
429  tr() << "befor rLOW: " << pose.energies().total_energies().weighted_string_of( scorefxn()->weights() ) <<
430  " rmsd: " << F(9,3,loop_rmsd( pose, native_pose, one_loop_loops )) << std::endl;
431  }
432 
433  // recover low
434  if ( recover_low_ ) {
435  mc.recover_low(pose);
436  }
437 
438  if ( local_debug) { // debug
439  ( *scorefxn() )( pose );
440  tr() << "after rLOW: " << pose.energies().total_energies().weighted_string_of( scorefxn()->weights() ) <<
441  " rmsd: " << F(9,3,loop_rmsd( pose, native_pose, one_loop_loops )) << std::endl;
442  }
443 
444  for( int j=1; j<=inner_cycles; ++j ) {
445  // change temperature
446  temperature *= gamma;
447  mc.set_temperature( temperature );
448  core::Size nits=0;
449  while (nits < remodel_kic_attempts_) {
450  nits++;
451  if (option[ OptionKeys::loops::always_remodel_full_loop ]()) { // warning: for long loops this could be extremely inefficient
452  kic_start = loop_begin;
453  kic_end = loop_end;
454  kic_middle = RG.random_range(kic_start+2, kic_end-2);
455  } else { // randomly selected sub-segments
456  // AS Oct 2012: in the previous KIC implementation there was a directional bias here, as the start pivot is always selected first, which means that the C-terminal part of the loop is sampled more than the N-terminal part
457  if ( option[ OptionKeys::loops::legacy_kic ]() || j % 2 == 0 ) {
458  kic_start = RG.random_range(loop_begin,loop_end-2);
459  // choose a random end residue so the length is >= 3, <= min(loop_end, start+maxlen)
460  kic_end = RG.random_range(kic_start+2, std::min((kic_start+max_seglen_ - 1), loop_end));
461  Size middle_offset = (kic_end - kic_start) / 2;
462  kic_middle = kic_start + middle_offset;
463  } else {
464  //tr() << " -- selection starting from the end of the loop -- " << std::endl;
465  kic_end = RG.random_range(loop_begin+2,loop_end);
466  kic_start = RG.random_range(std::max((kic_end - std::min(max_seglen_, kic_end) + 1), loop_begin), kic_end-2);
467  Size middle_offset = (kic_end - kic_start) / 2;
468  kic_middle = kic_start + middle_offset;
469  }
470  }
471  myKinematicMover.set_pivots(kic_start, kic_middle, kic_end);
472  myKinematicMover.set_temperature(temperature);
473  myKinematicMover.apply( pose );
474  if (myKinematicMover.last_move_succeeded()) {
475  break;
476  }
477  }
478  if (myKinematicMover.last_move_succeeded()) {
479  //fpd symmetrize 'mm_one_loop'
480  if ( core::pose::symmetry::is_symmetric( pose ) ) {
482  }
483  ( *scorefxn() )(pose);
484  minimizer->run( pose, mm_one_loop, *scorefxn(), options );
485  std::string move_type = "kinematic_perturb";
486  bool accepted = mc.boltzmann( pose, move_type );
487  if (accepted) {
488  tr() << "new centroid perturb rmsd: " << loop_rmsd( pose, native_pose, one_loop_loops ) << std::endl;
489  if (local_movie) {
490  loop_outfile << "MODEL" << std::endl;
491  utility::vector1<Size> indices(loop_end - loop_begin + 3);
492  for (Size i=loop_begin-1, j=1; i<=loop_end+1; i++, j++) {
493  indices[j]=i;
494  }
495  pose.dump_pdb(loop_outfile, indices, "init_perturb");
496  loop_outfile << "ENDMDL" << std::endl;
497  }
498  //tr << "chainbreak score: " << pose.energies().total_energies()[ core::scoring::chainbreak ] << std::endl;
499  }
500  //mc.show_scores();
501  }else{
502  tr().Error << "[WARNING] Failed to build loop with kinematic Mover after " << nits << " trials: " << loop << std::endl;
503  // return to original fold tree
504  //pose.fold_tree( f_orig ); // DJM: doing above in LoopRelaxMover now
505  return loop_mover::Failure;
506  }
507  } // inner_cycles
508  } // outer_cycles
509  if ( recover_low_ ) {
510  pose = mc.lowest_score_pose();
511  }
512  else {
513  pose = mc.last_accepted_pose();
514  }
515  if (local_movie) {
516  // this assumes there is only one loop.
517  Size begin_loop=loop.start();
518  Size end_loop=loop.stop();
519  loop_outfile << "MODEL" << std::endl;
520  utility::vector1<Size> indices(end_loop - begin_loop + 3);
521  for (Size i=begin_loop-1, j=1; i<=end_loop+1; i++, j++) {
522  indices[j]=i;
523  }
524  pose.dump_pdb(loop_outfile, indices, "final_perturb");
525  loop_outfile << "ENDMDL" << std::endl;
526  }
527  if (local_debug) {
528  std::ofstream out("score.tmp_perturb_cen");
529  out << "scoring after cen_perturb: " << ( *scorefxn() )(pose) << std::endl;
530  /// Now handled automatically. scorefxn_->accumulate_residue_total_energies(pose);
531  scorefxn()->show( out );
532  out << pose.energies();
533  }
534 
535  // return to original fold tree
536  //pose.fold_tree( f_orig ); // DJM: doing above in LoopRelaxMover now
537 
538  return loop_mover::Success;
539 }
540 
543  return "LoopMover_Perturb_KIC";
544 }
545 
546 basic::Tracer & LoopMover_Perturb_KIC::tr() const
547 {
548  return TR;
549 }
550 
552 
554  return new LoopMover_Perturb_KIC();
555 }
556 
558  return "LoopMover_Perturb_KIC";
559 }
560 
561 } // namespace perturb
562 } // namespace loop_mover
563 } // namespace loops
564 } // namespace protocols