Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
FlexbbSimAnnealer.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/flexpack/annealer/FlexbbSimAnnealer.cc
11 /// @brief Annealer for optimizing both backbone and sidechain conformations implementation.
12 /// @author Andrew Leaver-Fay (aleaverfay@gmail.com)
13 
14 /// Unit Headers
16 
17 /// Package headers
20 
21 /// Project headers
22 #include <basic/Tracer.hh>
23 #include <basic/options/option.hh>
24 #include <basic/options/keys/flexpack.OptionKeys.gen.hh>
25 
26 /// ObjexxFCL headers
27 // AUTO-REMOVED #include <ObjexxFCL/Fmath.hh>
28 
29 /// Utility headers
30 #include <utility/exit.hh>
31 
32 /// Numeric headers
33 #include <numeric/numeric.functions.hh>
34 #include <numeric/random/random.hh>
35 #include <numeric/random/random_permutation.hh>
36 
37 /// C++ headers
38 #include <iostream>
39 
40 #include <utility/vector0.hh>
41 #include <utility/vector1.hh>
42 
43 
44 namespace protocols {
45 namespace flexpack {
46 namespace annealer {
47 
48 static numeric::random::RandomGenerator RG(62458); // <- Magic number, do not change it!!!
49 
50 basic::Tracer TR("protocols.flexpack.annealer.FlexbbSimAnnealer");
51 
53  ObjexxFCL::FArray1D_int & bestrotamer_at_seqpos,
54  PackerEnergy & bestenergy,
55  bool start_with_current, // start simulation with current rotamers
58  ObjexxFCL::FArray1D_int & current_rot_index,
59  bool calc_rot_freq,
60  ObjexxFCL::FArray1D< PackerEnergy > & rot_freq
61 ):
62  parent(
63  ig->get_num_total_states(),
64  bestrotamer_at_seqpos,
65  bestenergy,
66  start_with_current, // start simulation with current rotamers
67  current_rot_index,
68  calc_rot_freq,
69  rot_freq
70  ),
71  ig_(ig),
72  rotsets_( rotsets )
73 {}
74 
76 {}
77 
78 /// @details The FlexbbSimAnnealer operates with three submodes:
79 /// mvsc_only : same as the fixbb mode, only consider moving the side chains
80 /// mvbb_only : no movement with the side chain, but only move the backbone
81 /// both_sc_and bb:default mode would be a combination of move side chain and
82 /// backbone fragments
84 {
85  using namespace interaction_graph;
86 
87 
88  TR << "Beginning flexible backbone simulated annealing" << std::endl;
89 
90  //--------------------------------------------------------------------
91 
92  Size ranrotamer,ranbbfrag;//,rannum;
93  Size nmoltenres = ig_->get_num_nodes();
94  //Size num_accessible, num_accessible_bb, num_backbones_available;
95  Size moltenres_id, rotamer_state_on_moltenres, prevrotamer_state;
96  Size const nrotamers( rotsets_->nrotamers() );
97  Size cycle1, cycle2, cycle3;
98  bool valid_bb_move; //apl if a node on a flexible fragment is in state 0 no meaningful "backbone move" exists
99  PackerEnergy currentenergy, previous_energy_for_node, delta_energy;
100  PackerEnergy previous_energy_for_bbfrag;
101 
102  utility::vector1< Size > accessible_state_list( nrotamers, 0 );
103  utility::vector1< Size > accessible_state_list_bbfrag( rotsets_->nbackbone_conformations(), 0 );//max number of backbone fragment
104 
105  ObjexxFCL::FArray1D< PackerEnergy > loopenergy( maxouteriterations, 0.0);
106 
107  //bk variables for calculating rotamer frequencies during simulation
108  Size nsteps = 0;
109  ObjexxFCL::FArray1D_int nsteps_for_rot( nrotamers, 0 );
110 
111  ObjexxFCL::FArray1D_int state_on_node( nmoltenres, 0);
112  ObjexxFCL::FArray1D_int best_state_on_node( nmoltenres, 0);
113  utility::vector1< int > moltenres_rotoffsets( nmoltenres, 0 );
114  for ( Size ii = 1; ii <= nmoltenres; ++ii ) { moltenres_rotoffsets[ ii ] = rotsets_->nrotamer_offset_for_moltenres( ii ); }
115 
116  //--------------------------------------------------------------------
117  //initialize variables
118 
119  cycle1 = 130;
120  cycle2 = 10;
121  cycle3 = 10;
122 
123  currentenergy = 0.0;
124 
125  //variables to keep track of the frequency of rotamers
126  for ( Size i = 1; i <= rotsets_->nrotamers(); ++i ) {
127  accessible_state_list[ i ] = i;
128  nsteps_for_rot(i) = 0;
129  }
130 
131  ig_->prepare_for_simulated_annealing();
132 
133  set_lowtemp( 0.2 ); // go colder than regular SA!
134 
135  if ( start_with_current() ) {
136  for (Size ii = 1; ii <= nmoltenres; ++ii) {
137  state_on_node(ii) = current_rot_index()( rotsets_->moltenres_2_resid( ii ));
138  }
139  ig_->set_network_state( state_on_node );
140  currentenergy = ig_->get_energy_current_state_assignment();
141  bestenergy() = currentenergy;
142  best_state_on_node = state_on_node;
143  } else {
144  ig_->blanket_assign_state_0();
145  state_on_node = 0;
146  }
147 
148  //outer iterations and inner iterations
150 
151  Size outeriterations = get_outeriterations();
152  Size inneriterations_usual = get_inneriterations();
153 
154  /// Reduce the number of inner iterations to reflect the three
155  /// inner-inner loops that extend the number of rotamer substitutions.
156  /// Note, the base class assigns 5x as many iterations
157  /// if start_with_current is false.
158  inneriterations_usual /= (start_with_current() ? 75 : 75 * 5 );
159 
160  using namespace basic::options;
161  using namespace basic::options::OptionKeys::flexpack::annealer;
162 
163  if ( option[ inner_iteration_scale ].user() ) {
164  inneriterations_usual *= static_cast< Size > (inneriterations_usual * option[ inner_iteration_scale ]);
165  }
166  if ( option[ outer_iteration_scale ].user() ) {
167  outeriterations = static_cast< Size > (outeriterations * option[ outer_iteration_scale ]);
168  }
169  if ( option[ fixbb_substitutions_scale ].user() ) {
170  cycle1 = static_cast< Size > ( cycle1 * option[ fixbb_substitutions_scale ]);
171  }
172  if ( option[ pure_movebb_substitutions_scale ].user() ) {
173  cycle2 = static_cast< Size > ( cycle2 * option[ pure_movebb_substitutions_scale ]);
174  }
175  if ( option[ rotsub_movebb_substitutions_scale ].user() ) {
176  cycle3 = static_cast< Size > ( cycle3 * option[ rotsub_movebb_substitutions_scale ]);
177  }
178 
179  //outeriterations *= 2;
180  //inneriterations_usual /= 25;
181 
182  //collect the list of all accessible states once
183  utility::vector1< Size > list_of_all( nrotamers, 0 );
184 
185  ig_->get_accessible_states(
186  FlexbbInteractionGraph::BOTH_SC_AND_BB,
187  list_of_all
188  );
189 
190 
191  bool sconly_move_accessible_state_list_current( false );
192 
193  //outer loop
194  PackerEnergy last_temperature = 100000;
195  for (Size nn = 1; nn <= outeriterations; ++nn ) {
196 
197  Size num_fixbb_move_accepts = 0;
198  Size num_fixbb_move_valid = 0;
199  Size num_bb_move_accepts = 0;
200  Size num_bb_move_valid = 0;
201  Size num_bb_sub_accepts = 0;
202  Size num_bb_sub_valid = 0;
203 
204  //set up the temperature
205  setup_temperature(loopenergy,nn);
206  Size inneriterations = inneriterations_usual;
207 
208  if ( nn > 1 && get_temperature() > last_temperature) {
209  /// short circuit -- do not return to high temperature.
210  //assert( outeriterations > 0 ); // don't wrap to 4 billion
211  //nn = outeriterations - 1; // force quence next round
212  //continue;
213  set_temperature( 0.5 ); // don't return to high temperatures /// ? maybe?
214  }
215  last_temperature = get_temperature();
216 
217  if ( get_temperature() > 5.0f ) {
218  inneriterations /= 2;
219  } else if ( quench() ) {
220  inneriterations *= 6;
221  }
222 
223  if ( quench() ) {
224  currentenergy = bestenergy();
225  state_on_node = best_state_on_node;
226  ig_->set_network_state( state_on_node );
227  }
228 
229  //default mode, which is a combination of move side chain, move backbone
230  //need to test how many cycles for each mode
231  PackerEnergy temperature = get_temperature();
232  for (Size j = 1; j <= inneriterations; ++j) {
233 
234  if ( ! sconly_move_accessible_state_list_current ) {
235  ig_->get_accessible_states( FlexbbInteractionGraph::SC_ONLY, accessible_state_list );
236  sconly_move_accessible_state_list_current = true;
237  }
238 
239  // std::cout<<"num_accessible = "<<num_accessible<<"totalinnner = "<<inneriterations<<'\n'
240  for (Size n = 1; n <= cycle1; ++n ) {//move side chain only
241  //pick random rotamers from the rotamer list,this subroutine should go into the base class
242  // ranrotamer = pick_a_rotamer(list,n,nn);
243 
244 
245  ranrotamer = pick_a_rotamer( j, n, cycle1, accessible_state_list);
246 
247  if (quench()) {
248  //std::cout<<"inneriteration = "<<j<<"cycle1 = "<<n<<"rannum="<<rannum<<"ranrot="<<ranrotamer<<'\n';
249  }
250 
251  //ranrotamer = accessible_state_list( static_cast< int > (ran3() * num_accessible) + 1 );
252  moltenres_id = rotsets_->moltenres_for_rotamer( ranrotamer );
253  //seqpos = rotsets_->moltenres_2_resid( moltenres_id );
254  rotamer_state_on_moltenres = rotsets_->local_rotid_for_rotamer_on_moltenres( moltenres_id, ranrotamer );
255  prevrotamer_state = state_on_node( moltenres_id );
256 
257  if (rotamer_state_on_moltenres == prevrotamer_state ) continue;// rotamer is already assigned; skip iteration
258 
259  ++num_fixbb_move_valid;
260  //std::cout << "State on node: ";
261  //for ( Size ii = 1; ii <= state_on_node.size(); ++ii ) { std::cout << state_on_node( ii ) << " ";}
262  //std::cout << std::endl;
263  //std::cout << "Consider fixed backbone rotamer substitution" << std::endl;
264  ig_->consider_substitution( moltenres_id, rotamer_state_on_moltenres,
265  delta_energy, previous_energy_for_node);
266 
267  if ((prevrotamer_state == 0)||pass_metropolis(previous_energy_for_node,delta_energy)) {
268  //std::cerr << "pass_metropolis sc only: " << delta_energy << ", " << alternate_energy_total << ", " << bestenergy_ << std::endl;
269  ++num_fixbb_move_accepts;
270  currentenergy = ig_->commit_considered_substitution();
271  state_on_node( moltenres_id ) = rotamer_state_on_moltenres;
272  if ((prevrotamer_state == 0)||(currentenergy < bestenergy() )) {
273  bestenergy() = currentenergy;
274  best_state_on_node = state_on_node;
275  }
276 
277  if ( calc_rot_freq() && ( temperature <= calc_freq_temp ) ) {
278  ++nsteps;
279  for ( Size ii = 1; ii <= nmoltenres; ++ii ) {
280  Size iistate = state_on_node(ii);
281  if ( iistate != 0 ) {
282  ++nsteps_for_rot( iistate + moltenres_rotoffsets[ii] );
283  }
284  }
285  }
286  }
287  }
288 
289  //switch to moving the backbone only
290  ig_->get_backbone_list( accessible_state_list_bbfrag );
291  for (Size n = 1; n <= cycle2; ++n ) {
292  //pick a random backbone fragment from the list
293  // ranbbfrag = accessible_state_list_bbfrag( static_cast< int > (ran3() * num_accessible_bb) + 1 );
294 
295  ranbbfrag = pick_a_rotamer(j,n,cycle2,accessible_state_list_bbfrag);
296 
297  //figure out the old energy and newenergy, at this circustance, the
298  //rotamers are unchanged or at least very close to the old rotamer
299  // frag_index = bbfrag_index(ranbbfrag);
300  // std::cout<<"ranbbfrag="<<ranbbfrag<<'\n';
301  if ( ig_->get_backbone_currently_assigned( ranbbfrag ) ) continue;
302  int num_changing_nodes = 0;
303 
304  //std::cout << "State on node: ";
305  //for ( Size ii = 1; ii <= state_on_node.size(); ++ii ) { std::cout << state_on_node( ii ) << " ";}
306  //std::cout << std::endl;
307 
308 
309  //std::cout << "Consider backbone substitution " << ranbbfrag << " ";
310  ig_->consider_backbone_move( ranbbfrag, delta_energy,
311  previous_energy_for_bbfrag, valid_bb_move, num_changing_nodes);
312  //std::cout << valid_bb_move << std::endl;
313  if (! valid_bb_move ) continue;
314 
315  ++num_bb_move_valid;
317  previous_energy_for_bbfrag,delta_energy, num_changing_nodes)) {
318  ++num_bb_move_accepts;
319  sconly_move_accessible_state_list_current = false;
320  //std::cerr << "pass_metropolis: bb(2) " << delta_energy << ", " << alternate_energy_newbbfrag << ", " << bestenergy_ << std::endl;
321 
322  //switch from prevbbfrag to ranbbfrag, make sure update all the coupled residues
323  currentenergy = ig_->commit_considered_backbone_move(state_on_node);
324  //since multiple sequence changed the backbone conformation
325  //bbfrag_for_fragindex( frag_index ) = ranbbfrag;
326  if ( currentenergy < bestenergy() ) {
327  bestenergy() = currentenergy;
328  best_state_on_node = state_on_node;
329  }
330  }
331 
332  if ( calc_rot_freq() && ( temperature <= calc_freq_temp ) ) {
333  ++nsteps;
334  for ( Size ii = 1; ii <= nmoltenres; ++ii ) {
335  Size iistate = state_on_node(ii);
336  if ( iistate != 0 ) {
337  ++nsteps_for_rot( iistate + moltenres_rotoffsets[ii] );
338  }
339  }
340  }
341  }
342 
343  //at some point, switch to move side/backbone simutaneously
344  //get this list once at the beginning of simulation and reuse it.
345  //ig_->get_accessible_states( FlexbbInteractionGraph::BOTH_SC_AND_BB, list, num_accessible);
346  //all states are accessible;
347  for (Size n = 1; n <= cycle3; ++n ) {
348  //return a list of all rotamers,not sure this is fair enough, because
349  //those residues with alternate backbone conformations defitenly have higher
350  //probability to get picked, but at least in the quench step, the annealer needs to go through
351  //the entire rotamer list exhaustively
352 
353  ranrotamer = pick_a_rotamer(j,n,cycle3,list_of_all);
354 
355  moltenres_id = rotsets_->moltenres_for_rotamer( ranrotamer );
356  //seqpos = rotsets_->moltenres_2_resid( moltenres_id );
357  rotamer_state_on_moltenres = rotsets_->local_rotid_for_rotamer_on_moltenres( moltenres_id, ranrotamer );
358  prevrotamer_state = state_on_node( moltenres_id );
359 
360  if (prevrotamer_state == rotamer_state_on_moltenres ) continue;
361 
362  int num_changing_nodes = 0;
363 
364  //std::cout << "State on node: ";
365  //for ( Size ii = 1; ii <= state_on_node.size(); ++ii ) { std::cout << state_on_node( ii ) << " ";}
366  //std::cout << std::endl;
367 
368 
369  //std::cout << "Consider backbone substitution with rotamer substitution: " << moltenres_id << " " << rotamer_state_on_moltenres << " ";
370  ig_->consider_bbmove_w_state_substitution(
371  moltenres_id, rotamer_state_on_moltenres,
372  delta_energy, previous_energy_for_bbfrag,
373  valid_bb_move, num_changing_nodes );
374  //std::cout << valid_bb_move << std::endl;
375  if (! valid_bb_move ) continue;
376 
377  ++num_bb_sub_valid;
378  if ( (prevrotamer_state == 0) ||
380  previous_energy_for_bbfrag, delta_energy, num_changing_nodes) ) {
381  ++num_bb_sub_accepts;
382 
383  /// If we accept a change in backbone conformation, then mark the state list for SCONLY moves as out-of-date.
384  if ( ! rotsets_->rotamers_on_same_bbconf( moltenres_id, rotamer_state_on_moltenres, prevrotamer_state )) {
385  sconly_move_accessible_state_list_current = false;
386  }
387 
388  //std::cerr << "pass_metropolis: bb & sc " << delta_energy << ", " << alternate_energy_total << ", " << bestenergy_ << std::endl;
389  currentenergy = ig_->commit_considered_backbone_move(state_on_node);
390  if ((prevrotamer_state == 0)||(currentenergy < bestenergy())) {
391  bestenergy() = currentenergy;
392  best_state_on_node = state_on_node;
393  }
394  } // end Metropolis criteria
395 
396  if ( calc_rot_freq() && ( temperature <= calc_freq_temp ) ) {
397  ++nsteps;
398  for ( Size ii = 1; ii <= nmoltenres; ++ii ) {
399  Size iistate = state_on_node(ii);
400  if ( iistate != 0 ) {
401  ++nsteps_for_rot( iistate + moltenres_rotoffsets[ii] );
402  }
403  }
404  }
405  }//end of both_sc_and_bb
406  loopenergy(nn) = currentenergy;
407  }
408 
409  /*std::cerr << "Finished Inner Iterations, temperature = " << get_temperature() << std::endl;
410  std::cerr << "fixbb moves attempted: " << num_fixbb_move_valid << " accepted: " << num_fixbb_move_accepts;
411  if ( num_fixbb_move_valid > 0 ) std::cerr << " (" << (double) num_fixbb_move_accepts / num_fixbb_move_valid << ")";
412  std::cerr << std::endl;
413  std::cerr << "bb moves attempted: " << num_bb_move_valid << " accepted: " << num_bb_move_accepts;
414  if ( num_bb_move_valid > 0 ) std::cerr << " (" << (double) num_bb_move_accepts / num_bb_move_valid << ")";
415  std::cerr << std::endl;
416  std::cerr << "bb substitutions attempted: " << num_bb_sub_valid << " accepted: " << num_bb_sub_accepts;
417  if ( num_bb_sub_accepts > 0 ) std::cerr << " (" << (double) num_bb_sub_accepts / num_bb_sub_valid << ")";
418  std::cerr << std::endl;
419  std::cerr << "bestenergy: " << bestenergy() << " currentenergy: " << currentenergy;
420  std::cerr << std::endl << "-------------" << std::endl;*/
421  }//end of outeriterations
422 
423  //std::cerr << "bestenergy after quench: " << bestenergy() << std::endl;
424  //apl now convert best_state_on_node into bestrotamer_at_seqpos
425 
426  for (Size ii = 1; ii <= nmoltenres; ++ii) {
427  Size iiresid = rotsets_->moltenres_2_resid( ii );
428  bestrotamer_at_seqpos()( iiresid ) = best_state_on_node( ii ) + rotsets_->nrotamer_offset_for_moltenres( ii );
429  }
430 
431  //std::cerr << "bestenergy_ " << bestenergy() << std::endl;
432  //ig_->print_current_state_assignment();
433 
434  return;
435 }
436 
439  Size outercycle,
440  Size innercycle,
441  Size inner_loop_iteration_limit, // ?
442  utility::vector1< Size > & accessible_state_list
443 ) const
444 {
445 
446  Size num = 0;
447 
448  if ( quench() ) {
449  num = numeric::mod( (outercycle - 1) * inner_loop_iteration_limit + innercycle - 1, accessible_state_list.size() ) + 1;
450  if (num == 1 ) {
451  numeric::random::random_permutation( accessible_state_list, RG );
452  }
453  } else {
454  num = static_cast< Size > ( RG.uniform() * accessible_state_list.size() ) + 1;
455  }
456  return accessible_state_list[ num ];
457 }
458 
459 bool
461  PackerEnergy previous_fragmentE,
462  PackerEnergy deltaE,
463  Size num_changing_nodes
464 ) const
465 {
466  assert( num_changing_nodes > 0 );
467  if ( get_temperature() > 0.5 ) {
468  return pass_metropolis( previous_fragmentE / num_changing_nodes , deltaE / ( num_changing_nodes > 4 ? 4 : num_changing_nodes) );
469  } else {
470  return pass_metropolis( previous_fragmentE, deltaE );
471  }
472 }
473 
474 
475 }
476 }
477 }
478 
479