Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GreenPacker.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/simple_moves/GreenPacker.cc
11 /// @brief packing mover that makes extensive reuse of rotamer pair energies class definition
12 /// @author Andrew Leaver-Fay (aleaverfay@gmail.com)
13 
14 /// Unit headers
16 
17 /// Core headers
21 #include <core/graph/Graph.hh>
30 #include <core/pose/Pose.hh>
33 #include <core/scoring/Energies.hh>
36 
37 #include <basic/basic.hh>
38 #include <basic/Tracer.hh>
39 
40 /// Numeric headers
41 #include <numeric/numeric.functions.hh>
42 #include <numeric/constants.hh>
43 #include <numeric/xyz.functions.hh>
44 
45 /// Utility headers
46 #include <utility/vector1.functions.hh>
47 
48 /// C++ Headers
49 // AUTO-REMOVED #include <ctime>
50 
51 #include <utility/vector0.hh>
52 #include <utility/vector1.hh>
53 
54 
55 namespace protocols {
56 namespace simple_moves {
57 
58 /// @details Auto-generated virtual destructor
60 
61 basic::Tracer TR("protocols.simple_moves.GreenPacker");
62 
64  residue_type_( res.type() ),
65  ideal_geometry_( false )
66 {
67  if ( has_ideal_geometry( res ) ) {
68  ideal_geometry_ = true;
69  record_chi( res );
70  } else {
71  ideal_geometry_ = false;
73  }
74 }
75 
76 bool
78  core::conformation::Residue const & res
79 ) const
80 {
81  for ( Size ii = res.type().first_sidechain_atom(); ii <= res.type().nheavyatoms(); ++ii ) {
82  if ( ! atom_is_ideal( res, ii ) ) {
83  return false;
84  }
85  for ( Size jj = res.type().attached_H_begin( ii );
86  jj <= res.type().attached_H_end( ii ); ++jj ) {
87  if ( ! atom_is_ideal( res, jj ) ) {
88  return false;
89  }
90  }
91  }
92  return true;
93 }
94 
95 /// @details Assumption: sidechain ideal coordinates do not depend on other residues
96 /// ( as opposed to the backbone O for example, which depends on the coordinates of i+1.)
97 bool
99  core::conformation::Residue const & res,
100  Size const atom_id
101 ) const
102 {
103  core::chemical::AtomICoor const & atom_icoor( res.type().icoor( atom_id ) );
104  Size st1 = atom_icoor.stub_atom1().atomno();
105  Size st2 = atom_icoor.stub_atom2().atomno();
106  Size st3 = atom_icoor.stub_atom2().atomno();
107 
108  Real const ideal_d = atom_icoor.d();
109  if ( std::abs( res.xyz( atom_id ).distance( res.xyz( st1 ) ) - ideal_d ) > 1e-8 ) {
110  //TR << "Failed atom is ideal: " << res.name() << " " << res.atom_name( atom_id ) << " d: ";
111  //TR << res.xyz( atom_id ).distance( res.xyz( st1 ) ) << " ideal: " << ideal_d << std::endl;
112  return false;
113  }
114 
115  /// It turns out that the CB placement on non-ideal backbones is almost uniformly non-ideal.
116  /// It might be nice to special-case CB, describing the sidechain geometry as a (set of?)
117  /// backbone-to-sidechain non-ideal-geometry (ies), and chi-angles for ideal geometry thereafter.
118  /// The profiler doesn't show much time spent in determining the correspondence between
119  /// rotamer sets... looping on GreenPacker->apply, 0.0% is spent in
120  /// GreenPacker::find_current_and_original_rotamer_correspondence. The time spent in "same"
121  /// is clearly minimal, and so the only gain of switching to the above-described representation
122  /// would be a memory savings...
123  Real const ideal_theta = atom_icoor.theta();
124  Real const actual_theta = numeric::constants::d::pi - numeric::angle_radians(
125  res.xyz( atom_id ),
126  res.xyz( st1 ),
127  res.xyz( st2 ) );
128  if ( std::abs( actual_theta - ideal_theta ) > 1e-8 ) {
129  //TR << "Failed atom is ideal: " << res.name() << " " << res.atom_name( atom_id ) << " theta: ";
130  //TR << actual_theta << " ideal: " << ideal_theta << std::endl;
131  return false;
132  }
133 
134  bool atom_is_last_for_some_chi = false;
135  for ( Size ii = 1; ii <= res.type().nchi(); ++ii ) {
136  if ( res.type().chi_atoms( ii )[ 4 ] == atom_id ) {
137  atom_is_last_for_some_chi = true;
138  break;
139  }
140  }
141  if ( ! atom_is_last_for_some_chi ) {
142  Real const ideal_phi = atom_icoor.phi();
143  Real const actual_phi = numeric::dihedral_radians(
144  res.xyz( atom_id ),
145  res.xyz( st1 ),
146  res.xyz( st2 ),
147  res.xyz( st3 )
148  );
149  if ( std::abs( basic::periodic_range( actual_phi - ideal_phi, numeric::constants::d::pi ) ) > 1e-8 ) {
150 
151  //TR << "Failed atom is ideal: " << res.name() << " " << res.atom_name( atom_id ) << " phi: ";
152  //TR << actual_phi << " ideal: " << ideal_phi << " diff: " << basic::periodic_range( actual_phi - ideal_phi, numeric::constants::d::pi ) << std::endl;
153 
154  return false;
155  }
156  }
157  return true;
158 }
159 
160 void
162 {
163  chi_.resize( res.type().nchi() );
164  for ( Size ii = 1; ii <= chi_.size(); ++ii ) {
165  assert( chi_matches_coords( res, ii ));
166  chi_[ ii ] = res.chi( ii );
167  }
168 }
169 
170 /// @details only record internal geometry for sidechain atoms
171 void
173 {
174  internal_geometry_.resize( res.natoms(), Vector(0,0,0) );
175  for ( Size ii = res.type().first_sidechain_atom(); ii <= res.type().nheavyatoms(); ++ii ) {
176  record_internal_geometry( res, ii );
177  for ( Size jj = res.type().attached_H_begin( ii );
178  jj <= res.type().attached_H_end( ii ); ++jj ) {
179  record_internal_geometry( res, jj );
180  }
181  }
182 }
183 
184 void
186  core::conformation::Residue const & res,
187  Size const atom_id
188 )
189 {
190  core::chemical::AtomICoor const & atom_icoor( res.type().icoor( atom_id ) );
191  Size st1 = atom_icoor.stub_atom1().atomno();
192  Size st2 = atom_icoor.stub_atom2().atomno();
193  Size st3 = atom_icoor.stub_atom2().atomno();
194 
195  Real actual_d = res.xyz( atom_id ).distance( res.xyz( st1 ) );
196  internal_geometry_[ atom_id ][ d ] = actual_d;
197 
198  /// Don't bother subtracing pi -- just don't try to construct a rotamer using this "proper" theta
199  /// (as opposed to the canonical improper bond angle...)
200  Real const actual_theta = numeric::angle_radians(
201  res.xyz( atom_id ),
202  res.xyz( st1 ),
203  res.xyz( st2 ) );
204  internal_geometry_[ atom_id ][ theta ] = actual_theta;
205 
206  Real const actual_phi = numeric::dihedral_radians(
207  res.xyz( atom_id ),
208  res.xyz( st1 ),
209  res.xyz( st2 ),
210  res.xyz( st3 )
211  );
212  internal_geometry_[ atom_id ][ phi ] = actual_phi;
213 }
214 
215 bool
217 {
218  core::chemical::AtomIndices const & chi_atoms( res.type().chi_atoms( chi_index ) );
219  assert( chi_atoms.size() == 4 );
220  Real const actual_chi = numeric::dihedral_degrees(
221  res.xyz( chi_atoms[ 1 ] ),
222  res.xyz( chi_atoms[ 2 ] ),
223  res.xyz( chi_atoms[ 3 ] ),
224  res.xyz( chi_atoms[ 4 ] )
225  );
226  if ( std::abs( basic::periodic_range( actual_chi - res.chi( chi_index ), 180 ) ) > 1e-8 ) {
227  return false;
228  }
229  return true;
230 }
231 
232 bool
233 MinimalRotamer::same( MinimalRotamer const & other ) const
234 {
235  //TR << "same ? " << residue_type_.name() << " " << other.residue_type_.name() << " " << ideal_geometry_ << " " << other.ideal_geometry_ << std::endl;
236 
237 
238  /// pointer comparison
239  if ( & residue_type_ != & other.residue_type_ ) return false;
240 
241  if ( ideal_geometry_ && other.ideal_geometry_ ) {
242  return same_chi( other );
243  } else if ( ! ideal_geometry_ && ! other.ideal_geometry_ ) {
244  return same_nonideal_geometry( other );
245  }
246 
247  /// else, one is ideal and the other is not
248  return false;
249 }
250 
251 /// @detail This tolerance may need fiddling with
252 bool
254 {
255  assert( ideal_geometry_ && other.ideal_geometry_ );
256  assert( chi_.size() == other.chi_.size() );
257  for ( Size ii = 1; ii <= chi_.size(); ++ii ) {
258  if ( std::abs( basic::periodic_range( chi_[ ii ] - other.chi_[ ii ], 180 ) ) > 1e-8 ) {
259  //TR << "same chi failed: " << residue_type_.name() << " " << other.residue_type_.name() << " " << ii << " " << chi_[ ii ] << " " << other.chi_[ ii ] << " " << basic::periodic_range( chi_[ ii ] - other.chi_[ ii ], 180 ) << std::endl;
260  return false;
261  }
262  }
263  //TR << "SAME!" << std::endl;
264  return true;
265 }
266 
267 /// @detail These tolerances may need fiddling with
268 bool
270 {
271  assert( !ideal_geometry_ && !other.ideal_geometry_ );
272  assert( internal_geometry_.size() == other.internal_geometry_.size() );
273  for ( Size ii = 1; ii <= internal_geometry_.size(); ++ii ) {
274  if ( std::abs( internal_geometry_[ ii ][ d ] - other.internal_geometry_[ ii ][ d ] ) > 1e-8 ) {
275  //TR << "same nonideal geometry d failed: " << residue_type_.name() << " " << other.residue_type_.name() << " " << ii << " " << internal_geometry_[ ii ][ d ] << " " << other.internal_geometry_[ ii ][ d ] << " " << internal_geometry_[ ii ][ d ] - other.internal_geometry_[ ii ][ d ] << std::endl;
276  return false;
277  }
278  if ( std::abs( internal_geometry_[ ii ][ theta ] - other.internal_geometry_[ ii ][ theta ] ) > 1e-8 ) {
279  //TR << "same nonideal geometry theta failed: " << residue_type_.name() << " " << other.residue_type_.name() << " " << ii << " " << internal_geometry_[ ii ][ theta ] << " " << other.internal_geometry_[ ii ][ theta ] << " " << internal_geometry_[ ii ][ theta ] - other.internal_geometry_[ ii ][ theta ] << std::endl;
280  return false;
281  }
282 
283  if ( std::abs( basic::periodic_range(
284  internal_geometry_[ ii ][ phi ] - other.internal_geometry_[ ii ][ phi ],
285  numeric::constants::d::pi ) ) > 1e-8 ) {
286  //TR << "same nonideal geometry phi failed: " << residue_type_.name() << " " << other.residue_type_.name() << " " << ii << " " << internal_geometry_[ ii ][ phi ] << " " << other.internal_geometry_[ ii ][ phi ] << " " <<
287  // basic::periodic_range( internal_geometry_[ ii ][ phi ] - other.internal_geometry_[ ii ][ phi ], numeric::constants::d::pi ) << std::endl;
288  return false;
289  }
290  }
291  //TR << "SAME!" << std::endl;
292  return true;
293 }
294 
295 
296 bool
298  MinimalRotamer const & other
299 ) const
300 {
301  //TR << "same residue type ? " << residue_type_.name() << " " << other.residue_type_.name() << std::endl;
302  return ( & residue_type_ == & other.residue_type_ );
303 }
304 
307 {
308  return residue_type_.aa();
309 }
310 
311 ///// Group Discriminators
312 
314 
316 
318 {
319  return new ChainGroupDiscriminator;
320 }
321 
323 ChainGroupDiscriminator::group_id( Pose const & pose, Size seqpos ) const
324 {
325  return pose.residue( seqpos ).chain();
326 }
327 
328 
329  //////////////////////////////////////////////////////////////////////
331 
333 {
335 }
336 
339  return group_ids_[ seqpos ];
340 }
341 
342 void
344  group_ids_ = group_ids_input;
345 }
346 
347 /// Green Packer
348 
349 GreenPacker::GreenPacker() : create_reference_data_( true ) {}
350 
352 
353 
354 void
356 {
357  clock_t starttime = clock();
358  if ( create_reference_data_ ) {
359  setup_reference_data( pose );
360  }
361  repack( pose );
362  clock_t stoptime = clock();
363  TR << "Green Packer took: " << ((double) stoptime-starttime) / CLOCKS_PER_SEC << " seconds." << std::endl;
364 }
365 
368  return "GreenPacker";
369 }
370 
371 void
373 {
374  full_sfxn_ = new ScoreFunction( sfxn );
375 
376  /// create context independent and context dependent versions of this score function
377  ci_sfxn_ = new ScoreFunction;
378  cd_sfxn_ = new ScoreFunction;
379 
380  set_weights_for_sfxn( *ci_sfxn_, full_sfxn_->ci_2b_types(), full_sfxn_->weights() );
381  set_weights_for_sfxn( *ci_sfxn_, full_sfxn_->ci_1b_types(), full_sfxn_->weights() );
382  set_weights_for_sfxn( *ci_sfxn_, full_sfxn_->ci_lr_2b_types(), full_sfxn_->weights() );
383 
384  set_weights_for_sfxn( *cd_sfxn_, full_sfxn_->cd_2b_types(), full_sfxn_->weights() );
385  set_weights_for_sfxn( *cd_sfxn_, full_sfxn_->cd_1b_types(), full_sfxn_->weights() );
386  set_weights_for_sfxn( *cd_sfxn_, full_sfxn_->cd_lr_2b_types(), full_sfxn_->weights() );
387 
388  create_reference_data_ = true;
389 }
390 
391 void
393  ScoreFunction & sfxn,
394  ScoreTypes const & scoretypes,
395  EnergyMap const & weights
396 ) const
397 {
398  for ( Size ii = 1; ii <= scoretypes.size(); ++ii ) {
399  sfxn.set_weight( scoretypes[ ii ], weights[ scoretypes[ ii ] ] );
400  }
401 }
402 
403 void
405 {
406  group_discriminator_ = discriminator;
407 }
408 
409 
410 /// @details Pointer copy, atm, since there's no good way to clone task factories
411 /// and all of their contents.
412 void
414 {
415  task_factory_ = factory;
416 }
417 
418 /// @details Pointer copy, atm, since there's no good way to clone task factories
419 /// and all of their contents.
420 void
422 {
423  reference_task_factory_ = factory;
424 }
425 
426 
427 
428 void
430 {
431  split_pose_into_groups( pose );
436  create_reference_data_ = false; // next time, we'll reuse these energies
437 }
438 
439 void
441 {
442  split_pose_into_groups( pose );
443  create_fresh_task( pose );
445  create_fresh_rotamers( pose );
447  compute_energies( pose );
448  run_sa( pose );
449  cleanup();
450 }
451 
452 
453 void
455  core::pose::Pose & pose
456 )
457 {
458  group_ids_.resize( pose.total_residue() );
459  for ( Size ii = 1; ii <= pose.total_residue(); ++ii ) {
460  group_ids_[ ii ] = group_discriminator_->group_id( pose, ii );
461  }
462  Size max_group_id = utility::max( group_ids_ );
463  group_members_.resize( max_group_id + 1 );
464  for ( Size ii = 1; ii <= pose.total_residue(); ++ii ) {
465  group_members_[ group_ids_[ ii ] ].push_back( ii );
466  }
467 }
468 
469 void
471  core::pose::Pose & pose
472 )
473 {
474  reference_task_ = reference_task_factory_->create_task_and_apply_taskoperations( pose );
475 
478  ci_sfxn_->setup_for_packing( pose, reference_task_->repacking_residues(), reference_task_->designing_residues() );
479 
480 }
481 
482 // @details So that bump check does not throw out rotamers that collide only with residues
483 // in other groups, throw out edges from the packer neighbor graph that span groups.
484 void
486  core::pose::Pose & pose
487 )
488 {
491 }
492 
493 void
495  core::pose::Pose & pose
496 )
497 {
498  using namespace core::pack::rotamer_set;
499 
503 
504  reference_rotamer_sets_->prepare_sets_for_packing( pose, *ci_sfxn_ );
505 
506 
507  /// Now create images of the internal geometry for each of the rotamers created.
508  original_rotamers_.resize( pose.total_residue() );
509 
512  std::fill( reference_resid_2_moltenres_.begin(), reference_resid_2_moltenres_.end(), 0 );
513 
514  for ( Size ii = 1; ii <= reference_rotamer_sets_->nmoltenres(); ++ii ) {
515  Size const ii_resid = reference_rotamer_sets_->moltenres_2_resid( ii );
516  Size const ii_nrots = reference_rotamer_sets_->rotamer_set_for_moltenresidue( ii )->num_rotamers();
517  original_rotamers_[ ii_resid ].reserve( ii_nrots );
518 
519  reference_moltenres_2_resid_[ ii ] = ii_resid;
520  reference_resid_2_moltenres_[ ii_resid ] = ii;
521 
522  for ( Size jj = 1; jj <= ii_nrots; ++jj ) {
523  original_rotamers_[ ii_resid ].push_back(
525  *reference_rotamer_sets_->rotamer_set_for_moltenresidue( ii )->rotamer( jj ) ) );
526  }
527  }
528 }
529 
530 void
532  core::pose::Pose & pose
533 )
534 {
535  using namespace core::pack::interaction_graph;
536  InteractionGraphBaseOP ig = InteractionGraphFactory::create_interaction_graph(
538 
540  dynamic_cast< PrecomputedPairEnergiesInteractionGraph * > (
541  ig.get() ));
542 
543  /// if the dynamic cast failed, then the packer task has produced
544  /// an on the fly interaction graph (or some other non-precomputed IG
545  /// that hadn't been invented by 4/18/2008) which makes the GreenPacker
546  /// pointless... just because it's pointless doesn't mean it should fail,
547  /// though, so this code should be revised in the future.
548  if ( ! pig ) {
549  utility_exit_with_message( "GreenPacker asked to use on-the-fly interaction graph. Why?" );
550  }
551  pig->initialize( *reference_rotamer_sets_ );
552 
553  reference_rotamer_sets_->precompute_two_body_energies(
554  pose,
555  *ci_sfxn_,
557  pig
558  );
559 
560  ci_rpes_ = pig;
561 
562  /// get rid of unneeded data
563  reference_task_ = 0;
566 
567 }
568 
569 void
571  core::pose::Pose & pose
572 )
573 {
574  current_task_ = task_factory_->create_task_and_apply_taskoperations( pose );
575 
578  full_sfxn_->setup_for_packing( pose, current_task_->repacking_residues(), current_task_->designing_residues() );
579 
580 }
581 
582 void
584  core::pose::Pose & pose
585 )
586 {
592 }
593 
594 /// @details All edges to group 0 are considered inter-group edges.
595 void
597  core::pose::Pose & pose,
598  core::graph::GraphOP packer_neighbor_graph
599 ) const
600 {
601  for ( Size ii = 1; ii <= pose.total_residue(); ++ii ) {
602  Size const ii_grp = group_ids_[ ii ];
603  for ( Graph::EdgeListIter
604  iru = packer_neighbor_graph->get_node(ii)->upper_edge_list_begin(),
605  irue = packer_neighbor_graph->get_node(ii)->upper_edge_list_end();
606  iru != irue; /* no increment */ ) {
607  Graph::EdgeListIter irunext = iru;
608  ++irunext;
609  if ( ii_grp != group_ids_[ (*iru)->get_second_node_ind() ] ||
610  ii_grp == 0 /* implies other group also 0*/ ) {
611  packer_neighbor_graph->delete_edge( *iru ); // invalidates iterator
612  }
613  iru = irunext; // increment;
614  }
615  }
616 }
617 
618 /// @details All edges to group 0 are considered inter-group edges.
619 void
621  core::pose::Pose & pose,
622  core::graph::GraphOP packer_neighbor_graph
623 ) const
624 {
625  for ( Size ii = 1; ii <= pose.total_residue(); ++ii ) {
626  Size const ii_grp = group_ids_[ ii ];
627  for ( Graph::EdgeListIter
628  iru = packer_neighbor_graph->get_node(ii)->upper_edge_list_begin(),
629  irue = packer_neighbor_graph->get_node(ii)->upper_edge_list_end();
630  iru != irue; /* no increment */ ) {
631  Graph::EdgeListIter irunext = iru;
632  ++irunext;
633  if ( ii_grp == group_ids_[ (*iru)->get_second_node_ind() ] &&
634  ii_grp != 0 &&
635  group_ids_[ (*iru)->get_second_node_ind() ] != 0 ) {
636  packer_neighbor_graph->delete_edge( *iru ); // invalidates iterator
637  }
638  iru = irunext; // increment;
639  }
640  }
641 }
642 
643 
644 void
646  core::pose::Pose & pose
647 )
648 {
652  current_rotamer_sets_->prepare_sets_for_packing( pose, *full_sfxn_ );
653 
654  /// Now create images of the internal geometry for each of the rotamers created.
655  current_rotamers_.resize( pose.total_residue() );
656 
657  for ( Size ii = 1; ii <= current_rotamer_sets_->nmoltenres(); ++ii ) {
658  Size const ii_resid = current_rotamer_sets_->moltenres_2_resid( ii );
659  Size const ii_nrots = current_rotamer_sets_->rotamer_set_for_moltenresidue( ii )->num_rotamers();
660  current_rotamers_[ ii_resid ].reserve( ii_nrots );
661 
662  for ( Size jj = 1; jj <= ii_nrots; ++jj ) {
663  current_rotamers_[ ii_resid ].push_back(
665  *current_rotamer_sets_->rotamer_set_for_moltenresidue( ii )->rotamer( jj ) ) );
666  }
667  }
668 }
669 
670 void
672  core::pose::Pose & pose
673 )
674 {
675  using namespace core::pack::rotamer_set;
677 
678  /// Assumption: if rotamer i of the original rotamers and rotamer j of the current rotamers match,
679  /// then if rotamers i+1 and rotamers j+1 do not match and i and i+1 have the same amino acid type,
680  /// then i+1 will not match any rotamer in the current rotamer set.
681  /// O(N) algorithm. Optimal for O(NlgN) with a sort.
682  Size correspondences_found( 0 );
683  for ( Size ii = 1; ii <= pose.total_residue(); ++ii ) {
684  Size const ii_moltenresid = current_rotamer_sets_->resid_2_moltenres( ii );
685  //TR << "find correspondences for residue " << ii << " " << ii_moltenresid << std::endl;
686  if ( ii_moltenresid == 0 ) continue;
687 
688  RotamerSetCOP iirotset = current_rotamer_sets_->rotamer_set_for_residue( ii );
689 
690  Size const ii_orig_nrots = orig_rot_2_curr_rot_[ ii ].size();
691  Size const ii_curr_nrots = curr_rot_2_orig_rot_[ ii ].size();
692 
693  //TR << "#orig rots: " << ii_orig_nrots << " #curr_rots: " << ii_curr_nrots << std::endl;
694 
695  Size orig_id( 1 ), curr_id( 1 );
696  bool orig_prev_restype_match( false );
697  Size ii_correspondences_found( 0 );
698  while ( orig_id <= ii_orig_nrots && curr_id <= ii_curr_nrots ) {
701  if ( orig_rot->same_residue_type( *curr_rot )) {
702  if ( orig_rot->same( *curr_rot ) ) {
703  curr_rot_2_orig_rot_[ ii ][ curr_id ] = orig_id;
704  orig_rot_2_curr_rot_[ ii ][ orig_id ] = curr_id;
705  //TR << "Correspondence found: increment both" << std::endl;
706  ++orig_id;
707  ++curr_id;
708  ++ii_correspondences_found;
709  } else {
710  //TR << "Increment original" << std::endl;
711  ++orig_id;
712  }
713  orig_prev_restype_match = true;
714  } else {
715  if ( orig_prev_restype_match ) {
716  if ( original_rotamers_[ ii ][ orig_id - 1 ]->same_residue_type( *curr_rot ) ) {
717  // orig has moved on to a new amino acid, and curr is on the same amino acid,
718  // no more matches expected of the curr amino acid type to the rotamers in orig
719  //TR << "Increment current" << std::endl;
720  ++curr_id;
721  continue;
722  }
723  }
724 
725  /// We've arrived in a tricky situation where orig and curr don't match residue-types,
726  /// and orig_prev was never found to have a restype match. The correspondence from
727  /// this point forward is not guaranteed optimal. It will definately be suboptimal if
728  /// ever curr_rots[ ii ]->aa() > curr_rots[ ii + 1]->aa().
729  /// Such a situation will only arise if you're appending rotamers to a rotamer set
730  /// in an out-of-order fashion... e.g. after adding rots for all 20 aa's, you add a few
731  /// extra arginine rots, then these rots won't be picked up as matching.
732  /// To avoid this situation from slowing your code, append extra rotamers inline:
733  /// add extra arginine rotamers as soon as the rotamer set has built its canonical arginine
734  /// rotamers but has not yet gone on to add rotamers for serine.
735  if ( orig_rot->aa() >= curr_rot->aa() ) {
736  //TR << "Increment current 2" << std::endl;
737  ++curr_id;
738  } else {
739  //TR << "Increment original 2" << std::endl;
740  ++orig_id;
741  orig_prev_restype_match = false;
742  }
743  }
744  } // end while
745  correspondences_found += ii_correspondences_found;
746  curr_rotamers_with_correspondence_[ ii ].reserve( ii_correspondences_found );
747  curr_rotamers_without_correspondence_[ ii ].reserve( ii_curr_nrots - ii_correspondences_found );
748  for ( Size jj = 1; jj <= ii_curr_nrots; ++jj ) {
749  if ( curr_rot_2_orig_rot_[ ii ][ jj ] != 0 ) {
750  curr_rotamers_with_correspondence_[ ii ].push_back( jj );
751  } else {
752  curr_rotamers_without_correspondence_[ ii ].push_back( jj );
753  }
754  }
755  }
756 
757  TR << "Found correspondence for " << correspondences_found;
758  TR << " rotamers out of " << current_rotamer_sets_->nrotamers() << std::endl;
759 }
760 
761 void
763  core::pose::Pose & pose
764 )
765 {
766  orig_rot_2_curr_rot_.clear(); orig_rot_2_curr_rot_.resize( pose.total_residue() );
767  curr_rot_2_orig_rot_.clear(); curr_rot_2_orig_rot_.resize( pose.total_residue() );
772 
773  for ( Size ii = 1; ii <= pose.total_residue(); ++ii ) {
774  Size const ii_moltenresid = current_rotamer_sets_->resid_2_moltenres( ii );
775  if ( ii_moltenresid != 0 ) {
776  orig_rot_2_curr_rot_[ ii ].resize( original_rotamers_[ ii ].size() );
777  std::fill( orig_rot_2_curr_rot_[ ii ].begin(), orig_rot_2_curr_rot_[ ii ].end(), 0 );
778  curr_rot_2_orig_rot_[ ii ].resize( current_rotamer_sets_->rotamer_set_for_moltenresidue( ii_moltenresid )->num_rotamers() );
779  std::fill( curr_rot_2_orig_rot_[ ii ].begin(), curr_rot_2_orig_rot_[ ii ].end(), 0 );
780  }
781  }
782 }
783 
784 void
786  core::pose::Pose & pose
787 )
788 {
789  using namespace core::pack::interaction_graph;
790  /// 0. Create an interaction graph
791  InteractionGraphBaseOP ig = InteractionGraphFactory::create_interaction_graph(
792  *current_task_,
794  pose,
795  *full_sfxn_ );
796 
798  dynamic_cast< PrecomputedPairEnergiesInteractionGraph * > (
799  ig.get() ));
800 
801  /// if the dynamic cast failed, then the packer task has produced
802  /// an on the fly interaction graph (or some other non-precomputed IG
803  /// that hadn't been invented by 4/18/2008) which makes the GreenPacker
804  /// pointless... just because it's pointless doesn't mean it should fail,
805  /// though, so this code should be revised in the future.
806  if ( ! pig ) {
807  utility_exit_with_message( "GreenPacker asked to use on-the-fly interaction graph. Why?" );
808  }
809  pig->initialize( *current_rotamer_sets_ );
810 
811 
812  /// 1. Compute all pair energies across the interface, and declare those edges final.
813  /// Let the rotamer sets class do all the hard work here...
814  current_rotamer_sets_->precompute_two_body_energies(
815  pose, *full_sfxn_,
817  );
818 
819  /// 2. Compute batch CD pair energies for intra-group edges
820  /// Let the rotamer sets class do all the hard work here...
821  current_rotamer_sets_->precompute_two_body_energies(
822  pose, *cd_sfxn_,
824  );
825 
826  /// 3. Add in CI pair energies for intra-group edges where both rotamers have a correspondence
827  add_precomputed_energies( pose, pig );
828 
829  /// 4. Compute CI pair energies for those rotamers lacking a correspondence.
830  compute_absent_energies( pose, pig );
831 
832  /// 5. Compute one-body energies
833  current_rotamer_sets_->compute_one_body_energies(
835 
836  current_ig_ = pig;
837 }
838 
839 void
841  core::pose::Pose & pose,
843 )
844 {
845  using namespace core::pack;
846  using namespace core::pack::interaction_graph;
847  for ( Size ii = 1; ii <= pose.total_residue(); ++ii ) {
848  Size const ii_moltenres_curr = current_rotamer_sets_->resid_2_moltenres( ii );
849  Size const ii_moltenres_orig = reference_resid_2_moltenres_[ ii ];
850 
851  if ( ii_moltenres_curr == 0 || ii_moltenres_orig == 0 ) continue;
852 
853  for ( ci_rpes_->reset_edge_list_iterator_for_node( ii_moltenres_orig );
854  ! ci_rpes_->edge_list_iterator_at_end();
855  ci_rpes_->increment_edge_list_iterator() ) {
856  EdgeBase const & edge( ci_rpes_->get_edge() );
857 
858  Size const jj_moltenres_orig = edge.get_other_ind( ii_moltenres_orig );
859  if ( jj_moltenres_orig < ii_moltenres_orig ) continue; // only deal with upper edges
860 
861  Size const jj = reference_moltenres_2_resid_[ jj_moltenres_orig ];
862  Size const jj_moltenres_curr = current_rotamer_sets_->resid_2_moltenres( jj );
863  if ( jj_moltenres_curr == 0 ) continue;
864 
865  assert( dynamic_cast< PrecomputedPairEnergiesEdge const * > ( & edge ) );
866 
867  PrecomputedPairEnergiesEdge const & precomp_edge(
868  static_cast< PrecomputedPairEnergiesEdge const & > ( edge ) );
869 
870  if ( !pig->get_edge_exists( ii_moltenres_curr, jj_moltenres_curr )) {
871  pig->add_edge( ii_moltenres_curr, jj_moltenres_curr );
872  }
873 
874  /// iterate across rotamer pairs with a correspondence.
875 
876  /// rename a few variables for brevity
879  utility::vector1< Size > const & ii_curr_2_orig( curr_rot_2_orig_rot_[ ii ] );
880  utility::vector1< Size > const & jj_curr_2_orig( curr_rot_2_orig_rot_[ jj ] );
881  Size ii_ncorr_rots = ii_corr_rots.size();
882  Size jj_ncorr_rots = jj_corr_rots.size();
883 
884  if ( ii_ncorr_rots == 0 || jj_ncorr_rots == 0 ) continue;
885 
886  for ( Size kk = 1; kk <= ii_ncorr_rots; ++kk ) {
887  Size const kk_curr_rot = ii_corr_rots[ kk ];
888  Size const kk_orig_rot = ii_curr_2_orig[ kk_curr_rot ];
889 
890  for ( Size ll = 1; ll <= jj_corr_rots.size(); ++ll ) {
891  Size const ll_curr_rot = jj_corr_rots[ ll ];
892  Size const ll_orig_rot = jj_curr_2_orig[ ll_curr_rot ];
893  core::PackerEnergy const kkll_energy = precomp_edge.get_two_body_energy( kk_orig_rot, ll_orig_rot );
894  pig->add_to_two_body_energies_for_edge(
895  ii_moltenres_curr, jj_moltenres_curr,
896  kk_curr_rot, ll_curr_rot,
897  kkll_energy );
898  }
899  }
900  }
901  }
902 }
903 
904 /// @details this time, iterate across edges in the packer neighbor graph
905 /// and compute pair interaction energies between rotamers that do not
906 /// correspond to any of the original rotamers with all other rotamers
907 /// in the neighboring set. This has to be careful not to double-count
908 /// interactions between rotamer pairs that both lack a correspondence.
909 void
911  core::pose::Pose & pose,
913 )
914 {
915  using namespace core::scoring;
916 
917  /// 1. Absent short ranged context independent two body energies
918  for ( Size ii = 1; ii <= pose.total_residue(); ++ii ) {
919  Size const ii_moltenres_curr = current_rotamer_sets_->resid_2_moltenres( ii );
920  if ( ii_moltenres_curr == 0 ) continue;
921 
922  Size const ii_nnew_rots = curr_rotamers_without_correspondence_[ ii ].size();
923  for ( Graph::EdgeListIter
924  iru = current_intra_group_packer_neighbor_graph_->get_node(ii)->upper_edge_list_begin(),
925  irue = current_intra_group_packer_neighbor_graph_->get_node(ii)->upper_edge_list_end();
926  iru != irue; ++iru ) {
927 
928  Size const jj = (*iru)->get_second_node_ind();
929  Size const jj_moltenres_curr = current_rotamer_sets_->resid_2_moltenres( jj );
930  if ( jj_moltenres_curr == 0 ) continue;
931 
932  Size const jj_nnew_rots = curr_rotamers_without_correspondence_[ jj ].size();
933 
934  if ( ii_nnew_rots == 0 && jj_nnew_rots == 0 ) continue; // AWESOME, no work to be done.
935 
936  if ( ! pig->get_edge_exists( ii_moltenres_curr, jj_moltenres_curr ) ) {
937  pig->add_edge( ii_moltenres_curr, jj_moltenres_curr );
938  }
940  }
941  }
942 
943  /// 2. Absent long ranged context independent two body energies
944  // Iterate across the long range energy functions and use the iterators generated
945  // by the LRnergy container object
947  lr_iter = ci_sfxn_->long_range_energies_begin(),
948  lr_end = ci_sfxn_->long_range_energies_end();
949  lr_iter != lr_end; ++lr_iter ) {
950  LREnergyContainerCOP lrec = pose.energies().long_range_container( (*lr_iter)->long_range_type() );
951  if ( !lrec || lrec->empty() ) continue; // only score non-emtpy energies.
952  // Potentially O(N^2) operation...
953 
954  for ( Size ii = 1; ii <= pose.total_residue(); ++ ii ) {
955  Size const ii_moltenres_curr = current_rotamer_sets_->resid_2_moltenres( ii );
956  if ( ii_moltenres_curr == 0 ) continue;
957  Size const ii_nnew_rots = curr_rotamers_without_correspondence_[ ii ].size();
958 
960  rni = lrec->const_upper_neighbor_iterator_begin( ii ),
961  rniend = lrec->const_upper_neighbor_iterator_end( ii );
962  (*rni) != (*rniend); ++(*rni) ) {
963  Size const jj = rni->upper_neighbor_id();
964 
965  Size const jj_moltenres_curr = current_rotamer_sets_->resid_2_moltenres( jj );
966  if ( jj_moltenres_curr == 0 ) continue;
967  Size const jj_nnew_rots = curr_rotamers_without_correspondence_[ jj ].size();
968 
969  if ( ii_nnew_rots == 0 && jj_nnew_rots == 0 ) continue; // AWESOME, no work to be done.
970 
971  if ( ! pig->get_edge_exists( ii_moltenres_curr, jj_moltenres_curr ) ) {
972  pig->add_edge( ii_moltenres_curr, jj_moltenres_curr );
973  }
974  compute_absent_lrci_energies_for_residue_pair( pose, **lr_iter, pig, ii, jj );
975 
976  }
977  }
978  }
979 
980 }
981 
982 void
984  core::pose::Pose & pose,
986  Size lower_res,
987  Size upper_res
988 )
989 {
990  using namespace core::conformation;
991  using namespace core::scoring;
992 
993  Size const lower_res_moltenresid = current_rotamer_sets_->resid_2_moltenres( lower_res );
994  assert( lower_res_moltenresid );
995 
996  Size const upper_res_moltenresid = current_rotamer_sets_->resid_2_moltenres( upper_res );
997  assert( upper_res_moltenresid );
998 
999  Size const lower_res_nrots = current_rotamer_sets_->nrotamers_for_moltenres( lower_res_moltenresid );
1000  Size const lower_res_nnew_rots = curr_rotamers_without_correspondence_[ lower_res ].size();
1001 
1002  Size const upper_res_nrots = current_rotamer_sets_->nrotamers_for_moltenres( upper_res_moltenresid );
1003  Size const upper_res_nnew_rots = curr_rotamers_without_correspondence_[ upper_res ].size();
1004 
1005  if ( lower_res_nnew_rots > 0 ) {
1006  for ( Size ii = 1; ii <= lower_res_nnew_rots; ++ii ) {
1007  Size ii_rot_index = curr_rotamers_without_correspondence_[ lower_res ][ ii ];
1008  ResidueCOP ii_rot = current_rotamer_sets_->rotamer_set_for_residue( lower_res )->rotamer( ii_rot_index );
1009  for ( Size jj = 1; jj <= upper_res_nrots; ++jj ) {
1010  EnergyMap emap;
1011  ResidueCOP jj_rot = current_rotamer_sets_->rotamer_set_for_residue( upper_res )->rotamer( jj );
1012  ci_sfxn_->eval_ci_2b( *ii_rot, *jj_rot, pose, emap );
1013  Real const weighted_energy = ci_sfxn_->weights().dot( emap );
1014  pig->add_to_two_body_energies_for_edge(
1015  lower_res_moltenresid, upper_res_moltenresid,
1016  ii_rot_index, jj, weighted_energy );
1017  }
1018  }
1019  }
1020 
1021  if ( upper_res_nnew_rots > 0 ) {
1022  for ( Size ii = 1; ii <= lower_res_nrots; ++ii ) {
1023 
1024  // Avoid double counting pair interactions by skipping the new rotamers of the lower residue,
1025  // since their interaction energies with the upper residue's rotamers have already been calculated
1026  if ( curr_rot_2_orig_rot_[ lower_res ][ ii ] == 0 ) continue;
1027 
1028  ResidueCOP ii_rot = current_rotamer_sets_->rotamer_set_for_residue( lower_res )->rotamer( ii );
1029  for ( Size jj = 1; jj <= upper_res_nnew_rots; ++jj ) {
1030  Size const jj_rot_index = curr_rotamers_without_correspondence_[ upper_res ][ jj ];
1031  EnergyMap emap;
1032  ResidueCOP jj_rot = current_rotamer_sets_->rotamer_set_for_residue( upper_res )->rotamer( jj_rot_index );
1033  ci_sfxn_->eval_ci_2b( *ii_rot, *jj_rot, pose, emap );
1034  Real const weighted_energy = ci_sfxn_->weights().dot( emap );
1035  pig->add_to_two_body_energies_for_edge(
1036  lower_res_moltenresid, upper_res_moltenresid,
1037  ii, jj_rot_index, weighted_energy );
1038  }
1039  }
1040  }
1041 
1042 }
1043 
1044 void
1046  core::pose::Pose & pose,
1049  Size lower_res,
1050  Size upper_res
1051 )
1052 {
1053  using namespace core::conformation;
1054  using namespace core::scoring;
1055 
1056  Size const lower_res_moltenresid = current_rotamer_sets_->resid_2_moltenres( lower_res );
1057  assert( lower_res_moltenresid );
1058 
1059  Size const upper_res_moltenresid = current_rotamer_sets_->resid_2_moltenres( upper_res );
1060  assert( upper_res_moltenresid );
1061 
1062  Size const lower_res_nrots = current_rotamer_sets_->nrotamers_for_moltenres( lower_res_moltenresid );
1063  Size const lower_res_nnew_rots = curr_rotamers_without_correspondence_[ lower_res ].size();
1064 
1065  Size const upper_res_nrots = current_rotamer_sets_->nrotamers_for_moltenres( upper_res_moltenresid );
1066  Size const upper_res_nnew_rots = curr_rotamers_without_correspondence_[ upper_res ].size();
1067 
1068  if ( lower_res_nnew_rots > 0 ) {
1069  for ( Size ii = 1; ii <= lower_res_nnew_rots; ++ii ) {
1070  Size ii_rot_index = curr_rotamers_without_correspondence_[ lower_res ][ ii ];
1071  ResidueCOP ii_rot = current_rotamer_sets_->rotamer_set_for_residue( lower_res )->rotamer( ii_rot_index );
1072  for ( Size jj = 1; jj <= upper_res_nrots; ++jj ) {
1073  EnergyMap emap;
1074  ResidueCOP jj_rot = current_rotamer_sets_->rotamer_set_for_residue( upper_res )->rotamer( jj );
1075  lre.residue_pair_energy( *ii_rot, *jj_rot, pose, *ci_sfxn_, emap );
1076  Real const weighted_energy = ci_sfxn_->weights().dot( emap );
1077  pig->add_to_two_body_energies_for_edge(
1078  lower_res_moltenresid, upper_res_moltenresid,
1079  ii_rot_index, jj, weighted_energy );
1080  }
1081  }
1082  }
1083 
1084  if ( upper_res_nnew_rots > 0 ) {
1085  for ( Size ii = 1; ii <= lower_res_nrots; ++ii ) {
1086 
1087  // Avoid double counting pair interactions by skipping the new rotamers of the lower residue,
1088  // since their interaction energies with the upper residue's rotamers have already been calculated
1089  if ( curr_rot_2_orig_rot_[ lower_res ][ ii ] == 0 ) continue;
1090 
1091  ResidueCOP ii_rot = current_rotamer_sets_->rotamer_set_for_residue( lower_res )->rotamer( ii );
1092  for ( Size jj = 1; jj <= upper_res_nnew_rots; ++jj ) {
1093  Size const jj_rot_index = curr_rotamers_without_correspondence_[ upper_res ][ jj ];
1094  EnergyMap emap;
1095  ResidueCOP jj_rot = current_rotamer_sets_->rotamer_set_for_residue( upper_res )->rotamer( jj_rot_index );
1096  lre.residue_pair_energy( *ii_rot, *jj_rot, pose, *ci_sfxn_, emap );
1097  Real const weighted_energy = ci_sfxn_->weights().dot( emap );
1098  pig->add_to_two_body_energies_for_edge(
1099  lower_res_moltenresid, upper_res_moltenresid,
1100  ii, jj_rot_index, weighted_energy );
1101  }
1102  }
1103  }
1104 }
1105 
1106 
1107 void
1109  core::pose::Pose & pose
1110 )
1111 {
1113 }
1114 
1115 /// @details Free memory that is no longer needed
1116 void
1118 {
1119  current_task_ = 0;
1121  current_rotamers_.clear();
1122  current_ig_ = 0;
1123 
1127 
1128  orig_rot_2_curr_rot_.clear();
1129  curr_rot_2_orig_rot_.clear();
1132 
1133 }
1134 
1136 {
1137  orig_bb_tors_.resize( pose.total_residue() );
1138  original_bb_rep_coords_.resize( pose.total_residue() );
1139  for ( Size ii = 1; ii <= pose.total_residue(); ++ii ) {
1140  orig_bb_tors_[ ii ] = pose.residue( ii ).mainchain_torsions();
1141  original_bb_rep_coords_[ ii ] = pose.residue( ii ).xyz( 1 );
1142  }
1143 }
1144 
1146 {
1147  assert( pose.total_residue() == orig_bb_tors_.size());
1148  for ( Size ii = 1; ii <= orig_bb_tors_.size(); ++ii ) {
1149  for ( Size jj = 1; jj <= orig_bb_tors_[ ii ].size(); ++jj ) {
1150  if ( std::abs( basic::periodic_range(
1151  orig_bb_tors_[ ii ][ jj ] - pose.residue( ii ).mainchain_torsions()[ jj ],
1152  180 ) ) > 1e-8 ) {
1153  std::cerr << "Critical Error in GreenPacker -- Backbone torsions have changed since original packing" << std::endl;
1154  std::cerr << "Residue " << ii << " torsion " << jj << " originally: " << orig_bb_tors_[ ii ][ jj ];
1155  std::cerr << " currently: " << pose.residue( ii ).mainchain_torsions()[ jj ] << std::endl;
1156  utility_exit_with_message("Bad torsion in GreenPacker" );
1157  }
1158  }
1159  }
1160 
1161 }
1162 
1163 
1164 
1165 }
1166 }