Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
min_pack.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 core/pack/min_pack.cc
11 /// @brief pack rotamers with minimization module
12 /// @author Andrew Leaver-Fay (aleaverfay@gmail.com)
13 
14 // Unit Headers
15 
16 // Package Headers
17 #include <core/pack/rtmin.hh>
29 
30 //#include <core/conformation/symmetry/SymmetryInfo.hh>
31 //#include <core/pose/symmetry/util.hh>
32 // AUTO-REMOVED #include <core/conformation/symmetry/util.hh>
33 
34 
35 // Project Headers
37 #include <core/graph/Graph.hh>
38 #include <core/pose/Pose.hh>
39 #include <core/scoring/Energies.hh>
47 
48 // AUTO-REMOVED #include <core/optimization/DOF_Node.hh> // REQUIRED FOR WINDOWS
49 
50 // util
51 #include <basic/Tracer.hh>
52 
53 /// ObjexxFCL
54 // AUTO-REMOVED #include <ObjexxFCL/format.hh>
55 
56 // Numeric
57 #include <numeric/random/random.hh>
58 // AUTO-REMOVED #include <numeric/xyz.functions.hh>
59 
60 // option key includes
61 #include <basic/options/option.hh>
62 #include <basic/options/keys/packing.OptionKeys.gen.hh>
63 
65 #include <utility/vector1.hh>
66 
67 
68 namespace core {
69 namespace pack {
70 
71 //#define APL_FULL_DEBUG
72 
74  Size resid,
75  pose::Pose const & pose,
76  scoring::ScoreFunction const & sfxn,
77  scoring::MinimizationGraph const & mingraph
78 );
79 
80 static basic::Tracer TR("core.pack.min_pack",basic::t_info );
81 static numeric::random::RandomGenerator RG(22307);
82 
85  pose::Pose const & pose,
87  bool cartesian
88 )
89 {
90  /// create the scminmap and activate all chi for all residues being packed.
91  /// This is important for the initialization of the MinimizationGraph; the
92  /// domain map that the scminmap provides to the ScoreFunction must state
93  /// that each of the molten residues have color 0.
95  if (cartesian) {
96  scminmap = new scmin::CartSCMinMinimizerMap();
97  } else {
98  scminmap = new scmin::AtomTreeSCMinMinimizerMap();
99  }
100 
101  scminmap->set_total_residue( pose.total_residue() );
102  for ( Size ii = 1; ii <= pose.total_residue(); ++ii ) {
103  if ( task->being_packed( ii )) {
104  scminmap->activate_residue_dofs( ii );
105  } else {
106  scminmap->set_natoms_for_residue( ii, pose.residue( ii ).natoms() );
107  }
108  }
109  return scminmap;
110 }
111 
112 
115  pose::Pose & pose,
116  scoring::ScoreFunction const & sfxn,
117  task::PackerTask const & task,
118  graph::Graph const & packer_neighbor_graph,
119  scmin::SCMinMinimizerMap const & sc_min_map
120 )
121 {
123 
124  /// copy all edges that are incident upon the molten residues; background edges may be ignored.
126  eiter = packer_neighbor_graph.const_edge_list_begin(),
127  eiter_end = packer_neighbor_graph.const_edge_list_end();
128  eiter != eiter_end; ++eiter ) {
129  if ( task.being_packed( (*eiter)->get_first_node_ind() ) || task.being_packed( (*eiter)->get_second_node_ind() )) {
130  mingraph->add_edge( (*eiter)->get_first_node_ind(), (*eiter)->get_second_node_ind() );
131  }
132  }
133 
134  /// now, setup the nodes and edges.
135  /// Initialize any node being packed, or that has at least one
136  /// neighbor being packed (i.e. it has at least one incident
137  /// edge in the minimization graph)
138 
139  scoring::EnergyMap dummy;
140  for ( Size ii = 1; ii <= pose.total_residue(); ++ii ) {
141  if ( task.being_packed( ii ) || mingraph->get_node( ii )->num_edges() != 0 ) {
143  * mingraph->get_minimization_node( ii ), pose.residue( ii ),
144  sc_min_map, pose, false, dummy );
145  }
146  }
148  eiter = mingraph->edge_list_begin(), eiter_end = mingraph->edge_list_end();
149  eiter != eiter_end; ++eiter ) {
150  Size const node1 = (*eiter)->get_first_node_ind();
151  Size const node2 = (*eiter)->get_second_node_ind();
152 
153  scoring::MinimizationEdge & minedge( static_cast< scoring::MinimizationEdge & > (**eiter) );
154 
156  pose.residue( node1 ), pose.residue( node2 ),
157  minedge, sc_min_map, pose, true, false,
158  static_cast< scoring::EnergyEdge const * > ( 0 ), dummy );
159  }
160 
161  /// Now initialize the long-range edges
162  for ( Size ii = 1; ii <= pose.total_residue(); ++ii ) {
163  if ( ! task.being_packed( ii ) ) continue;
165  iter = sfxn.long_range_energies_begin(),
166  iter_end = sfxn.long_range_energies_end();
167  iter != iter_end; ++iter ) {
168 
169  if ( (*iter)->minimize_in_whole_structure_context( pose ) ) continue;
170 
171  scoring::LREnergyContainerCOP lrec = pose.energies().long_range_container( (*iter)->long_range_type() );
172  if ( !lrec || lrec->empty() ) continue;
173 
174  // Potentially O(N) operation...
176  rni = lrec->const_neighbor_iterator_begin( ii ), // traverse both upper and lower neighbors
177  rniend = lrec->const_neighbor_iterator_end( ii );
178  (*rni) != (*rniend); ++(*rni) ) {
179  Size const r1 = rni->lower_neighbor_id();
180  Size const r2 = rni->upper_neighbor_id();
181  Size const jj = ( r1 == ii ? r2 : r1 );
182  bool const res_moving_wrt_eachother( true );
183 
184  if ( task.being_packed( jj ) && jj < ii ) continue; // only setup each edge once.
185 
186  conformation::Residue const & lower_res( r1 == ii ? pose.residue( ii ) : pose.residue( jj ) );
187  conformation::Residue const & upper_res( r1 == ii ? pose.residue( jj ) : pose.residue( ii ) );
189  lower_res, upper_res, *iter, *mingraph, sc_min_map, pose,
190  res_moving_wrt_eachother, false, rni, dummy );
191  }
192  }
193  }
194  return mingraph;
195 }
196 
197 /*scmin::AtomTreeCollectionOP
198 create_atom_tree_collections(
199  pose::Pose const & pose,
200  rotamer_set::RotamerSets const & rotsets
201 )
202 {
203  utility::vector1< scmin::AtomTreeCollectionOP > atcs( pose.total_residue() );
204  for ( Size ii = 1; ii <= rotsets->nmoltenres(); ++ii ) {
205  Size iiresid = rotsets->moltenres_2_resid( ii );
206  atcs[ ii ] = new scmin::AtomTreeCollection( rotsets->rotamer_set_for_residue( iiresid ) );
207  }
208  return atcs;
209 }*/
210 
213  pose::Pose const & pose,
214  task::PackerTask const & task
215 )
216 {
218  for ( Size ii = 1; ii <= pose.total_residue(); ++ii ) {
219  if ( ! task.being_packed( ii ) ) bgres[ ii ] = pose.residue( ii ).clone();
220  }
221  return bgres;
222 }
223 
224 
227 )
228 {
229  using namespace basic::options;
230  using namespace basic::options::OptionKeys::packing;
231 
232  if ( option[ minpack_temp_schedule ].user() ) {
233  return option[ minpack_temp_schedule ]();
234  }
235 
236  /// "kTsched5" in APL's tuning of the min packer
237  utility::vector1< Real > temps( 12 );
238  temps[ 1 ] = 33;
239  temps[ 2 ] = 10;
240  temps[ 3 ] = 5;
241  temps[ 4 ] = 1;
242  temps[ 5 ] = .6;
243  temps[ 6 ] = .45;
244  temps[ 7 ] = .4;
245  temps[ 8 ] = .3;
246  temps[ 9 ] = .2;
247  temps[ 10 ] = .1;
248  temps[ 11 ] = .05;
249  temps[ 12 ] = .03;
250  return temps;
251 }
252 
255 )
256 {
257  using namespace basic::options;
258  using namespace basic::options::OptionKeys::packing;
259 
260  if ( option[ minpack_temp_schedule ].user() ) {
261  return option[ minpack_temp_schedule ]();
262  }
263 
264  /// "kTsched5" in APL's tuning of the min packer
265  utility::vector1< Real > temps; temps.reserve( 15 );
266 
267  temps.push_back( 20 );
268  temps.push_back( 10 );
269  temps.push_back( 3 );
270  temps.push_back( 1 );
271  temps.push_back( .6 );
272  temps.push_back( .4 );
273  temps.push_back( .3 );
274  temps.push_back( .2 );
275  temps.push_back( .15 );
276  temps.push_back( .1 );
277  temps.push_back( .075 );
278  temps.push_back( .05 );
279  temps.push_back( .03 );
280  temps.push_back( .02 );
281  temps.push_back( .01 );
282 
283  /*temps[ 1 ] = 10;
284  temps[ 2 ] = 3;
285  temps[ 3 ] = 1;
286  temps[ 4 ] = .6;
287  temps[ 5 ] = .4;
288  temps[ 6 ] = .3;
289  temps[ 7 ] = .2;
290  temps[ 8 ] = .15;
291  temps[ 9 ] = .1;
292  temps[ 10 ] = .075;
293  temps[ 11 ] = .05;
294  temps[ 12 ] = .03;
295  temps[ 13 ] = .02;*/
296  return temps;
297 }
298 
299 
300 Real
302  pose::Pose & pose,
304  scoring::ScoreFunction const & sfxn,
305  scoring::MinimizationGraph & mingraph,
306  scmin::SCMinMinimizerMap & scminmap,
307  scmin::SidechainStateAssignment const & curr_state,
309  rotamer_set::RotamerSets const & rotsets,
310  Size resid,
311  Size moltenres_id
312 #ifdef APL_FULL_DEBUG
313  , pose::Pose & debug_pose
314 #endif
315 )
316 {
317  /// This will be faster after I subclass the minimization graph and store energies on its edges.
318  /// For now, recomupute the energies for this residue
319 
320 #ifdef APL_FULL_DEBUG
321 
322  /// the background residue should already contain the correct coordinates
323  for ( Size ii = 1; ii <= debug_pose.total_residue(); ++ii ) {
324  if ( bgres[ ii ]->natoms() != debug_pose.residue( ii ).natoms() ) {
325  std::cout << "Residue " << ii << " natoms discrepancy" << std::endl;
326  }
327  for ( Size jj = 1; jj <= debug_pose.residue( ii ).natoms(); ++jj ) {
328  if ( bgres[ ii ]->xyz( jj ).distance_squared( debug_pose.residue(ii).xyz(jj) ) > 1e-6 ) {
329  std::cout << "Coordinate discrepancy between debug pose and background residue " << ii << " at atom " << jj << std::endl;
330  }
331  }
332  }
333  for ( Size ii = 1; ii <= debug_pose.residue( resid ).natoms(); ++ii ) {
334  if ( curr_state.momento_for_moltenres( moltenres_id ).coord( ii ).distance_squared( debug_pose.residue( resid ).xyz( ii ) ) > 1e-6 ) {
335  std::cout << " Momento and debug pose coordinate discrepancy " << resid << " " << moltenres_id << " " << ii << std::endl;
336  }
337  }
338  std::cout << " get_residue_current_energy: " << resid << std::endl;
339 #endif
340 
341 
342 
343  /// 1.
344  scmin::ResidueAtomTreeCollection & ratc = atc->residue_atomtree_collection( resid );
345  Size curr_rot = curr_state.orig_rotamer_id_for_moltenres( moltenres_id );
346  Size const restype_index_for_curr_rotamer = rotsets.rotamer_set_for_residue( resid )->get_residue_type_index_for_rotamer( curr_rot );
347  ratc.set_active_restype_index( restype_index_for_curr_rotamer );
348  ratc.update_from_momento( curr_state.momento_for_moltenres( moltenres_id ) );
349 
350 #ifdef APL_FULL_DEBUG
351  for ( Size ii = 1; ii <= ratc.active_residue().natoms(); ++ii ) {
352  if ( std::abs( ratc.active_residue().xyz( ii ).distance_squared( curr_state.momento_for_moltenres( moltenres_id ).coord( ii ) ) > 1e-6 )){
353  std::cout << " RATC and momento coordinate discrepancy before func eval " << ii << std::endl;
354  }
355  }
356  for ( Size ii = 1; ii <= ratc.active_residue().chi().size(); ++ii ) {
357  Real ratc_chi_ii = ratc.active_residue().chi()[ ii ] <= -180 ? ratc.active_residue().chi()[ ii ] + 360 : ratc.active_residue().chi()[ ii ];
358  Real dbpose_chi_ii = debug_pose.residue( resid ).chi()[ ii ] <= -180 ? debug_pose.residue( resid ).chi()[ ii ] + 360 : debug_pose.residue( resid ).chi()[ ii ];
359  if ( std::abs( ratc_chi_ii - dbpose_chi_ii ) > 1e-6 && std::abs( std::abs( ratc_chi_ii - dbpose_chi_ii) - 360 ) > 1e-3 ) {
360  std::cout << " Chi discrepancy between momento-restored ratc and debug pose " << ratc_chi_ii << " vs " << dbpose_chi_ii << " " << resid << " " << debug_pose.residue( resid ).name() << " chi: " << ii << std::endl;
361  }
362  }
363 #endif
364 
365  /// 2.
366  scminmap.clear_active_dofs();
367  scminmap.activate_residue_dofs( resid );
368  scminmap.set_natoms_for_residue( resid, atc->residue_atomtree_collection( resid ).active_restype().natoms() );
369  scminmap.setup( atc );
370 
371  /// 3.
372  reinitialize_mingraph_neighborhood_for_residue( pose, sfxn, bgres, scminmap, ratc.active_residue(), mingraph );
373 
374  /// 4.
375  //scmin::SCMinMultifunc scmin_func( pose, bgres, sfxn, mingraph, scminmap );
376  optimization::MultifuncOP scmin_func = scminmap.make_multifunc( pose, bgres, sfxn, mingraph );
377  //utility::vector1< Real > chi = ratc.active_residue().chi();
379  scminmap.starting_dofs( chi );
380 
381  Real funcval = (*scmin_func)( chi );
382 
383 #ifdef APL_FULL_DEBUG
384  bool bad = false;
385  for ( Size ii = 1; ii <= ratc.active_residue().natoms(); ++ii ) {
386  if ( std::abs( ratc.active_residue().xyz( ii ).distance_squared( curr_state.momento_for_moltenres( moltenres_id ).coord( ii ) ) > 1e-6 )){
387  std::cout << " RATC and momento coordinate discrepancy! " << ii << std::endl;
388  bad = true;
389  }
390  }
391  if ( bad ) {
392  std::cout << " measured chi " << std::endl;
393  conformation::Residue const & r( ratc.active_residue() );
394  for ( Size ii = 1; ii <= chi.size(); ++ii ) {
395  std::cout << " ratc desired: " << chi[ ii ] << " actual: " << numeric::dihedral_degrees( r.xyz( r.chi_atoms(ii)[ 1 ]), r.xyz( r.chi_atoms(ii)[2]), r.xyz( r.chi_atoms(ii)[3]), r.xyz( r.chi_atoms(ii)[4] ) ) << std::endl;
396  std::cout << " momento desired: " << chi[ ii ] << " actual: " << numeric::dihedral_degrees( curr_state.momento_for_moltenres( moltenres_id ).coord( r.chi_atoms(ii)[ 1 ]), curr_state.momento_for_moltenres( moltenres_id ).coord( r.chi_atoms(ii)[2]), curr_state.momento_for_moltenres( moltenres_id ).coord( r.chi_atoms(ii)[3]), curr_state.momento_for_moltenres( moltenres_id ).coord( r.chi_atoms(ii)[4] ) ) << std::endl;
397  }
398  }
399 
400  compare_mingraph_and_energy_graph(resid, debug_pose, sfxn, mingraph );
401 
402  //Real res_energy_from_debug_pose = debug_pose.energies().residue_total_energies( resid ).dot( sfxn.weights() );
403  for ( Size ii = 1; ii <= chi.size(); ++ii ) {
404  if ( std::abs( ratc.active_residue().chi()[ ii ] - chi[ ii ] ) > 1e-3 ) {
405  std::cout << "chi discrepancy " << ratc.active_residue().chi()[ ii ] << " vs " << chi[ ii ] << std::endl;
406  }
407  }
408  for ( Size ii = 1; ii <= debug_pose.residue( resid ).natoms(); ++ii ) {
409  if ( ratc.active_residue().xyz( ii ).distance_squared( debug_pose.residue( resid ).xyz( ii ) ) > 1e-6 ) {
410  std::cout << "Coordinate discrepancy between debug pose and RATC for residue " << resid << " at atom " << ii << std::endl;
411  }
412  }
413  for ( Size ii = 1; ii <= debug_pose.total_residue(); ++ii ) {
414  if ( bgres[ ii ]->natoms() != debug_pose.residue( ii ).natoms() ) {
415  std::cout << "Residue " << ii << " natoms discrepancy" << std::endl;
416  }
417  for ( Size jj = 1; jj <= debug_pose.residue( ii ).natoms(); ++jj ) {
418  if ( bgres[ ii ]->xyz( jj ).distance_squared( debug_pose.residue(ii).xyz(jj) ) > 1e-6 ) {
419  std::cout << "Coordinate discrepancy between debug pose and background residue " << ii << " at atom " << jj << std::endl;
420  }
421  }
422  }
423 
424 #endif
425 
426  return funcval;
427 }
428 
429 Real
431  pose::Pose & pose,
433  scoring::ScoreFunction const & sfxn,
434  scoring::MinimizationGraph & mingraph,
435  scmin::SCMinMinimizerMap & scminmap,
436  scmin::SidechainStateAssignment const & curr_state,
438  rotamer_set::RotamerSets const & rotsets
439 )
440 {
441  /// This will be faster after I subclass the minimization graph and store energies on its edges.
442  /// For now, recomupute the energies for this residue
443 
444  /// 1.
445  for ( Size ii = 1; ii <= rotsets.nmoltenres(); ++ii ) {
446  Size iiresid = rotsets.moltenres_2_resid( ii );
447  scmin::ResidueAtomTreeCollection & iiratc = atc->residue_atomtree_collection( iiresid );
448  Size curr_rot = curr_state.orig_rotamer_id_for_moltenres( ii );
449  Size const restype_index_for_curr_rotamer = rotsets.rotamer_set_for_residue( iiresid )->get_residue_type_index_for_rotamer( curr_rot );
450  iiratc.set_active_restype_index( restype_index_for_curr_rotamer );
451  iiratc.update_from_momento( curr_state.momento_for_moltenres( ii ) );
452  }
453 
454  /// 2.
455  scminmap.clear_active_dofs();
456  for ( Size ii = 1; ii <= rotsets.nmoltenres(); ++ii ) {
457  Size iiresid = rotsets.moltenres_2_resid( ii );
458  scminmap.activate_residue_dofs( iiresid );
459  scminmap.set_natoms_for_residue( iiresid, atc->residue_atomtree_collection( iiresid ).active_restype().natoms() );
460  }
461  scminmap.setup( atc );
462 
463  /// 3.
464  for ( Size ii = 1; ii <= rotsets.nmoltenres(); ++ii ) {
465  Size iiresid = rotsets.moltenres_2_resid( ii );
466  scmin::ResidueAtomTreeCollection & iiratc = atc->residue_atomtree_collection( iiresid );
467  reinitialize_mingraph_neighborhood_for_residue( pose, sfxn, bgres, scminmap, iiratc.active_residue(), mingraph );
468  }
469 
470  /// 4.
471  //scmin::SCMinMultifunc scmin_func( pose, bgres, sfxn, mingraph, scminmap );
472  optimization::MultifuncOP scmin_func = scminmap.make_multifunc( pose, bgres, sfxn, mingraph );
474  //for ( Size ii = 1; ii <= rotsets.nmoltenres(); ++ii ) {
475  // Size iiresid = rotsets.moltenres_2_resid( ii );
476  // scmin::ResidueAtomTreeCollection & iiratc = atc->residue_atomtree_collection( iiresid );
477  // utility::vector1< Real > chi = iiratc.active_residue().chi();
478  // for ( Size jj = 1; jj <= chi.size(); ++jj ) allchi.push_back( chi[ jj ] );
479  //}
480  scminmap.starting_dofs( allchi );
481 
482 
483  return (*scmin_func)( allchi );
484 }
485 
486 Real
488  pose::Pose & pose,
490  scoring::ScoreFunction const & sfxn,
491  scoring::MinimizationGraph & mingraph,
492  scmin::SCMinMinimizerMap & scminmap,
493  optimization::MinimizerOptions const & min_options,
494  scmin::SidechainStateAssignment const & curr_state,
496  rotamer_set::RotamerSets const & rotsets,
497  Size resid,
498  Size moltenres_id,
499  Size rotamer_state_on_moltenres
500 #ifdef APL_FULL_DEBUG
501  , pose::Pose & debug_pose
502 #endif
503 
504 )
505 {
506  /// 0. (to be made more efficient) get the starting energy for this residue
507  /// 1. setup the atom tree collection for the (possibly) new residue type
508  /// 2. setup the scminmap so that it has space to store derivatives for all the atoms in the molten residue
509  /// 3. setup the mingraph
510  /// 4. create the scminmultifunc
511  /// 5. run the minimizer
512  /// 6. re-evaluate the energy of the new minimized residue (made accurate by a nblist reconstruction)
513  /// 7. return the delta-energy
514 
515  /// 0.
516  Real start_energy_for_residue( 0.0 );
517  if ( ! curr_state.any_unassigned() ) {
518  start_energy_for_residue = get_residue_current_energy(
519  pose, bgres, sfxn, mingraph, scminmap,
520  curr_state, atc, rotsets, resid, moltenres_id
521 #ifdef APL_FULL_DEBUG
522  , debug_pose
523 #endif
524  );
525  }
526 
527  /// 1.
528  scmin::ResidueAtomTreeCollection & ratc = atc->residue_atomtree_collection( resid );
529  Size const restype_index_for_rotamer = rotsets.rotamer_set_for_residue( resid )->get_residue_type_index_for_rotamer( rotamer_state_on_moltenres );
530  ratc.set_active_restype_index( restype_index_for_rotamer );
531  ratc.set_rescoords( * rotsets.rotamer_for_moltenres( moltenres_id, rotamer_state_on_moltenres ));
532  ratc.update_atom_tree();
533 
534  /// 2.
535  scminmap.set_natoms_for_residue( resid, atc->residue_atomtree_collection( resid ).active_restype().natoms() );
536 
537  if ( curr_state.any_unassigned() ) return 0.0; // quit now; can't minimize in the absence of assigned rotamers
538 
539  scminmap.clear_active_dofs();
540  scminmap.activate_residue_dofs( resid );
541  scminmap.setup( atc );
542 
543  /// 3.
544  reinitialize_mingraph_neighborhood_for_residue( pose, sfxn, bgres, scminmap, ratc.active_residue(), mingraph );
545 
546  /// 4.
547  //scmin::SCMinMultifunc scmin_func( pose, bgres, sfxn, mingraph, scminmap );
548  optimization::MultifuncOP scmin_func = scminmap.make_multifunc( pose, bgres, sfxn, mingraph );
549  //utility::vector1< Real > chi = ratc.active_residue().chi();
551  scminmap.starting_dofs( chi );
552 
553  /// 5.
554  optimization::Minimizer minimizer( *scmin_func, min_options );
555  minimizer.run( chi );
556 
557  /// 6.
558  reinitialize_mingraph_neighborhood_for_residue( pose, sfxn, bgres, scminmap, ratc.active_residue(), mingraph );
559  Real final_energy_for_residue = (*scmin_func)( chi );
560 
561  /// 7.
562  //TR << "start energy for rotamer on " << resid << " " << start_energy_for_residue << " final energy: " << final_energy_for_residue << std::endl;
563  return final_energy_for_residue - start_energy_for_residue;
564 
565 }
566 
567 bool
569  Real temperature,
570  Real deltaE
571 )
572 {
573  /// call this every time, for better numerical stability. Otherwise delta_energies ~ 0 can lead to
574  /// instability in the number of calls to the random number generator
575  core::PackerEnergy const rg_uniform( RG.uniform() );
576 
577  if ( deltaE < 0 ) {
578  return true;
579  } else { //evaluate prob of substitution
580  Real lnprob = deltaE / temperature;
581  if ( lnprob < 10.0 ) {
582  Real probability = std::exp(-lnprob);
583  if ( probability > rg_uniform ) return true;
584  }
585  }
586  return false;
587 }
588 
589 Size
591 {
592  using namespace basic::options;
593  using namespace basic::options::OptionKeys::packing;
594 
595  int scale = 5;
596  if ( option[ minpack_inner_iteration_scale ].user() ) {
597  scale = option[ minpack_inner_iteration_scale ]();
598  if ( scale < 0 ) scale = 0; // negative iterations make no sense.
599  }
600 
601  return scale * nrotamers;
602 }
603 
604 
605 
607  Size resid,
608  pose::Pose const & pose,
609  scoring::ScoreFunction const & sfxn,
610  scoring::MinimizationGraph const & mingraph
611 )
612 {
613  using namespace pose;
614  using namespace scoring;
615  using namespace graph;
616 
617  bool discrepancy( false );
618  static int n_discreps( 0 );
619 
620  EnergyMap const & one_body_emap( pose.energies().onebody_energies( resid ));
621  EnergyMap min_node_1b;
622  eval_res_onebody_energies_for_minnode( * mingraph.get_minimization_node( resid ), pose.residue( resid ), pose, sfxn, min_node_1b );
623  for ( Size kk = 1; kk <= total_score; ++kk ) {
624  ScoreType kkst = ScoreType(kk);
625  if ( sfxn.weights()[ kkst ] != 0.0 ) {
626  if ( std::abs( one_body_emap[ kkst ] - min_node_1b[ kkst ] ) > 1e-10 ) {
627  std::cout << " one body discrepancy " << kkst << ": " << one_body_emap[ kkst ] << " " << min_node_1b[ kkst ] << std::endl;
628  }
629  }
630  }
631 
632  EnergyGraph const & eg( pose.energies().energy_graph() );
633  for ( Node::EdgeListConstIter iter = eg.get_node(resid)->const_edge_list_begin(),
634  iter_end = eg.get_node(resid)->const_edge_list_end();
635  iter != iter_end; ++iter ) {
636  Size ii( (*iter)->get_first_node_ind() );
637  Size jj( (*iter)->get_second_node_ind() );
638  if ( ii != resid && jj != resid ) continue; // only compare nodes that are involved in the current optimization
639  MinimizationEdge const * minedge = static_cast< MinimizationEdge const * > ( mingraph.find_edge( ii, jj ) );
640  EnergyEdge const * eedge = static_cast< EnergyEdge const * > ( *iter );
641  EnergyMap emap = eedge->fill_energy_map();;
642 
643  if ( ! minedge ) {
644  std::cout << "Minimization edge " << ii << " " << jj << " missing from minimization graph" << std::endl;
645  emap.show_if_nonzero_weight( std::cout, pose.energies().weights() );
646  std::cout << std::endl;
647  Real delta = emap.dot( pose.energies().weights() );
648  if ( delta > 0 ) {
649  discrepancy = true;
650  }
651  continue;
652  }
653  bool etab_discrepancy( false );
654  EnergyMap emap2;
655  eval_res_pair_energy_for_minedge( *minedge, pose.residue(ii), pose.residue(jj), pose, sfxn, emap2 );
656  for ( Size kk = 1; kk <= total_score; ++kk ) {
657  ScoreType kkst = ScoreType(kk);
658  if ( sfxn.weights()[ kkst ] != 0.0 ) {
659  if ( std::abs( emap[ kkst ] - emap2[ kkst ] ) > 1e-10 ) {
660  std::cout << " " << ii << " " << jj << " " << kkst << " discrepancy: " << emap[ kkst ] << " " << emap2[ kkst ] << std::endl;
661  if ( kkst != hbond_bb_sc ) {
662  discrepancy = true; // the hydrogen bond exclusion rule can lead to funniness.
663  }
664  if ( kkst == fa_atr || kkst == fa_rep || kkst == fa_sol ) {
665  etab_discrepancy = true;
666  }
667  }
668  }
669  }
670  if ( etab_discrepancy ) {
671  std::cout << "etable discrepancy" << std::endl;
672  ///using namespace scoring;
673  ///using namespace scoring::etable;
674  ///methods::EnergyMethodOptions options; // default is fine
675  //EtableEnergy etab_energy( *( ScoringManager::get_instance()->etable( options.etable_type() )), options );
676  //ResiduePairNeighborList const & nblist( static_cast< ResiduePairNeighborList const & > (minedge->res_pair_min_data().get_data_ref( etab_pair_nblist )) );
677  //debug_nblist_for_respair( pose.residue(ii), pose.residue(jj), pose, sfxn, etab_energy, nblist );
678  }
679  }
680 
681  if ( discrepancy ) {
682  ++n_discreps;
683  pose.dump_pdb( "discrepancy_pose_" + utility::to_string( n_discreps ) + ".pdb" );
684  }
685 
686 }
687 
688 void
690  pose::Pose & pose,
692  scoring::ScoreFunction const & sfxn,
695  optimization::MinimizerOptions const & min_options,
696  scmin::SidechainStateAssignment & curr_state,
697  scmin::SidechainStateAssignment & best_state,
700 #ifdef APL_FULL_DEBUG
701  , pose::Pose & debug_pose
702 #endif
703 )
704 {
705  /// Assign random rotamers to start.
706  /// This is the initial assignment; from here on out, we're doing regular sim annealing instead
707  /// of waiting until each residue has an assigned rotamer.
708  for ( Size ii = 1; ii <= rotsets->nmoltenres(); ++ii ) {
709  Size const ii_resid = rotsets->moltenres_2_resid( ii );
710  Size const ii_rotamer_on_moltenres = static_cast< Size > ( rotsets->nrotamers_for_moltenres( ii ) * RG.uniform() + 1 );
711 
712  /// This is an aborted call; this function knows not to attempt to minimize until curr_state has
713  /// no unassigned residues.
715  pose, bgres, sfxn, *mingraph, *scminmap, min_options, curr_state,
716  atc, *rotsets, ii_resid, ii, ii_rotamer_on_moltenres
717 #ifdef APL_FULL_DEBUG
718  , debug_pose
719 #endif
720  );
721  atc->moltenres_atomtree_collection( ii ).save_momento( curr_state.state_momento( ii ) );
722  curr_state.assign_state( ii, ii_rotamer_on_moltenres );
723  bgres[ ii_resid ] = atc->moltenres_atomtree_collection( ii ).active_residue_cop();
724 
725 #ifdef APL_FULL_DEBUG
726  debug_pose.replace_residue( ii_resid, atc->moltenres_atomtree_collection( ii ).active_residue(), false );
727 #endif
728  }
729 
730  Real totalE = get_total_energy_for_state( pose, bgres, sfxn, *mingraph, *scminmap, curr_state, atc, *rotsets );
731  //std::cout << "Initial assignment total energy: " << totalE << std::endl;
732 #ifdef APL_FULL_DEBUG
733  Real debug_pose_start_score( sfxn( debug_pose ) );
734  if ( std::abs( debug_pose_start_score - totalE ) > 1e-3 ) {
735  std::cout << "Initial energy assignment disagrees with actual initial energy " << totalE << " " << debug_pose_start_score << std::endl;
736  debug_pose.energies().total_energies().show_weighted( std::cout, sfxn.weights() );
737  std::cout << std::endl;
738  for ( Size kk = 1; kk <= debug_pose.total_residue(); ++kk ) {
739  compare_mingraph_and_energy_graph( kk, debug_pose, sfxn, *mingraph );
740  }
741  }
742 #endif
743 
744  curr_state.assign_energy( totalE );
745  best_state = curr_state;
746 
747 }
748 
749 void
751  pose::Pose & pose,
752  scoring::ScoreFunction const & sfxn,
753  task::PackerTaskCOP input_task,
754  bool cartesian,
755  bool nonideal
756 )
757 {
758  using namespace interaction_graph;
759  using namespace rotamer_set;
760  using namespace basic::options;
761  using namespace basic::options::OptionKeys::packing;
762  task::PackerTaskOP task = input_task->clone();
763 
764  Real start_score( sfxn( pose ) );
765 
766  /// 1. build the packer neighbor graph and construct rotamers
767  /// 2. build the SCMinMinimizerMap & the MinimizationGraph
768  /// 3. build the atom tree sets for each of the molten residues
769  /// 4. assign a random rotamer to each molten residue
770  /// 5. begin the temperature loop
771  /// 6. begin the fixed-temperature loop
772  /// 7. given a considered rotamer substitution, run a quick minimization
773  /// 8. if the new rotamer passes the metropolis criterion, save a momento of the network state
774  /// 9. construct the pose from the momentos of the lowest scoring network state
775 
776  /// 1.
777  pack_scorefxn_pose_handshake( pose, sfxn);
779  sfxn.setup_for_packing( pose, task->repacking_residues(), task->designing_residues() );
780  if ( option[ minpack_disable_bumpcheck ] ) task->set_bump_check( false );
781  graph::GraphOP packer_neighbor_graph = create_packer_graph( pose, sfxn, task );
783  rotsets->set_task( task );
784  rotsets->build_rotamers( pose, sfxn, packer_neighbor_graph );
785  rotsets->prepare_sets_for_packing( pose, sfxn );
786 
787  /// 2.
788  scmin::SCMinMinimizerMapOP scminmap = create_scmin_minimizer_map( pose, task, cartesian );
789  scminmap->set_nonideal(nonideal);
790  scoring::MinimizationGraphOP mingraph = create_minimization_graph( pose, sfxn, *task, *packer_neighbor_graph, *scminmap );
791 
792  /// 3.
793  scmin::AtomTreeCollectionOP atc = new scmin::AtomTreeCollection( pose, *rotsets );
794 
795  // true -- nblist, false -- deriv_check, false -- deriv_verbose
796  //optimization::MinimizerOptions min_options( "dfpmin", 0.1, true, false, false );
797  std::string minimizer = "dfpmin";
798  Size max_iter=200;
799  if (cartesian) {
800  minimizer = "lbfgs_armijo";
801  max_iter = 25;
802  }
803  optimization::MinimizerOptions min_options( minimizer, 0.1, true, false, false );
804  min_options.max_iter(max_iter);
805  min_options.silent(true);
806 
807 
808 #ifdef APL_FULL_DEBUG
809  pose::Pose debug_pose( pose );
810  sfxn( debug_pose );
811 #endif
812 
813  /// 4.
815  scmin::SidechainStateAssignment curr_state( rotsets->nmoltenres() ), best_state( rotsets->nmoltenres() );
816  assign_random_rotamers( pose, bgres, sfxn, mingraph,
817  scminmap, min_options, curr_state, best_state, atc, rotsets
818 #ifdef APL_FULL_DEBUG
819  , debug_pose
820 #endif
821  );
822 
823  /// 5.
825 
826  for ( Size ii = 1; ii <= temps.size(); ++ii ) {
827  Real ii_temperature = temps[ ii ];
828  /// 6.
829  for ( Size jj = 1, jj_end = n_inner_iterations( ii_temperature, rotsets->nrotamers() ); jj <= jj_end; ++jj ) {
830  Size const jj_ranrotamer = static_cast< Size > ( rotsets->nrotamers() * RG.uniform() + 1 );
831  Size const jj_moltenres_id = rotsets->moltenres_for_rotamer( jj_ranrotamer );
832  Size const jj_resid = rotsets->moltenres_2_resid( jj_moltenres_id );
833  Size const jj_rotamer_state_on_moltenres = rotsets->rotid_on_moltenresidue( jj_ranrotamer );
834 
835 #ifdef APL_FULL_DEBUG
836  conformation::ResidueCOP before_sub_rotamer( 0 );
837  if ( bgres[ jj_resid ] ) {
838  before_sub_rotamer = new conformation::Residue( *bgres[ jj_resid ] );
839  }
840  if ( ! curr_state.any_unassigned() ) {
841  for ( Size kk = 1; kk <= rotsets->nmoltenres(); ++kk ) {
842  Size kkresid = rotsets->moltenres_2_resid( kk );
843  for ( Size ll = 1; ll <= bgres[ kkresid ]->natoms(); ++ll ) {
844  if ( std::abs( bgres[ kkresid ]->xyz( ll ).distance_squared( debug_pose.residue( kkresid ).xyz( ll ) )) > 1e-5 ) {
845  std::cout << " DEBUG error: debug pose and bgres disagree: " << kkresid << " " << bgres[ kkresid ]->atom_name( ll ) << std::endl;
846  }
847  }
848  }
849  }
850 #endif
851 
852  /// 7.
853  Real deltaE = minimize_alt_rotamer(
854  pose, bgres, sfxn, *mingraph, *scminmap, min_options, curr_state,
855  atc, *rotsets, jj_resid, jj_moltenres_id, jj_rotamer_state_on_moltenres
856 #ifdef APL_FULL_DEBUG
857  , debug_pose
858 #endif
859  );
860 
861 #ifdef APL_FULL_DEBUG
862 
863  Real debug_before = sfxn( debug_pose );
864  scoring::EnergyMap total_before = debug_pose.energies().total_energies();
865  debug_pose.replace_residue( jj_resid, atc->moltenres_atomtree_collection( jj_moltenres_id ).active_residue(), false );
866  Real debug_after = sfxn( debug_pose );
867  scoring::EnergyMap total_after = debug_pose.energies().total_energies();
868  Real real_deltaE = debug_after - debug_before;
869  if ( !curr_state.any_unassigned() && std::abs( real_deltaE - deltaE ) > 1e-3 ) {
870  std::cout << "DeltaE mismatch: " << real_deltaE << " vs " << deltaE << std::endl;
871  scoring::EnergyMap total_diff = total_after;
872  for ( Size ii = 1; ii <= scoring::n_score_types; ++ii ) {
873  total_diff[ (scoring::ScoreType) ii ] -= total_before[ (scoring::ScoreType) ii ];
874  }
875  std::cout << "Difference in energies: before vs after " << std::endl;
876  total_diff.show_weighted( std::cout, sfxn.weights() );
877  std::cout << std::endl;
878  compare_mingraph_and_energy_graph( jj_resid, debug_pose, sfxn, *mingraph );
879  } else if ( !curr_state.any_unassigned() ) {
880  //std::cout << "Good deltaE" << std::endl;
881  }
882 #endif
883 
884  /// 7.
885  if ( curr_state.any_unassigned() || pass_metropolis( ii_temperature, deltaE ) ) {
886  //std::cout << "Substitution accepted " << jj_resid << std::endl;
887  // accept the rotamer substitution
888  if ( curr_state.any_unassigned() ) {
889  if ( curr_state.orig_rotamer_id_for_moltenres( jj_moltenres_id ) == 0 && curr_state.n_unassigned() == 1 ) {
890  /// This is the last un-assigned residue that needs assigning
891  atc->moltenres_atomtree_collection( jj_moltenres_id ).save_momento( curr_state.state_momento( jj_moltenres_id ) );
892  curr_state.assign_state( jj_moltenres_id, jj_rotamer_state_on_moltenres );
893  bgres[ jj_resid ] = atc->moltenres_atomtree_collection( jj_moltenres_id ).active_residue_cop();
894  Real totalE = get_total_energy_for_state( pose, bgres, sfxn, *mingraph, *scminmap, curr_state, atc, *rotsets );
895  std::cout << "Initial assignment total energy: " << totalE << std::endl;
896 #ifdef APL_FULL_DEBUG
897  if ( std::abs( debug_after - totalE ) > 1e-3 ) {
898  std::cout << "Initial energy assignment disagrees with actual initial energy" << std::endl;
899  for ( Size kk = 1; kk <= debug_pose.total_residue(); ++kk ) {
900  compare_mingraph_and_energy_graph( kk, debug_pose, sfxn, *mingraph );
901  }
902  }
903 #endif
904 
905  curr_state.assign_energy( totalE );
906  best_state = curr_state;
907  } else {
908  atc->moltenres_atomtree_collection( jj_moltenres_id ).save_momento( curr_state.state_momento( jj_moltenres_id ) );
909  curr_state.assign_state( jj_moltenres_id, jj_rotamer_state_on_moltenres );
910  bgres[ jj_resid ] = atc->moltenres_atomtree_collection( jj_moltenres_id ).active_residue_cop();
911  }
912  } else {
913  Real alt_totalE = curr_state.energy() + deltaE;
914  curr_state.assign_energy( alt_totalE );
915  //std::cout << "Accepted substitution total energy: " << alt_totalE << " temp: " << ii_temperature << std::endl;
916 #ifdef APL_FULL_DEBUG
917  if ( std::abs( alt_totalE - debug_after ) > 1e-3 ) {
918  std::cout << "total energy mismatch: " << debug_after << " " << alt_totalE << std::endl;
919  }
920 #endif
921 
922  atc->moltenres_atomtree_collection( jj_moltenres_id ).save_momento( curr_state.state_momento( jj_moltenres_id ) );
923  curr_state.assign_state( jj_moltenres_id, jj_rotamer_state_on_moltenres );
924  bgres[ jj_resid ] = atc->moltenres_atomtree_collection( jj_moltenres_id ).active_residue_cop();
925  if ( curr_state.energy() < best_state.energy() ) {
926  Real totalE = get_total_energy_for_state( pose, bgres, sfxn, *mingraph, *scminmap, curr_state, atc, *rotsets );
927 #ifdef APL_FULL_DEBUG
928  if ( std::abs( totalE - curr_state.energy() ) > 1e-6 ) {
929  std::cout << "totalE and curr_state energy mismatch " << totalE << " " << curr_state.energy() << std::endl;
930  }
931 #endif
932  curr_state.assign_energy( totalE );
933  if ( totalE < best_state.energy() ) {
934  best_state = curr_state;
935  //std::cout << "Accepted new best " << best_state.energy() << " " << totalE << " discrepancy: " << best_state.energy() - totalE << std::endl;
936  }
937  }
938  }
939 
940  } else {
941  // reset the bgres state
942  //std::cout << "Substitution rejected " << jj_resid << std::endl;
943  atc->moltenres_atomtree_collection( jj_moltenres_id ).
944  update_from_momento( curr_state.momento_for_moltenres( jj_moltenres_id ) );
945  bgres[ jj_resid ] = atc->moltenres_atomtree_collection( jj_moltenres_id ).active_residue_cop();
946 #ifdef APL_FULL_DEBUG
947  debug_pose.replace_residue( jj_resid, *bgres[ jj_resid ], false );
948  sfxn( debug_pose );
949  if ( before_sub_rotamer && before_sub_rotamer->natoms() == bgres[ jj_resid ]->natoms() ) {
950  for ( Size kk = 1; kk <= before_sub_rotamer->natoms(); ++kk ) {
951  if ( before_sub_rotamer->xyz( kk ).distance_squared( bgres[ jj_resid ]->xyz( kk ) ) > 1e-5 ) {
952  std::cout << "Failed to properly restore the previous state after rejecting substitution at residue " << jj_resid << " atom " << kk << std::endl;
953  }
954  }
955  } else {
956  std::cout << "NATOMS discrepancy in before-sub rotamer with bgrotamer" << std::endl;
957  }
958 #endif
959 
960  }
961  }
962  //std::cout << "Finished temperature " << ii_temperature << " with energy " << curr_state.energy() << " and best energy " << best_state.energy() << std::endl;
963  }
964 
965  /// 8.
966  for ( Size ii = 1; ii <= rotsets->nmoltenres(); ++ii ) {
967  Size iiresid = rotsets->moltenres_2_resid( ii );
968  atc->moltenres_atomtree_collection( ii ).update_from_momento( best_state.momento_for_moltenres( ii ) );
969  pose.replace_residue( iiresid, atc->moltenres_atomtree_collection( ii ).active_residue(), false );
970  }
971 
972  Real final_score( sfxn( pose ) );
973  TR << "min pack final score: " << final_score << " start_score: " << start_score << std::endl;
974 
975 }
976 
978  Size resid,
979  pose::Pose const & pose,
980  scoring::ScoreFunction const & sfxn,
982 )
983 {
984  using namespace pose;
985  using namespace scoring;
986  using namespace graph;
987  using namespace interaction_graph;
988 
989  bool discrepancy( false );
990  static int n_discreps( 0 );
991 
992  EnergyMap const & one_body_emap( pose.energies().onebody_energies( resid ));
993  Real onebody_energy = sfxn.weights().dot( one_body_emap );
994  Real sig_onebody_energy = ig.get_simple_node( resid )->proposed_one_body_energy();
995 
996  if ( std::abs( onebody_energy - sig_onebody_energy ) > 1e-5 ) {
997  std::cout << " onebody energy discrepancy: " << onebody_energy << " " << sig_onebody_energy << " " << onebody_energy - sig_onebody_energy << std::endl;
998  }
999 
1000  /*for ( Size kk = 1; kk <= total_score; ++kk ) {
1001  ScoreType kkst = ScoreType(kk);
1002  if ( sfxn.weights()[ kkst ] != 0.0 ) {
1003  if ( std::abs( one_body_emap[ kkst ] - min_node_1b[ kkst ] ) > 1e-10 ) {
1004  std::cout << " one body discrepancy " << kkst << ": " << one_body_emap[ kkst ] << " " << min_node_1b[ kkst ] << std::endl;
1005  }
1006  }
1007  }*/
1008 
1009  EnergyGraph const & eg( pose.energies().energy_graph() );
1010  for ( Node::EdgeListConstIter iter = eg.get_node(resid)->const_edge_list_begin(),
1011  iter_end = eg.get_node(resid)->const_edge_list_end();
1012  iter != iter_end; ++iter ) {
1013  Size ii( (*iter)->get_first_node_ind() );
1014  Size jj( (*iter)->get_second_node_ind() );
1015  if ( ii != resid && jj != resid ) continue; // only compare nodes that are involved in the current optimization
1016  SimpleEdge const * simple_edge = static_cast< SimpleEdge const * > ( ig.find_edge( ii, jj ) );
1017  EnergyEdge const * eedge = static_cast< EnergyEdge const * > ( *iter );
1018  EnergyMap emap = eedge->fill_energy_map();
1019  Real edge_energy = sfxn.weights().dot( emap );
1020  if ( ! simple_edge ) {
1021  std::cout << "Simple edge " << ii << " " << jj << " missing from simple interaction graph" << std::endl;
1022  emap.show_if_nonzero_weight( std::cout, pose.energies().weights() );
1023  std::cout << std::endl;
1024  Real delta = emap.dot( pose.energies().weights() );
1025  if ( delta > 0 ) {
1026  discrepancy = true;
1027  }
1028  continue;
1029  } else {
1030  Real ig_edge_energy = simple_edge->get_proposed_energy();
1031  if ( std::abs( edge_energy - ig_edge_energy ) > 1e-5 ) {
1032  std::cout << " twobody energy discrepancy: " << ii << " " << jj << " " << edge_energy << " " << ig_edge_energy << " " << edge_energy - ig_edge_energy << std::endl;
1033  }
1034  }
1035  }
1036 
1037  if ( discrepancy ) {
1038  ++n_discreps;
1039  pose.dump_pdb( "discrepancy_pose_" + utility::to_string( n_discreps ) + ".pdb" );
1040  }
1041 
1042 }
1043 
1044 /// @details Returns the rotamer index (1 for the current rotamer) for a randomly assigned rotamer
1045 Size
1047  rotamer_set::ContinuousRotamerSet const & rotset,
1049  Size ranrot_on_moltenres
1050 )
1051 {
1052  Size const ran_rotblock_for_ranrot( rotset.get_rotblock_index_for_sampling_rotamer( ranrot_on_moltenres ) );
1053  resatc.set_active_restype_index( ran_rotblock_for_ranrot );
1054  if ( ranrot_on_moltenres == rotset.sampling_id_for_current_rotamer() ) {
1055  resatc.set_rescoords( rotset.current_rotamer_coords() );
1056  //return set_current_rotamer_for_moltres( ran_moltres, rotsets, atc );
1057  return 1 + rotset.get_n_baserotamers_for_rotblock( ran_rotblock_for_ranrot );
1058  } else {
1059  /// resatc.idealize_active_restype(); -- need this if we ever allow the input sidechain!
1060  if ( rotset.get_n_baserotamers_for_rotblock( ran_rotblock_for_ranrot ) != 0 ) {
1061  // i.e. not gly or ala.
1062  Real rand_btw_0_and_1 = RG.uniform();
1063  Size const ran_baserot_ind = rotset.pick_baserotamer_from_rotblock( ran_rotblock_for_ranrot, rand_btw_0_and_1 );
1064  dunbrack::DunbrackRotamerSampleData const & rotdata =
1065  rotset.baserotamer_data( ran_rotblock_for_ranrot, ran_baserot_ind );
1066  /// OK: now, sample the dunbrack chi
1067  for ( Size ii = 1; ii <= rotdata.nchi(); ++ii ) {
1068  /// First attempt strategy: sample uniformly +/- 1 standard deviation
1069  Real const iichi_randval = RG.uniform();
1070  Real const iisd = rotdata.chi_sd()[ ii ];
1071  resatc.set_chi( ii, rotdata.chi_mean()[ii] - iisd + 2 * iisd * iichi_randval );
1072  }
1073  }
1074  chemical::ResidueTypeCOP ran_restype( rotset.restype_for_rotblock( ran_rotblock_for_ranrot ));
1075  for ( Size ii = 1; ii <= ran_restype->n_proton_chi(); ++ii ) {
1076  Size ii_chi = ran_restype->proton_chi_2_chi( ii );
1077  utility::vector1< Real > const & ii_chi_samples = ran_restype->proton_chi_samples( ii );
1078  utility::vector1< Real > const & ii_chi_extra_samples = ran_restype->proton_chi_extra_samples( ii );
1079 
1080  // assume extra samples has its largest value in the last position
1081  Real iichi_sdev = ii_chi_extra_samples[ ii_chi_extra_samples.size() ];
1082 
1083  Real rand_btw_0_and_1 = RG.uniform();
1084  Size sample = static_cast< Size > ( ii_chi_samples.size() * rand_btw_0_and_1 ) + 1;
1085  Real sample_dev = RG.uniform();
1086  resatc.set_chi( ii_chi, ii_chi_samples[ sample ] - iichi_sdev + 2 * sample_dev * iichi_sdev );
1087  }
1088  resatc.update_residue();
1089  return ran_rotblock_for_ranrot;
1090  }
1091 }
1092 
1093 void
1095  pose::Pose & pose,
1096  scoring::ScoreFunction const & sfxn,
1097  task::PackerTaskCOP task
1098 )
1099 {
1100  /// 1. Create the classes that will be used in the stochastic packer
1101  //// (misc setup)
1102  /// a. The AtomTreeCollection
1103  /// b. The ContinuousRotamerSet
1104  /// c. The Packer Neighbor Graph / SimpleIG
1105  /// 2. Begin annealing
1106  /// a. Assign random sequence structure
1107  /// b. loop over temperatures
1108  /// c. loop over fixed temperature n iterations
1109  /// d. select residue to undergo substitution
1110  /// e. select residue type on that residue
1111  /// f. select random chi for that restype
1112  /// g. set coords for that residue
1113  /// h. compute new energy -> deltaE
1114  /// i. metropolis accept/reject
1115  /// j. restore previous state, or save new state
1116 
1117 #ifdef APL_FULL_DEBUG
1118  pose::Pose debug_pose( pose );
1119  sfxn( debug_pose );
1120 #endif
1121 
1122 
1123  // 1 (misc setup)
1124  Real start_score( sfxn( pose ) );
1125  pack_scorefxn_pose_handshake( pose, sfxn);
1126  sfxn.setup_for_packing( pose, task->repacking_residues(), task->designing_residues() );
1127 
1128  // 1a
1129  scmin::AtomTreeCollectionOP atc = new scmin::AtomTreeCollection( pose, *task );
1130 
1131  // 1b
1132  rotamer_set::ContinuousRotamerSets rotsets( pose, *task );
1133  Size const n_sample_rots = rotsets.n_sample_rotamers();
1134 
1135  // 1c
1137  ig.set_scorefunction( sfxn );
1138  ig.set_pose_no_initialize( pose );
1139  graph::GraphOP packer_neighbor_graph = create_packer_graph( pose, sfxn, task );
1140  //for ( Size ii = 1; ii <= pose.total_residue(); ++ii ) {
1141  // ig.get_simple_node( ii )->set_current( pose.residue( ii ).clone() );
1142  //}
1143  ig.copy_connectivity( *packer_neighbor_graph );
1144 
1145  /// 2.
1147  scmin::SidechainStateAssignment curr_state( rotsets.nmoltenres() ), best_state( rotsets.nmoltenres() );
1148 
1149  for ( Size ii = 1; ii <= temps.size(); ++ii ) {
1150  Real ii_temperature = temps[ ii ];
1151  /// 6.
1152  Size naccepts( 0 );
1153  Real accum_deltaE( 0 );
1154  Size const jj_end = 5 * n_inner_iterations( ii_temperature, n_sample_rots );
1155  for ( Size jj = 1; jj <= jj_end; ++jj ) {
1156 
1157  Size const random_sample_rot = static_cast< Size > ( n_sample_rots * RG.uniform() + 1 );
1158  Size const ran_moltres = rotsets.moltenres_for_sample_rot( random_sample_rot );
1159  Size const ran_res = rotsets.moltenresid_2_resid( ran_moltres );
1160  Size const ranrot_on_moltenres = rotsets.full_sample_rot_index_2_moltenres_sample_rot_index( random_sample_rot );
1161 
1162  Size const ranrot_baserot_id = assign_random_continuous_rotamer(
1163  rotsets.rotamer_set_for_moltenres( ran_moltres ),
1164  atc->moltenres_atomtree_collection( ran_moltres),
1165  ranrot_on_moltenres );
1166 
1167  Real const neg_deltaE = ig.consider_substitution( ran_res, atc->moltenres_atomtree_collection( ran_moltres ).active_residue_cop() );
1168  Real const deltaE = -1 * neg_deltaE;
1169 
1170 #ifdef APL_FULL_DEBUG
1171  Real curE = sfxn( debug_pose );
1172  debug_pose.replace_residue( ran_res, atc->moltenres_atomtree_collection( ran_moltres ).active_residue(), false );
1173  Real altE = sfxn( debug_pose );
1174  Real actual_deltaE = altE - curE;
1175  if ( ! curr_state.any_unassigned() && std::abs( actual_deltaE - deltaE ) > 1e-5 ) {
1176  std::cout << "DeltaE discrepancy replacing residue " << ran_res << " "
1177  << actual_deltaE << " " << deltaE << " " << actual_deltaE - deltaE << std::endl;
1178  compare_simple_inteaction_graph_alt_state_and_energy_graph( ran_res, debug_pose, sfxn, ig );
1179  }
1180 #endif
1181 
1182 
1183  if ( curr_state.any_unassigned() || pass_metropolis( ii_temperature, deltaE ) ) {
1184  /// Accept the substitution
1185  ++naccepts;
1186  accum_deltaE += deltaE;
1187  ig.commit_change( ran_res );
1188 
1189  /// Before assigning the state, write down: do we have extra bookkeeping we need to worry about?
1190  bool const any_previously_unassigned = curr_state.any_unassigned();
1191  bool const last_unassigned_assigned = any_previously_unassigned &&
1192  curr_state.orig_rotamer_id_for_moltenres( ran_moltres ) == 0 &&
1193  curr_state.n_unassigned() == 1;
1194 
1195  /// always record the new state
1196  atc->moltenres_atomtree_collection( ran_moltres ).save_momento( curr_state.state_momento( ran_moltres ) );
1197  curr_state.assign_state( ran_moltres, ranrot_baserot_id );
1198 
1199  if ( any_previously_unassigned ) {
1200  if ( last_unassigned_assigned ) {
1201  /// This is the last un-assigned residue that needs assigning; save the total energy for current & best
1202  Real totalE = ig.total_energy();;
1203  curr_state.assign_energy( totalE );
1204  best_state = curr_state;
1205  }
1206  } else {
1207  Real alt_totalE = curr_state.energy() + deltaE;
1208  curr_state.assign_energy( alt_totalE );
1209 
1210  if ( curr_state.energy() < best_state.energy() ) {
1211  Real totalE = ig.total_energy(); //get_total_energy_for_state( pose, bgres, sfxn, *mingraph, *scminmap, curr_state, atc, *rotsets );
1212  assert( std::abs( totalE - curr_state.energy() ) < 1e-5 ); // drift does accumulate, but it should be small!
1213  curr_state.assign_energy( totalE );
1214  if ( totalE < best_state.energy() ) {
1215  best_state = curr_state;
1216  //std::cout << "Accepted new best " << best_state.energy() << " " << totalE << " discrepancy: " << best_state.energy() - totalE << std::endl;
1217  }
1218  }
1219 
1220  }
1221  //Real totalE = ig.total_energy(); //get_total_energy_for_state( pose, bgres, sfxn, *mingraph, *scminmap, curr_state, atc, *rotsets );
1222  //if( ! curr_state.any_unassigned() && std::abs( totalE - curr_state.energy() ) > 1e-5 ) {
1223  // std::cout << "Disagreement between totalE and curr_state.energy() " << totalE << " " << curr_state.energy() << " diff " << totalE - curr_state.energy() << std::endl;
1224  //}
1225  } else {
1226  // reject; restore the old residue
1227  atc->moltenres_atomtree_collection( ran_moltres ).update_from_momento( curr_state.momento_for_moltenres( ran_moltres ) );
1228  ig.reject_change( ran_res );
1229 #ifdef APL_FULL_DEBUG
1230  debug_pose.replace_residue( ran_res, atc->moltenres_atomtree_collection( ran_moltres ).active_residue(), false );
1231 #endif
1232  }
1233  }
1234  std::cout << "Finished temperature " << ii_temperature << " with energy " << curr_state.energy() << " and best energy " << best_state.energy()
1235  << " accept rate: " << ((double) naccepts )/ jj_end << " avg deltaE: " << accum_deltaE / ( naccepts == 0 ? 1 : naccepts ) << std::endl;
1236 
1237  }
1238 
1239  /// 8.
1240  for ( Size ii = 1; ii <= rotsets.nmoltenres(); ++ii ) {
1241  Size iiresid = rotsets.moltenresid_2_resid( ii );
1242  atc->moltenres_atomtree_collection( ii ).update_from_momento( best_state.momento_for_moltenres( ii ) );
1243  pose.replace_residue( iiresid, atc->moltenres_atomtree_collection( ii ).active_residue(), false );
1244  }
1245 
1246  Real final_score( sfxn( pose ) );
1247  TR << "stochastic pack final score: " << final_score << " start_score: " << start_score << std::endl;
1248 
1249 }
1250 
1251 
1252 } // namespace pack
1253 } // namespace core
1254