Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
RotamerSet_.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/rotamer_set/RotamerSet_.cc
11 /// @brief amino acid rotamer set class implementation
12 /// @author Andrew Leaver-Fay (leaverfa@email.unc.edu)
13 
14 // Unit Headers
16 
17 // Package Headers
18 // AUTO-REMOVED #include <core/pack/rotamer_set/RotamerCouplings.hh>
23 
24 // Project Headers
27 // AUTO-REMOVED #include <core/conformation/ResidueMatcher.hh>
28 // AUTO-REMOVED #include <core/chemical/ResidueTypeSet.hh>
33 #include <basic/Tracer.hh>
34 
35 #include <core/graph/Graph.hh>
36 
37 #include <core/pose/Pose.hh>
38 #include <core/scoring/Energies.hh>
40 
41 // AUTO-REMOVED #include <core/scoring/EnergyGraph.hh>
43 //#include <core/scoring/ScoringManager.hh>
48 
51 
52 // AUTO-REMOVED #include <core/io/pdb/pose_io.hh>
53 // AUTO-REMOVED #include <basic/database/open.hh>
54 
55 // AUTO-REMOVED #include <numeric/random/random.hh>
56 // AUTO-REMOVED #include <numeric/xyz.functions.hh>
57 
58 // AUTO-REMOVED #include <utility/io/izstream.hh>
59 // AUTO-REMOVED #include <utility/utility.functions.hh>
60 
61 // ObjexxFCL Headers
62 // AUTO-REMOVED #include <ObjexxFCL/FArray2.hh>
63 // AUTO-REMOVED #include <ObjexxFCL/string.functions.hh>
64 
65 // C++ headers
66 #include <string>
67 #include <iostream>
68 // AUTO-REMOVED #include <fstream>
69 
71 #include <utility/vector1.hh>
72 
73 
74 namespace core {
75 namespace pack {
76 namespace rotamer_set {
77 
78 static basic::Tracer tt("core.pack.rotamer_set.RotamerSet_",basic::t_info );
79 
81 :
82  n_residue_types_( 0 ),
83  n_residue_groups_( 0 ),
84  cached_tries_( scoring::methods::n_energy_methods, 0 ),
85  id_for_current_rotamer_( 0 ),
86  rotamer_offsets_require_update_( false )
87 {}
88 
90 
92  pose::Pose const & pose,
93  scoring::ScoreFunction const & scorefxn,
94  task::PackerTask const & the_task,
95  graph::GraphCOP packer_neighbor_graph,
96  bool use_neighbor_context
97 )
98 {
99  using namespace chemical;
100 
102  allowed_iter = the_task.residue_task( resid() ).allowed_residue_types_begin(),
103  allowed_end = the_task.residue_task( resid() ).allowed_residue_types_end();
104  allowed_iter != allowed_end; ++allowed_iter ) {
105  build_rotamers_for_concrete_virt( pose, scorefxn, the_task, *allowed_iter, packer_neighbor_graph, use_neighbor_context );
106  //std::cout << "Built rotamers for " << (*allowed_iter)->name() << " seqpos " << resid() << " " << n_residue_types_ << std::endl;
107  }
108 
109  if ( num_rotamers() == 0 ) {
110  tt << "[ WARNING ] including current in order to get at least 1 rotamer !!!!!! " << resid() << ' ' <<
111  pose.residue( resid() ).name() << '\n';
114  ResidueOP rot = pose.residue( resid() ).create_rotamer();
115  push_back_rotamer( rot );
116  }
117 
119  rotsetop_iter = the_task.residue_task( resid() ).rotamer_set_operation_begin(),
120  rotsetop_end = the_task.residue_task( resid() ).rotamer_set_operation_end();
121  rotsetop_iter != rotsetop_end; ++rotsetop_iter ) {
122  (*rotsetop_iter)->alter_rotamer_set( pose, scorefxn, the_task, packer_neighbor_graph, *this );
123  }
124 
125  tt.flush();
126  //std::cout << "Built " << num_rotamers() << " rotamers for residue " << resid() << " " << pose.residue(resid()).name() << std::endl;
127 }
128 
129 void
132 )
133 {
134  //tt << "RotamerSet_::add_rotamer" << '\n';
135  //++n_residue_types_; // TOTAL HACK -- possible to add 50 HIS's and declare there to be 50 different AA types.
136  //tt << "TOTAL HACK BEING USED in " << __FILE__ << " line " << __LINE__ << ". For efficiency, refactor!" << '\n';
137  //residue_type_rotamers_begin_.push_back( num_rotamers() + 1);
138  //n_rotamers_for_restype_.push_back( 1 );
139  //rotamers_.push_back( rotamer.clone() );
140 
141  prepare_for_new_residue_type( rotamer.type() );
142  push_back_rotamer( rotamer.clone() );
143 }
144 
145 
146 
147 Size
149 {
150  //std::cout << "B get_n_residue_types: " << n_residue_types_ << std::endl;
152  //std::cout << "A get_n_residue_types: " << n_residue_types_ << std::endl;
153  return n_residue_types_;
154 }
155 
156 Size
158 {
160  return n_residue_groups_;
161 }
162 
163 
164 Size
166 {
168  assert( which_restype <= n_residue_types_ );
169  return residue_type_rotamers_begin_[ which_restype ];
170 }
171 
172 Size
174 {
176  assert( which_resgroup <= n_residue_groups_ );
177  return residue_group_rotamers_begin_[ which_resgroup ];
178 }
179 
180 
181 Size
183 {
185  assert( which_restype <= n_residue_types_ );
186  return n_rotamers_for_restype_[ which_restype ];
187 }
188 
189 
190 Size
192 {
194  assert( which_resgroup <= n_residue_groups_ );
195  return n_rotamers_for_resgroup_[ which_resgroup ];
196 }
197 
198 Size
200 {
201  return residue_type_for_rotamers_[ which_rotamer ];
202 }
203 
204 Size
206 {
207  return residue_group_for_rotamers_[ which_rotamer ];
208 }
209 
210 /// @details This will check for rotamer/background collisions if the PackerTask's
211 /// bump_check boolean is true -- it uses the bump_check_{sidechain/full} methods
212 /// defined by the energy methods contained in the scorefxn object
213 void
215  pose::Pose const & pose,
216  scoring::ScoreFunction const & scorefxn,
217  task::PackerTask const & task,
218  chemical::ResidueTypeCOP concrete_residue,
219  graph::GraphCOP packer_neighbor_graph,
220  bool use_neighbor_context
221 )
222 {
223  conformation::Residue const & existing_residue( pose.residue( resid() ));
225  pose, scorefxn, task, concrete_residue, existing_residue,
226  packer_neighbor_graph, use_neighbor_context );
227 }
228 
229 void
231  pose::Pose const & pose,
232  scoring::ScoreFunction const & scorefxn,
233  task::PackerTask const & task,
234  chemical::ResidueTypeCOP concrete_residue,
235  conformation::Residue const & existing_residue,
236  graph::GraphCOP packer_neighbor_graph,
237  bool use_neighbor_context
238 )
239 {
240  using namespace conformation;
241  using namespace pack::task;
242 
243  //++n_residue_types_;
244  //residue_type_rotamers_begin_.push_back( num_rotamers() + 1);
245  //n_rotamers_for_restype_.push_back( 0 );
246  prepare_for_new_residue_type( *concrete_residue );
247 
248  if ( task.residue_task( resid() ).optimize_h() ) {
249  build_optimize_H_rotamers( pose, task, concrete_residue, existing_residue );
250  } else if ( concrete_residue->is_DNA() ) {
251  // behavior depends on residue type. should refactor this -- at least into
252  // several separate methods that this one switches betweeen...
253 
254  /// DNA rotamers //////////////////////////////////////////
255  utility::vector1< ResidueOP > new_rotamers;
256 
257  build_dna_rotamers( resid(), pose, concrete_residue, task, new_rotamers );
258 
259 
260  if ( task.include_current( resid() ) && existing_residue.name() == concrete_residue->name() ) {
261  ResidueOP rot = existing_residue.create_rotamer();
262  new_rotamers.push_back( rot );
263  id_for_current_rotamer_ = new_rotamers.size();
264  }
265 
266  for ( Size ii=1; ii<= new_rotamers.size(); ++ii ) {
267  assert( new_rotamers[ii]->seqpos() == resid() && new_rotamers[ii]->chain() == existing_residue.chain() );
268  push_back_rotamer( new_rotamers[ii] );
269  }
270 
271  } else if ( concrete_residue->is_RNA() ) {
272 
273  utility::vector1< ResidueOP > new_rotamers;
274 
275  // sample chi, include_current, and proton chi expansion is inside here:
276  build_rna_rotamers( resid(), pose, concrete_residue, task, new_rotamers, id_for_current_rotamer_ );
277 
278  for ( Size ii=1; ii<= new_rotamers.size(); ++ii ) {
279  // assert( new_rotamers[ii]->seqpos() == resid() && new_rotamers[ii]->chain() == existing_residue.chain() );
280  push_back_rotamer( new_rotamers[ii] );
281  }
282 
283  } else if ( concrete_residue->name() == "VRT1" ) { /// single-atom virtual residue //////////////
284 
285  tt << "building VRT1 residue at " << resid() << ' ' << existing_residue.name() << "position\n";
286  if ( existing_residue.name() == concrete_residue->name() ) {
287  ResidueOP rot = existing_residue.clone();
288  push_back_rotamer( rot );
290 
291  } else {
292  ResidueOP rot = ResidueFactory::create_residue( *concrete_residue );
293  rot->set_xyz( 1, existing_residue.nbr_atom_xyz() );
294  rot->seqpos( existing_residue.seqpos() );
295  rot->chain ( existing_residue.chain() );
296  push_back_rotamer( rot );
297  }
298 
299  } else if ( concrete_residue->name() == "TP3" ) { // TIP3 water /////////////////////////////////
300 
301  // build rotamers for water
302  utility::vector1< ResidueOP > new_rotamers;
303 
304  build_independent_water_rotamers( resid(), *concrete_residue, task, pose, packer_neighbor_graph, new_rotamers );
305 
306  for ( Size ii=1; ii<= new_rotamers.size(); ++ii ) {
307  new_rotamers[ii]->seqpos( resid() );
308  new_rotamers[ii]->chain( existing_residue.chain() );
309  push_back_rotamer( new_rotamers[ii] );
310  }
311 
312  if ( task.include_current( resid() ) && existing_residue.name() == concrete_residue->name() ) {
313  ResidueOP rot = existing_residue.create_rotamer();
314  push_back_rotamer( rot );
316  }
317 
318  } else { // Not DNA ///////////////////////////////////////////////////////////////////////
319 
320  utility::vector1< utility::vector1< Real > > extra_chi_steps( concrete_residue->nchi() );
321 
322  int nneighbs(999);
323  if ( use_neighbor_context ) {
325  }
326  bool buried = ( nneighbs >= int(task.residue_task(resid()).extrachi_cutoff()) || !use_neighbor_context );
327 
328  for ( Size ii = 1; ii <= concrete_residue->nchi(); ++ii ) {
330  task, nneighbs, ii,
331  concrete_residue, extra_chi_steps[ ii ] );
332  }
333 
336 
337  utility::vector1< ResidueOP > suggested_rotamers;
338 
340  if (rotlib) {
341  rotlib->fill_rotamer_vector( pose, scorefxn, task, packer_neighbor_graph, concrete_residue, existing_residue, extra_chi_steps, buried, suggested_rotamers);
342  } else {
343  // Add proton chi rotamers even if there's no rotamer library... this will disappear when
344  // ligands get their own rotamer libraries.
345  if ( concrete_residue->n_proton_chi() != 0 ) {
347  proton_chi_chisets.push_back( new pack::dunbrack::ChiSet( concrete_residue->nchi() ) );
348  for ( Size ii = 1; ii <= concrete_residue->n_proton_chi(); ++ii ) {
351  ( (Size) nneighbs >= task.residue_task( resid() ).extrachi_cutoff() ),
352  concrete_residue->proton_chi_2_chi( ii ),
353  concrete_residue ),
354  concrete_residue,
355  ii, proton_chi_chisets);
356  }
357  suggested_rotamers.reserve( proton_chi_chisets.size() );
358  for ( Size ii = 1; ii <= proton_chi_chisets.size(); ++ii ) {
359  suggested_rotamers.push_back( existing_residue.clone() );
360  for ( Size jj = 1; jj <= concrete_residue->n_proton_chi(); ++jj ) {
361  Size jj_protchi = concrete_residue->proton_chi_2_chi( jj );
362  suggested_rotamers[ ii ]->set_chi(
363  jj_protchi,
364  proton_chi_chisets[ ii ]->chi[ jj_protchi ] );
365  }
366  }
367  }
368  //tt << "Building rotamers for " << concrete_residue->name() << ": total number of suggested: " << suggested_rotamers.size() << '\n';
369 
370  }
371  //tt <<
372  // "existing: " << existing_residue.name() <<
373  // " concrete: " << concrete_residue->name() <<
374  // " total number of suggested: " << suggested_rotamers.size() << '\n';
375 
376  for ( Size ii = 1; ii <= suggested_rotamers.size(); ++ii ) {
377  ResidueOP rot = suggested_rotamers[ ii ];
378  /*{
379  tt << "suggested rotamer " << ii <<' ';
380  for ( Size jj =1; jj <= rot->nchi(); jj++ ) {
381  tt << rot->chi()[jj] << ' ';
382  }
383  }*/
384  if ( task.bump_check() ) {
385  core::PackerEnergy bumpenergy = bump_check( rot, scorefxn, pose, task, packer_neighbor_graph );
386  // tt << "bump energy: " << bumpenergy;// ss << '\n';
388  switch ( decision ) {
389  case KEEP_ROTAMER :
390  // std::cout << " ... added" << std::endl;
391  push_back_rotamer( rot );
392  break;
394  //std::cout << " ... replace previous " << std::endl;
395  assert ( num_rotamers() > 0 );
396  rotamers_[ num_rotamers() ] = rot;
397  break;
398  case DELETE_ROTAMER : // do nothing
399  //std::cout << " ... deleted " << std::endl;
400  break;
401  }
402  } else {
403  //tt << "...added unchecked" << '\n';
404  push_back_rotamer( rot );
405  }
406  }
407 
408  if ( task.include_current( resid() ) && existing_residue.name() == concrete_residue->name() ) {
409  //tt << "including current rotamer: " << existing_residue.name() << ' ' << existing_residue.seqpos() << std::endl;
410  ResidueOP rot = existing_residue.create_rotamer();
411  push_back_rotamer( rot );
413  //int rotid = bump_select_rotamer( pose, scorefxn, task, rot );
414  } else if ( suggested_rotamers.size() == 0 && concrete_residue->nchi() == 0 ) {
415  // tt << "use emergency rotamer " << '\n';
416  ResidueOP rot = ResidueFactory::create_residue( *concrete_residue, existing_residue, pose.conformation() );
417  push_back_rotamer( rot );
418  }
419  } // not DNA
420 }
421 
422 /// @details Creates a sets of rotamers for an "optimize H" repacking:
423 /// optimize H repositions hydroxyl hydrogens and resolve protonation
424 /// ambiguity and if the task's flip_HNQ flag is set, it will flip
425 /// amide groups ( ASN (N) and GLN (Q) ) and the ring orientation
426 /// in histidine (H).
427 void
429  pose::Pose const & pose,
430  task::PackerTask const & task,
431  chemical::ResidueTypeCOP concrete_residue,
432  conformation::Residue const & existing_residue
433 )
434 {
435  using namespace chemical;
436  using namespace conformation;
437 
438  // Three cases:
439  // 1) if we're flipping HNQ's and this is an HNQ, then push back two rotamers, an original
440  // and a flipped rotamer. If it's His and concrete.type != existing.type, then copy
441  // the heavy coords and place the H's in their ideal conf.
442  // 2) if the concrete residue is not the same as the existing residue, then copy
443  // over the heavyatom coordinates and idealize the hydrogen coordinates. HIS case w/o flip.
444  // 3) otherwise, create proton-chi-varying rotamers only, cloning the existing residue
445 
446 
447  if ( task.residue_task( resid() ).flip_HNQ() && (
448  concrete_residue->aa() == aa_his ||
449  concrete_residue->aa() == aa_asn ||
450  concrete_residue->aa() == aa_gln ) ) {
451 
452  /// This is not the Richardson style HNQ flip. Instead of preserving the bond geometry
453  /// and rotating chi2/chi3 by 180, they swap the coordinates of the heavy atoms.
454  /// e.g. ASN ND2 swaped with ASN OD1.
455  /// rosetta++ simply rotates the bond angles.
456 
457  if ( concrete_residue->name() != pose.residue( resid() ).name() ) {
458  /// HisE --> HisD or HisD --> HisE
459  ResidueOP example_rotamer = ResidueFactory::create_residue( *concrete_residue );
460  example_rotamer->seqpos( existing_residue.seqpos() );
461  for ( Size ii = 1; ii <= existing_residue.nheavyatoms(); ++ii ) {
462  if ( example_rotamer->has( existing_residue.atom_name( ii ) ) ) {
463  example_rotamer->set_xyz(
464  example_rotamer->atom_index( existing_residue.atom_name( ii ) ),
465  existing_residue.xyz( ii ) );
466  }
467  }
468  example_rotamer->chain( pose.residue( resid() ).chain() );
469  example_rotamer->mainchain_torsions() = pose.residue( resid() ).mainchain_torsions();
470  example_rotamer->copy_residue_connections( pose.residue( resid() ) );
471  idealize_hydrogens( *example_rotamer, pose.conformation() );
472  push_back_rotamer( example_rotamer );
473 
474  ResidueOP flipped_rotamer = example_rotamer->clone();
475  Real flipped_chi2 = flipped_rotamer->chi(2) + 180;
476  flipped_rotamer->set_chi( 2, flipped_chi2 );
477  push_back_rotamer( flipped_rotamer );
478 
479  } else {
480  push_back_rotamer( existing_residue.clone() );
481 
482  ResidueOP flipped_rotamer = existing_residue.clone();
483  Size chi_to_flip( 0 );
484  switch ( concrete_residue->aa() ) {
485  case aa_his :
486  case aa_asn :
487  chi_to_flip = 2;
488  break;
489  case aa_gln :
490  chi_to_flip = 3;
491  break;
492  default:
493  utility_exit_with_message("Illegal case statement option.");
494  break;
495  }
496 
498 
499  Real flipped_chi2 = flipped_rotamer->chi( chi_to_flip ) + 180;
500  flipped_rotamer->set_chi( chi_to_flip, flipped_chi2 );
501  push_back_rotamer( flipped_rotamer );
502  }
503 
504  } else if ( concrete_residue->is_NA() ) {
505  /// merely clone the input residue
506  push_back_rotamer( existing_residue.clone() );
507  } else if ( concrete_residue->name() != pose.residue( resid() ).name() ) {
508  // in particular, HIS can be protonated on either ND1 or NE2
509  // Note: there is an assumption here that there are no proton chi
510  // in residues with alternate H placements. This assumption is unneccessary
511  // and can be changed by modifying the code below to expand proton chi.
512 
513  ResidueOP example_rotamer = ResidueFactory::create_residue( *concrete_residue );
514  example_rotamer->seqpos( existing_residue.seqpos() );
515  for ( Size ii = 1; ii <= existing_residue.nheavyatoms(); ++ii ) {
516  if ( example_rotamer->has( existing_residue.atom_name( ii ) ) ) {
517  example_rotamer->set_xyz(
518  example_rotamer->atom_index( existing_residue.atom_name( ii ) ),
519  existing_residue.xyz( ii ) );
520  }
521  }
522  example_rotamer->chain( pose.residue( resid() ).chain() );
523  example_rotamer->mainchain_torsions() = pose.residue( resid() ).mainchain_torsions();
524  example_rotamer->copy_residue_connections( pose.residue( resid() ) );
525  idealize_hydrogens( *example_rotamer, pose.conformation() );
527 
528  push_back_rotamer( example_rotamer );
529  } else {
530  /// Rotatable proton chi
531  utility::vector1< ResidueOP > suggested_rotamers;
532 
533  // REFACTOR!!!
534  if ( concrete_residue->n_proton_chi() != 0 ) {
536  proton_chi_chisets.push_back(
537  new pack::dunbrack::ChiSet( concrete_residue->nchi() ) );
538  for ( Size ii = 1; ii <= concrete_residue->n_proton_chi(); ++ii ) {
541  true, // ignore buriedness when adding extra proton chi rotamers
542  concrete_residue->proton_chi_2_chi( ii ),
543  concrete_residue ),
544  concrete_residue,
545  ii, proton_chi_chisets);
546  }
547  suggested_rotamers.reserve( proton_chi_chisets.size() );
548  for ( Size ii = 1; ii <= proton_chi_chisets.size(); ++ii ) {
549  suggested_rotamers.push_back( existing_residue.clone() );
550  for ( Size jj = 1; jj <= concrete_residue->n_proton_chi(); ++jj ) {
551  Size jj_protchi = concrete_residue->proton_chi_2_chi( jj );
552  suggested_rotamers[ ii ]->set_chi(
553  jj_protchi,
554  proton_chi_chisets[ ii ]->chi[ jj_protchi ] );
555  }
556  }
557  for ( Size ii = 1; ii <= suggested_rotamers.size(); ++ii ) {
558  push_back_rotamer( suggested_rotamers[ ii ] );
559  }
560  } else {
561  /// merely clone the input residue
562  push_back_rotamer( existing_residue.clone() );
564  }
565 
566  }
567 
568 
569 }
570 
572  task::PackerTask const & task,
573  int num_10A_neighbors,
574  int chi,
575  chemical::ResidueTypeCOP concrete_residue,
576  utility::vector1< Real > & extra_chi_steps
577 ) const
578 {
579  using namespace task;
580  bool buried = ( num_10A_neighbors >= int(task.residue_task( resid()).extrachi_cutoff()) );
581  switch ( task.residue_task( resid() ).extrachi_sample_level( buried, chi, concrete_residue ) ) {
582  case NO_EXTRA_CHI_SAMPLES :
583  break;
584  case EX_ONE_STDDEV :
585  extra_chi_steps.push_back(1);
586  extra_chi_steps.push_back(-1);
587  break;
589  extra_chi_steps.push_back(0.5);
590  extra_chi_steps.push_back(-0.5);
591  break;
593  extra_chi_steps.push_back(1);
594  extra_chi_steps.push_back(2);
595  extra_chi_steps.push_back(-1);
596  extra_chi_steps.push_back(-2);
597  break;
599  extra_chi_steps.push_back(0.5);
600  extra_chi_steps.push_back(1);
601  extra_chi_steps.push_back(-0.5);
602  extra_chi_steps.push_back(-1);
603  break;
605  extra_chi_steps.push_back(0.5);
606  extra_chi_steps.push_back(1);
607  extra_chi_steps.push_back(1.5);
608  extra_chi_steps.push_back(2.0);
609  extra_chi_steps.push_back(-0.5);
610  extra_chi_steps.push_back(-1);
611  extra_chi_steps.push_back(-1.5);
612  extra_chi_steps.push_back(-2);
613  break;
615  extra_chi_steps.push_back(0.33);
616  extra_chi_steps.push_back(0.67);
617  extra_chi_steps.push_back(1);
618  extra_chi_steps.push_back(-0.33);
619  extra_chi_steps.push_back(-0.67);
620  extra_chi_steps.push_back(-1);
621  break;
623  extra_chi_steps.push_back(0.25);
624  extra_chi_steps.push_back(0.5);
625  extra_chi_steps.push_back(0.75);
626  extra_chi_steps.push_back(1);
627  extra_chi_steps.push_back(1.25);
628  extra_chi_steps.push_back(1.5);
629  extra_chi_steps.push_back(-0.25);
630  extra_chi_steps.push_back(-0.5);
631  extra_chi_steps.push_back(-0.75);
632  extra_chi_steps.push_back(-1);
633  extra_chi_steps.push_back(-1.25);
634  extra_chi_steps.push_back(-1.5);
635  break;
637  default :
638  std::cerr << "Error in RotamerSet_::set_extrachi_samples, invalid ExtraChiSample type" << '\n';
639  utility_exit();
640  break;
641  }
642 }
643 
644 
645 // @ details The packer's 1-body is a combination of the rotamer internal energies (the
646 // context dependent and independent one body energies), the intra-residue
647 // energies defined by the two body energies, and the sum of the
648 // two body energies with the background residues in this repacking. The
649 // PackerTask tells the RotamerSet_ what residues are part of the
650 // background and which are being repacked.
651 void
653  pose::Pose const & pose,
654  scoring::ScoreFunction const & sf,
655  task::PackerTask const & task,
656  graph::GraphCOP packer_neighbor_graph,
658 ) const
659 {
660  using namespace conformation;
661  using namespace scoring;
662 
663  std::fill( energies.begin(), energies.end(), core::PackerEnergy( 0.0 ) );
664 
665  int const nrotamers = num_rotamers(); // does not change in this function
666  Size const theresid = resid();
667 
668  for ( int ii = 1; ii <= nrotamers; ++ii ) {
669  EnergyMap emap;
670  sf.eval_ci_1b( *rotamers_[ ii ], pose, emap );
671  sf.eval_cd_1b( *rotamers_[ ii ], pose, emap );
672  energies[ ii ] += static_cast< core::PackerEnergy > (sf.weights().dot( emap )); // precision loss here.
673  }
674 
675  sf.evaluate_rotamer_intrares_energies( *this, pose, energies );
676 
678  ir = packer_neighbor_graph->get_node( theresid )->const_edge_list_begin(),
679  ire = packer_neighbor_graph->get_node( theresid )->const_edge_list_end();
680  ir != ire; ++ir ) {
681 
682  int const neighbor_id( (*ir)->get_other_ind( theresid ) );
683 
684  if ( task.pack_residue( neighbor_id ) ) continue;
685 
686  Residue const & neighbor( pose.residue( neighbor_id ) );
687  sf.evaluate_rotamer_background_energies( *this, neighbor, pose, energies );
688 
689  }
690 
691  // long-range energy interactions with background
692  // Iterate across the long range energy functions and use the iterators generated
693  // by the LRnergy container object
695  lr_iter = sf.long_range_energies_begin(),
696  lr_end = sf.long_range_energies_end();
697  lr_iter != lr_end; ++lr_iter ) {
698  LREnergyContainerCOP lrec = pose.energies().long_range_container( (*lr_iter)->long_range_type() );
699  if ( !lrec || lrec->empty() ) continue; // only score non-emtpy energies.
700 
701  // Potentially O(N) operation leading to O(N^2) behavior
703  rni = lrec->const_neighbor_iterator_begin( theresid ),
704  rniend = lrec->const_neighbor_iterator_end( theresid );
705  (*rni) != (*rniend); ++(*rni) ) {
706  Size const neighbor_id = rni->neighbor_id();
707  assert( neighbor_id != theresid );
708  if ( task.pack_residue( neighbor_id ) ) continue;
709 
710  (*lr_iter)->evaluate_rotamer_background_energies(
711  *this, pose.residue( neighbor_id ), pose, sf,
712  sf.weights(), energies );
713 
714  } // (potentially) long-range neighbors of theresid [our resid()]
715  } // long-range energy functions
716 
717 
718 }
719 
720 
721 ///@details Used in OptE. Based on the function compute_one_body_energies(). OptE needs to store the energies for all score terms for each rotamer separately. In this context there are only rotamers at a single position, with all other positions fixed.
722 void
724  pose::Pose const & pose,
725  scoring::ScoreFunction const & sf,
726  task::PackerTask const & , // task
727  graph::GraphCOP packer_neighbor_graph,
729 ) const
730 {
731  using namespace conformation;
732  using namespace scoring;
733 
734  EnergyMap default_map_of_zeroes;
735 
736  std::fill( energies.begin(), energies.end(), default_map_of_zeroes );
737 
738  int const nrotamers = num_rotamers(); // does not change in this function
739  Size const theresid = resid();
740 
741  //ronj variables for surfaceE, see below for more info
742  Real last_computed_surfaceE = 0.0;
743 
744  utility::vector1<Size> num_neighbors_;
745  num_neighbors_.resize( pose.n_residue(), 0 );
746  scoring::TenANeighborGraph const & tenA_neighbor_graph( pose.energies().tenA_neighbor_graph() );
747  for ( Size id = 1; id <= pose.n_residue(); ++id ) {
748  num_neighbors_[ id ] = tenA_neighbor_graph.get_node( id )->num_neighbors_counting_self();
749  }
750 
751  for ( int ii = 1; ii <= nrotamers; ++ii ) {
752  // one-body energies
753  EnergyMap emap;
754  sf.eval_ci_1b( *rotamers_[ ii ], pose, emap );
755  sf.eval_cd_1b( *rotamers_[ ii ], pose, emap );
756 
757  // With apl's blessing, adding a special check for whether or not surface scoring is in use for the long-term
758  // goal of trying to optimize the non-PD surface score together with the other EnergyMethods in the optE protocol.
759  // Since this method is only used by optE, this ugly if statement here will not affect performance in regular runs. (ronj)
760 
761  // This calculation is inside the for loop above which goes through all the different possible rotamers at a sequence
762  // position. To avoid making the expensive surface calculation, cache the last computed energy if the residue type
763  // of the last rotamer is the same as that of the current rotamer since that will not change the surface score.
764  // This kind of "state" can't be kept in the surface calculation function since that is not implemented as a class. (ronj)
765  core::Real surface_weight( sf.get_weight( core::scoring::surface ) );
766  if ( surface_weight ) {
767  if ( ( ii > 1 ) && ( (*rotamers_[ii]).name() == (*rotamers_[ii-1]).name() ) ) {
768  emap[ surface ] = last_computed_surfaceE;
769  } else {
771  last_computed_surfaceE = emap[ surface ];
772  }
773  // emap[surface] should now have an energy in it for this rotamer
774  }
775 
776  energies[ii] += emap;
777 
778  // add interactions for each rotamer with its (fixed) neighbors
780  ir = packer_neighbor_graph->get_node( theresid )->const_edge_list_begin(),
781  ire = packer_neighbor_graph->get_node( theresid )->const_edge_list_end();
782  ir != ire; ++ir ) {
783  int const neighbor_id( (*ir)->get_other_ind( theresid ) );
784  Residue const & neighbor( pose.residue( neighbor_id ) );
785 
786  EnergyMap emap2b;
787 
788  emap2b.zero();
789  sf.eval_ci_2b( neighbor, *rotamers_[ ii ], pose, emap2b );
790  energies[ii] += emap2b;
791 
792  emap2b.zero();
793  sf.eval_cd_2b( neighbor, *rotamers_[ ii ], pose, emap2b );
794  energies[ii] += emap2b;
795  }
796  }
797 
798  // Intrares energies
799  sf.evaluate_rotamer_intrares_energy_maps( *this, pose, energies );
800 
801  // Long Range Interactions
803  lr_iter = sf.long_range_energies_begin(),
804  lr_end = sf.long_range_energies_end();
805  lr_iter != lr_end; ++lr_iter ) {
806 
807  LREnergyContainerCOP lrec = pose.energies().long_range_container( (*lr_iter)->long_range_type() );
808 
809  if ( !lrec || lrec->empty() ) continue; // only score non-empty energies.
810 
811  // Potentially O(N^2) operation...
812  for ( ResidueNeighborConstIteratorOP rni = lrec->const_neighbor_iterator_begin( theresid ),
813  rniend = lrec->const_neighbor_iterator_end( theresid );
814  (*rni) != (*rniend); ++(*rni) ) {
815 
816  Size const neighbor_id = rni->neighbor_id();
817 
818  if( theresid == neighbor_id ) continue;
819 
820  (*lr_iter)->evaluate_rotamer_background_energy_maps(
821  *this, pose.residue( neighbor_id ), pose, sf, sf.weights(), energies );
822 
823  } // (potentially) long-range neighbors of ii [our resid()]
824  } // long-range energy functions
825 }
826 
827 Size
829 {
830  return rotamers_.size();
831 }
832 
833 Size
835 {
837 }
838 
840 RotamerSet_::rotamer( Size rot_id ) const
841 {
842  return rotamers_[ rot_id ];
843 }
844 
845 
846 /// @details In handing out non-const data, the guarantee of rotamer-type contiguity
847 /// within the rotamers_ array, and the correspondence of the rotamer offset
848 /// data is lost. Future access to rotamer offset data first requires an update
849 /// of the rotamer offset arrays.
852 {
854 
855  return rotamers_[ rot_id ];
856 }
857 
858 void
860  Size method_enum_id,
862 )
863 {
864  cached_tries_[ method_enum_id ] = trie;
865 }
866 
867 
869 RotamerSet_::get_trie( Size method_enum_id ) const
870 {
871  return cached_tries_[ method_enum_id ];
872 }
873 
874 /// @details O(n) operation; if you have a lot of rotamers you want to remove, use
875 /// drop_rotamers() instead.
876 void
878 {
879  assert( rot_id <= rotamers_.size() );
880  utility::vector1< conformation::ResidueOP > copy_rotamers( rotamers_.size() - 1, 0 );
881  Size count_copy( 1 );
882  for ( Size ii = 1; ii <= rotamers_.size(); ++ii ) {
883  if ( ii != rot_id ) {
884  copy_rotamers[ count_copy ] = rotamers_[ ii ];
885  if ( ii == id_for_current_rotamer_ ) {
886  id_for_current_rotamer_ = count_copy;
887  }
888  ++count_copy;
889  } else {
890  if ( ii == id_for_current_rotamer_ ) {
892  }
893  }
894  }
895  copy_rotamers.swap( rotamers_ );
898 
899 }
900 
901 /// @brief rotamers_to_delete must be of size nrotmaers -- each position
902 /// in the array that's "true" is removed from the set of rotamers
903 void
905 {
906  assert( rotamers_to_delete.size() == rotamers_.size() );
907 
908  Size n_dropped = 0;
909  for ( Size ii = 1; ii <= rotamers_.size(); ++ii ) {
910  if ( rotamers_to_delete[ ii ] ) {
911  /// if all rotamers end up dropped, then preserve the input rotamer.
912  if ( ii == id_for_current_rotamer_ ) {
914  }
915  rotamers_[ ii ] = 0;
916  ++n_dropped;
917  }
918  }
919  if ( n_dropped == 0 ) return;
920 
921  if ( n_dropped == rotamers_.size() ) {
922  if ( id_for_current_rotamer_ == 0 ) {
923  utility_exit_with_message( "ERROR:: RotamerSet_::drop_rotamers attempted to remove all rotamers without available input_rotamer." );
924  }
925  // keep the input rotamer.
926  rotamers_.resize( 1 );
930  } else {
931  utility::vector1< conformation::ResidueOP > new_rotamers( rotamers_to_delete.size() - n_dropped, 0 );
932  Size count_new = 1;
933  for ( Size ii = 1; ii <= rotamers_.size(); ++ii ) {
934  if ( rotamers_[ ii ] != 0 ) {
935  new_rotamers[ count_new ] = rotamers_[ ii ];
936  if ( ii == id_for_current_rotamer_ ) {
937  id_for_current_rotamer_ = count_new;
938  }
939  ++count_new;
940  }
941  }
942  new_rotamers.swap( rotamers_ );
943  }
946 }
947 
948 /// @brief deletes the rotamers in the list with the given indices.
949 /// The indices of these rotamers is presumed to be those before any delete operation.
950 /// e.g. if there are four rotamers, and rotamer_indices_to_delete includes 1 & 3,
951 /// then the rotamers that will remain are the rotamers originally indexed as 2 and 4,
952 /// even though their new indices will be 1 & 2.
953 void
955  utility::vector1< Size > const & rotamer_indices_to_delete
956 )
957 {
958  utility::vector1< bool > rotamers_to_delete( rotamers_.size(), false );
959  for ( Size ii = 1; ii <= rotamer_indices_to_delete.size(); ++ii ) {
960  rotamers_to_delete[ rotamer_indices_to_delete[ ii ] ] = true;
961  }
962  drop_rotamers( rotamers_to_delete );
963 }
964 
965 /// @details Bump check does not include long range energies,
966 /// though, maybe this should change.
970  scoring::ScoreFunction const & sf,
971  pose::Pose const & pose,
972  task::PackerTask const & task,
973  graph::GraphCOP packer_neighbor_graph
974 ) const
975 {
976  using namespace scoring;
977  using namespace conformation;
978 
979  EnergyMap emap;
980 
982  ir = packer_neighbor_graph->get_node( resid() )->const_edge_list_begin(),
983  ire = packer_neighbor_graph->get_node( resid() )->const_edge_list_end();
984  ir != ire; ++ir ) {
985  int const neighbor_id( (*ir)->get_other_ind( resid() ) );
986  Residue const & neighbor( pose.residue( neighbor_id ) );
987 
988  if ( ! task.pack_residue( neighbor_id ) ) {
989  sf.bump_check_full( *rotamer, neighbor, pose, emap);
990  } else {
991  sf.bump_check_backbone( *rotamer, neighbor, pose, emap);
992  }
993  }
994  return static_cast< core::PackerEnergy > (sf.weights().dot( emap ));
995 }
996 
997 void
999 {
1000  if ( n_residue_types_ == 0 ) {
1001  new_residue_type();
1003  return;
1004  }
1005  if ( num_rotamers() == 0 ) {
1006  // n_residue_types_ and n_residue_groups_ is not zero -- how odd
1007  return;
1008  }
1009 
1010  if ( different_restype( rotamers_[ num_rotamers() ]->type(), restype )) {
1011  new_residue_type();
1012  }
1013  if ( different_resgroup( rotamers_[ num_rotamers() ]->type(), restype )) {
1015  }
1016 }
1017 
1018 bool
1020 {
1021  return & rt1 != & rt2;
1022 }
1023 
1024 /// @details The logic to determine if two residue types should be classified as part of the same group.
1025 /// The thinking is as follows. Two residue types are in the same group if they have the same residue type.
1026 /// They're in the same group if their residue types differ, but they have the same name3 (HIS vs HIS_D have
1027 /// the same name3) and they have the same neighbor radius (SER and PhosphoSER should have different groups).
1028 /// The goal is to organize residue types together which will be packed together (as happens in multistate design
1029 /// with HIS and HISD) and that have the same reach (as is needed for the AANeighborSparseMatrix).
1030 bool
1032 {
1033  return & rt1 != & rt2 && ( rt1.name3() != rt2.name3() || rt1.nbr_radius() != rt2.nbr_radius() );
1034 }
1035 
1036 void
1038 {
1039  ++n_residue_types_;
1040  residue_type_rotamers_begin_.push_back( num_rotamers() + 1);
1041  n_rotamers_for_restype_.push_back( 0 );
1042 }
1043 
1044 void
1046 {
1048  residue_group_rotamers_begin_.push_back( num_rotamers() + 1 );
1049  n_rotamers_for_resgroup_.push_back( 0 );
1050 }
1051 
1052 void
1054 {
1055  rotamers_.push_back( rotamer );
1060 }
1061 
1063  RotamerSets const & rotamer_sets,
1064  pose::Pose const & pose,
1065  scoring::ScoreFunction const & scorefxn,
1066  task::PackerTask const & the_task,
1067  graph::GraphCOP packer_neighbor_graph
1068 )
1069 {
1070  using namespace chemical;
1071  conformation::Residue const & existing_residue( pose.residue( resid() ) );
1073  allowed_iter = the_task.residue_task( resid() ).allowed_residue_types_begin(),
1074  allowed_end = the_task.residue_task( resid() ).allowed_residue_types_end();
1075  allowed_iter != allowed_end; ++allowed_iter ) {
1076  build_dependent_rotamers_for_concrete( rotamer_sets, pose, scorefxn, the_task,
1077  existing_residue, *allowed_iter, packer_neighbor_graph);
1078  }
1079 }
1080 
1081 void
1083  RotamerSets const & rotamer_sets,
1084  pose::Pose const & pose,
1085  scoring::ScoreFunction const &,// scorefxn,
1086  task::PackerTask const & task,
1087  conformation::Residue const & existing_residue,
1088  chemical::ResidueTypeCOP concrete_residue,
1089  graph::GraphCOP packer_neighbor_graph
1090 )
1091 {
1092  using namespace conformation;
1093  using namespace pack::task;
1094 
1095  //if ( !task.residue_task( resid() ).build_dependent_rotamers() ) return;
1096 
1097  if ( concrete_residue->name() != "TP3" ) return; // logic only exists for this guy right now
1098 
1099  if ( concrete_residue->name() == "TP3" ) { // TIP3 water /////////////////////////////////
1100 
1101  // build rotamers for water
1102  utility::vector1< ResidueOP > new_rotamers;
1103 
1105  rotamer_sets, resid(), *concrete_residue,
1106  task, pose, packer_neighbor_graph,
1107  new_rotamers );
1108 
1109  if ( new_rotamers.empty() ) return;
1110 
1111  prepare_for_new_residue_type( *concrete_residue );
1112 
1113  for ( Size ii=1; ii<= new_rotamers.size(); ++ii ) {
1114  new_rotamers[ii]->seqpos( resid() );
1115  new_rotamers[ii]->chain( existing_residue.chain() );
1116  push_back_rotamer( new_rotamers[ii] );
1117  }
1118 
1119  } else {
1120  utility_exit_with_message( "unsupported restype for dependent rotamer building: "+concrete_residue->name() );
1121  }
1122 }
1123 
1124 
1125 void
1127 {
1128  if ( ! rotamer_offsets_require_update_ ) return;
1129 
1130  if ( rotamers_.size() == 0 ) {
1131  n_residue_types_ = 0;
1132  n_residue_groups_ = 0;
1133  residue_type_for_rotamers_.resize( 0 );
1134  residue_group_for_rotamers_.resize( 0 );
1135  residue_type_rotamers_begin_.resize( 0 );
1136  residue_group_rotamers_begin_.resize( 0 );
1137  n_rotamers_for_restype_.resize( 0 );
1138  n_rotamers_for_resgroup_.resize( 0 );
1139  return;
1140  }
1141 
1142  /// From here forward, rotamers_.size() >= 1
1143  residue_type_for_rotamers_.resize( rotamers_.size() );
1144  residue_group_for_rotamers_.resize( rotamers_.size() );
1145  n_residue_types_ = 1;
1146  n_residue_groups_ = 1;
1149  for ( Size ii = 2; ii <= rotamers_.size(); ++ii ) {
1150  // compare addresses of the two types
1151  // treat them as different amino acids only if they have different name3's
1152  // or if they have different radii
1153  //if ( & (rotamers_[ ii ]->type()) != & (rotamers_[ ii ]->type()) ) {
1154  if ( different_restype( rotamers_[ ii ]->type(), rotamers_[ ii-1 ]->type() ) ) {
1155  ++n_residue_types_;
1156  }
1158 
1159  if ( different_resgroup( rotamers_[ ii ]->type(), rotamers_[ ii-1 ]->type() ) ) {
1161  }
1163  }
1164 
1167  std::fill( residue_type_rotamers_begin_.begin(), residue_type_rotamers_begin_.end(), 0 );
1168  std::fill( n_rotamers_for_restype_.begin(), n_rotamers_for_restype_.end(), 0 );
1169 
1172  std::fill( residue_group_rotamers_begin_.begin(), residue_group_rotamers_begin_.end(), 0 );
1173  std::fill( n_rotamers_for_resgroup_.begin(), n_rotamers_for_resgroup_.end(), 0 );
1174 
1175  Size count_seen_residue_types( 1 );
1176  Size count_seen_residue_groups( 1 );
1177  n_rotamers_for_restype_[ count_seen_residue_types ] = 1;
1178  n_rotamers_for_resgroup_[ count_seen_residue_groups ] = 1;
1179  residue_type_rotamers_begin_[ count_seen_residue_types ] = 1;
1180  residue_group_rotamers_begin_[ count_seen_residue_groups ] = 1;
1181 
1182  for ( Size ii = 2; ii <= rotamers_.size(); ++ii ) {
1183  if ( residue_type_for_rotamers_[ ii ] != residue_type_for_rotamers_[ ii-1 ] ) {
1184  ++count_seen_residue_types;
1185  residue_type_rotamers_begin_[ count_seen_residue_types ] = ii;
1186  }
1187  ++n_rotamers_for_restype_[ count_seen_residue_types ];
1189  ++count_seen_residue_groups;
1190  residue_group_rotamers_begin_[ count_seen_residue_groups ] = ii;
1191  }
1192  ++n_rotamers_for_resgroup_[ count_seen_residue_groups ];
1193  }
1194  //std::cout << "nrestypes " << n_residue_types_ << std::endl;
1196 }
1197 
1198 
1199 } // rotamer_set
1200 } // pack
1201 } // core