Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
rotamer_building_functions.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
25 
26 // Project Headers
28 
33 
34 #include <core/kinematics/Stub.hh>
35 
36 // AUTO-REMOVED #include <core/scoring/LREnergyContainer.hh>
37 // AUTO-REMOVED #include <core/scoring/methods/LongRangeTwoBodyEnergy.hh>
42 #include <basic/Tracer.hh>
43 
44 #include <core/graph/Graph.hh>
45 
46 #include <core/pose/Pose.hh>
52 // AUTO-REMOVED #include <core/scoring/Energies.hh>
53 // AUTO-REMOVED #include <core/scoring/EnergyGraph.hh>
54 // AUTO-REMOVED #include <core/scoring/TenANeighborGraph.hh>
55 //#include <core/scoring/ScoringManager.hh>
56 // AUTO-REMOVED #include <core/pack/dunbrack/RotamerLibrary.hh>
60 // AUTO-REMOVED #include <core/scoring/methods/Methods.hh>
61 // AUTO-REMOVED #include <core/scoring/rna/RNA_TorsionPotential.hh>
62 
65 
66 // AUTO-REMOVED #include <basic/prof.hh> // profiling
67 
68 #include <basic/datacache/BasicDataCache.hh>
70 
71 // AUTO-REMOVED #include <core/io/pdb/pose_io.hh>
72 #include <basic/database/open.hh>
73 
75 
76 #include <numeric/random/random.hh>
77 #include <numeric/xyz.functions.hh>
78 
79 #include <utility/io/izstream.hh>
80 // AUTO-REMOVED #include <utility/utility.functions.hh>
81 
82 #include <numeric/constants.hh>
83 
84 // ObjexxFCL Headers
85 // AUTO-REMOVED #include <ObjexxFCL/FArray2.hh>
86 // AUTO-REMOVED #include <ObjexxFCL/string.functions.hh>
87 #include <ObjexxFCL/format.hh>
88 
89 // C++ headers
90 #include <string>
91 #include <iostream>
92 #include <fstream>
93 
95 #include <utility/vector1.hh>
96 #include <ObjexxFCL/FArray3D.hh>
97 
98 //Auto Headers
100 
101 
102 namespace core {
103 namespace pack {
104 namespace rotamer_set {
105 
106 static numeric::random::RandomGenerator RG(32241); // <- Magic number, do not change it!!!
107 
108 static basic::Tracer tt("core.pack.rotamer_set.rotamer_building_functions",basic::t_info );
109 
110 void
112  utility::io::izstream & lib_stream,
114 )
115 {
116  using namespace std;
117  const string delimiters(" ");
118  string line;
119 
120  while ( !lib_stream.eof() ) {
121 
122  DihedralSet *dihedrals = new DihedralSet;
123 
124  // Read next entry
125  getline( lib_stream, line );
126 
127  // Skip delimiters at beginning
128  Size last_pos = line.find_first_not_of( delimiters, 0 );
129  // Find first "non-delimiter"
130  Size pos = line.find_first_of( delimiters, last_pos );
131 
132  while ( string::npos != pos || string::npos != last_pos ) {
133  // Found a token, add it to the vector.
134  const string next_dih( line.substr( last_pos, pos-last_pos) );
135  dihedrals->push_back( strtod( next_dih.c_str(), NULL) );
136 
137  // Skip delimiters. Note the "not_of"
138  last_pos = line.find_first_not_of( delimiters, pos );
139 
140  // Find next "non-delimiter"
141  pos = line.find_first_of( delimiters, last_pos );
142  }
143 
144  if ( dihedrals->size() < 7)
145  delete dihedrals;
146  else
147  library.push_back( dihedrals );
148  }
149 }
150 
151 void
153  utility::vector1< DihedralSet* > const & library,
154  Size const resid,
155  pose::Pose const & pose,
156  chemical::ResidueTypeCOP concrete_residue,
158 )
159 {
160  using namespace basic;
161  using namespace pose;
162  using namespace conformation;
163  using namespace optimization;
164  using namespace id;
165  using namespace std;
166  using namespace scoring;
167  using namespace constraints;
168 
169  bool const minimize_rotamers( true );
170  Real const distance_cutoff( 2.0 );
171  Real min_tolerance( 1e-2 );
172  Real const pi( numeric::constants::d::pi );
173 
174  Real const std_length( .145 );
175  Real const std_angle ( .38 );
176  Real const dist_tol ( .2 ); // A
177  Real const angle_tol ( 30 ); // degrees
178  Real const rad2deg ( 180/pi );
179 
180  Residue const & existing_residue( pose.residue( resid ) );
181  assert( existing_residue.is_NA() && concrete_residue->is_NA() );
182 
183  bool const simple_way( existing_residue.is_terminus() );
184 
185  // a residue of the correct type aligned to the existing backbone
186  ResidueOP rot = ResidueFactory::create_residue( *concrete_residue, existing_residue, pose.conformation() );
187  rot->set_chi( 1, existing_residue.chi(1) );
188 
189  if ( simple_way )
190  rotamers.push_back( rot );
191  else {
192  pose::Pose mini_pose;
193  mini_pose.append_residue_by_bond( pose.residue( resid-1 ) );
194  mini_pose.append_residue_by_bond( *rot );
195  mini_pose.append_residue_by_jump( pose.residue( resid+1 ), 1 );
196 
197  Size const seqpos(2);
198  Residue const & rsd( mini_pose.residue(seqpos ) ), next_rsd( mini_pose.residue(seqpos+1) );
199 
200  assert( rsd.is_NA() && mini_pose.residue(seqpos-1).is_NA() );
201 
202  Vector const P_O3( ( next_rsd.xyz("P") - rsd.xyz("O3*") ) );
203  Real const target_distance( P_O3.length() );
204 
205  Real const P_bond_angle (angle_of( next_rsd.xyz("O5*"), next_rsd.xyz("P") , rsd.xyz("O3*") ));
206  Real const O3_bond_angle(angle_of( next_rsd.xyz("P") , rsd.xyz("O3*"), rsd.xyz("C3*") ));
207 
208  // tt << "P-O3 dist.=" << target_distance << ", P_bond_angle=" << P_bond_angle << ", O3_bond_angle=" << O3_bond_angle << std::endl;
209 
210  ConstraintSetOP cst_set( new ConstraintSet() );
211  cst_set->add_constraint( new AtomPairConstraint( AtomID(rsd.atom_index("O3*"),seqpos), AtomID(next_rsd.atom_index("P"),seqpos+1),
212  new HarmonicFunc( target_distance, std_length ) ) );
213  cst_set->add_constraint( new AngleConstraint ( AtomID(next_rsd.atom_index("O5*"),seqpos+1), AtomID(next_rsd.atom_index("P"),seqpos+1),
214  AtomID(rsd.atom_index("O3*"),seqpos), new HarmonicFunc( P_bond_angle, std_angle ) ) );
215  cst_set->add_constraint( new AngleConstraint ( AtomID(next_rsd.atom_index("P"),seqpos+1), AtomID(next_rsd.atom_index("O3*"),seqpos),
216  AtomID(rsd.atom_index("C3*"),seqpos), new HarmonicFunc( O3_bond_angle, std_angle ) ) );
217 
218  // could also add angle constraints
219  mini_pose.constraint_set( cst_set );
220 
221  ScoreFunction sf;
222  sf.set_weight( atom_pair_constraint, 1.0 );
223  sf.set_weight( angle_constraint , 1.0 );
224 
225  // setup the options
226  MinimizerOptions options( "dfpmin" /* or "linmin" */, min_tolerance, true /*use_nblist*/, false /*deriv_check*/, false /*no verbose-deriv-check, is default*/ );
227 
229  // allow minimizer to change these five dihedrals
230  mm.set( TorsionID(seqpos-1, BB, 6), true );
231  mm.set( TorsionID(seqpos , BB, 1), true );
232  mm.set( TorsionID(seqpos , BB, 2), true );
233  mm.set( TorsionID(seqpos , BB, 3), true );
234  mm.set( TorsionID(seqpos , BB, 4), true );
235 
236  utility::vector1< DihedralSet* >::const_iterator lib_iter = library.begin();
237  for ( ; lib_iter!=library.end(); lib_iter++ ) {
238 
239  DihedralSet const *dihedrals(*lib_iter);
240  bool accept_rotamer( true ) ;
241 
242  // Set mainchain dihedral angles (zeta, alpha - epsilon)
243  Size const nbb( rsd.n_mainchain_atoms() );
244  for ( int i=1; i<=6; ++i ) {
245  TorsionID const id ( ( i==1 ) ? ( TorsionID( seqpos-1, BB, nbb ) ) : ( TorsionID( seqpos, BB, i-1 ) ) );
246  mini_pose.set_torsion( id, (*dihedrals)[i] );
247  }
248  // Set chi
249  TorsionID const id ( seqpos, CHI, 1 );
250  mini_pose.set_torsion( id, (*dihedrals)[7] );
251 
252  Vector const rot_P_O3( ( next_rsd.xyz("P") - mini_pose.residue(seqpos).xyz("O3*") ) );
253 
254  // consider rotamers only if P-O3* distance is "similar" to that in the original structure.
255  if ( fabs( target_distance - rot_P_O3.length() ) < distance_cutoff ) {
256 
257  accept_rotamer = true;
258 
259  if ( minimize_rotamers ) {
260 // mini_pose.dump_pdb( "before_"+string_of(rotamers.size())+".pdb" );
261 
262 // PROF_START( TEST1 );
263  AtomTreeMinimizer().run( mini_pose, mm, sf, options );
264 // PROF_STOP ( TEST1 );
265 
266 // tt << "LIBR.: ";
267 // for ( int i=1; i<=5; ++i ) {
268 // tt << F(10,3,(*dihedrals)[i]);
269 // }
270 
271 // tt << std::endl << "AFTER: ";
272 // for (Size i=1; i <= 5; ++i) {
273 // TorsionID const id ( ( i==1 ) ? ( TorsionID( seqpos-1, BB, nbb ) ) : ( TorsionID( seqpos, BB, i-1 ) ) );
274 // tt << F(10,3, mini_pose.torsion( id ) );
275 // }
276 
277 // tt << std::endl << "DIFF : ";
278  for ( int i=1; i<=5; ++i ) {
279  TorsionID const id ( ( i==1 ) ? ( TorsionID( seqpos-1, BB, nbb ) ) : ( TorsionID( seqpos, BB, i-1 ) ) );
280  Real diff_i = fabs( mini_pose.torsion( id ) - (*dihedrals)[i] );
281 
282  if ( diff_i>180 )
283  diff_i = 360-diff_i;
284 
285  if ( diff_i > angle_tol )
286  accept_rotamer = false;
287 
288 // tt << F(10,3,diff_i);
289  }
290 // tt << std::endl << std::endl;
291  }
292 
293  if (accept_rotamer) {
294  Residue const &
295  cur_rsd( mini_pose.residue( seqpos ) ),
296  cur_next_rsd( mini_pose.residue(seqpos+1) );
297  Vector const cur_P_O3( ( cur_next_rsd.xyz("P") - cur_rsd.xyz("O3*") ) );
298  Real const cur_P_bond_angle ( angle_of( cur_next_rsd.xyz("O5*"), cur_next_rsd.xyz("P") , cur_rsd.xyz("O3*") ) );
299  Real const cur_O3_bond_angle( angle_of( cur_next_rsd.xyz("P") , cur_rsd.xyz("O3*"), cur_rsd.xyz("C3*") ) );
300 
301  Real const diff_length ( fabs( cur_P_O3.length() - target_distance ) );
302 
303  Real diff_P_angle ( rad2deg * fabs( cur_P_bond_angle - P_bond_angle ) );
304  Real diff_O3_angle( rad2deg * fabs( cur_O3_bond_angle - O3_bond_angle ) );
305  if ( diff_P_angle > 180 )
306  diff_P_angle = 360 - diff_P_angle;
307  if ( diff_O3_angle > 180 )
308  diff_O3_angle = 360 - diff_O3_angle;
309 
310  if ( ( diff_P_angle > angle_tol ) || ( diff_O3_angle > angle_tol ) || ( diff_length > dist_tol ) )
311  accept_rotamer = false;
312 
313 // if ( accept_rotamer )
314 // tt << "ACCEPTED: Opt. diff: P-O3=" << diff_length << ", P_bond diff=" << diff_P_angle << ", O3_bond diff=" << diff_O3_angle << std::endl;
315 // else
316 // tt << "REJECTED: Opt. diff: P-O3=" << diff_length << ", P_bond diff=" << diff_P_angle << ", O3_bond diff=" << diff_O3_angle << std::endl;
317 
318  // mini_pose.dump_pdb( "after_"+string_of(rotamers.size())+".pdb" );
319  }
320 
321  if ( accept_rotamer ) {
322  ResidueOP new_rot( mini_pose.residue(seqpos).clone() );
323 
324  // may have to do still more in current code
325  new_rot->seqpos( existing_residue.seqpos() );
326  new_rot->chain ( existing_residue.chain () );
327  new_rot->copy_residue_connections( existing_residue ); // AARGHH!!
328  rotamers.push_back( new_rot );
329  }
330  }
331  }
332  }
333 
334  tt << "Built " << rotamers.size() << " rotamers for " << resid << " " << concrete_residue->name() << std::endl;
335 }
336 
337 
338 ///////////////////////////////////////////////////////////////////////////////////////////////////
339 // move this helper function
340 // better yet, stuff inside new rotamer-building class
341 //
342 void
344  Size const resid,
345  pose::Pose const & pose,
346  chemical::ResidueTypeCOP concrete_residue,
347  pack::task::ExtraRotSample const & level,
349 )
350 {
351  using namespace pose;
352  using namespace conformation;
353  using namespace id;
354  using namespace pack::task;
355 
356 
357  Real const max_rotation( 5.0 ); // degrees
358  bool const tether_bond_distance( true );
359  bool const tether_bond_angle( false );
360 
361  int nrot_to_build(1);
362  switch ( level ) {
363  case NO_EXTRA_CHI_SAMPLES : // 0
364  nrot_to_build = 1;
365  break;
366  case EX_ONE_STDDEV : // 1
367  nrot_to_build = 10;
368  break;
369  case EX_ONE_HALF_STEP_STDDEV : // 2
370  nrot_to_build = 25;
371  break;
372  case EX_TWO_FULL_STEP_STDDEVS : // 3
373  nrot_to_build = 50;
374  break;
375  case EX_TWO_HALF_STEP_STDDEVS : // 4
376  nrot_to_build = 100;
377  break;
378  case EX_FOUR_HALF_STEP_STDDEVS : // 5
379  nrot_to_build = 250;
380  break;
381  case EX_THREE_THIRD_STEP_STDDEVS : // 6
382  nrot_to_build = 500;
383  break;
384  case EX_SIX_QUARTER_STEP_STDDEVS : // 7
385  nrot_to_build = 1000;
386  break;
388  default :
389  std::cerr << "Error in RotamerSet_::set_extrachi_samples, invalid ExtraChiSample type" << std::endl;
390  utility_exit();
391  break;
392  }
393 
394  Residue const & existing_residue( pose.residue( resid ) );
395  assert( existing_residue.is_NA() && concrete_residue->is_NA() );
396 
397  if ( existing_residue.is_terminus() ) nrot_to_build = 1;
398 
399 // basic::T( "core.pack.rotamer_set", basic::t_info ) << "Building " << nrot_to_build << " DNA rotamers for " << resid <<
400 // " " << concrete_residue->name() << '\n';
401 
402  // a residue of the correct type aligned to the existing backbone
403  ResidueOP rot = ResidueFactory::create_residue( *concrete_residue, existing_residue, pose.conformation() );
404  rot->set_chi( 1, existing_residue.chi(1) );
405 
406 // tt << "Pushing DNA rotamer " << std::endl;
407 // for( Size ii = 1 ; ii <= concrete_residue->natoms() ; ++ii) {
408 // Vector coords( rot->xyz(ii) );
409 // tt << "Atom " << concrete_residue->atom_name( ii ) <<
410 // " " << coords[0] <<
411 // " " << coords[1] <<
412 // " " << coords[2] << std::endl;
413 // }
414 
415  rotamers.push_back( rot );
416 
417  if ( nrot_to_build > 1 ) {
418 
419  ///////////////////////////////////////////////////////////////////
420  // new fancy way
421  // make a minipose
422  pose::Pose mini_pose;
423  mini_pose.append_residue_by_bond( pose.residue( resid-1 ) );
424  mini_pose.append_residue_by_bond( *rot );
425  mini_pose.append_residue_by_jump( pose.residue( resid+1 ), 1 );
426 
427  Size const seqpos(2);
428  Residue const &
429  prev_rsd( mini_pose.residue(seqpos-1) ),
430  rsd( mini_pose.residue(seqpos ) ),
431  next_rsd( mini_pose.residue(seqpos+1) );
432 
433  assert( rsd.is_DNA() && prev_rsd.is_DNA() );
434 
435  utility::vector1< Vector > bonds, atoms;
436 
437  atoms.push_back( prev_rsd.xyz("O3*") );
438  atoms.push_back( rsd.xyz( "P") );
439  atoms.push_back( rsd.xyz("O5*") );
440  atoms.push_back( rsd.xyz("C5*") );
441  atoms.push_back( rsd.xyz("C4*") );
442 
443  Vector const r( rsd.xyz("O3*") );
444 
445  Vector const n1( ( next_rsd.xyz( "P") - rsd.xyz("O3*" ) ).normalized() );
446  Vector const n2( ( next_rsd.xyz("O5*") - next_rsd.xyz( "P" ) ).normalized() );
447 
448  Real l1( 0.0 );
449  utility::vector1< Real > v1(4), v2(4);
450 
451  for ( int i=1; i<= 4; ++i ) {
452  Vector const bi( ( atoms[i+1] - atoms[i] ).normalized() );
453  Vector const ci( atoms[i+1] );
454  v1[i] = n1.dot( bi.cross( r - ci ) );
455  v2[i] = n2.dot( bi.cross( r - ci ) );
456  l1 += v1[i] * v1[i];
457  }
458 
459  // want to choose e[i] so that e dot v1 = 0 and e dot v2 = 0
460  // eg choose two indices randomly
461  // choose random values for those indices
462  // now choose the unique values of the other two e[i]'s that will give e.v1= e.v2=0
463  //
464  // even simpler, orthonormalize v1 and v2, then we start with e' and subtract off dot(e',v1)*v1 and
465  // dot(e',v2)*v2 and we are golden.
466  //
467 
468  // normalize v1, compute dot product with v2
469  l1 = std::sqrt( l1 );
470  Real v1_dot_v2(0.0);
471  for ( int i=1; i<= 4; ++i ) {
472  v1[i] /= l1;
473  v1_dot_v2 += v1[i] * v2[i];
474  }
475 
476  // now subtract
477  Real l2(0.0);
478  for ( int i=1; i<= 4; ++i ) {
479  v2[i] -= v1_dot_v2 * v1[i];
480  l2 += v2[i] * v2[i];
481  }
482  // normalize v2
483  l2 = std::sqrt(l2);
484  for ( int i=1; i<= 4; ++i ) v2[i] /= l2;
485 
486  // confirm orthogonality
487  Real tmp1(0.0), tmp2(0.0), tmp12(0.0);
488  for ( int i=1; i<= 4; ++i ) {
489  tmp1 += v1[i] * v1[i];
490  tmp2 += v2[i] * v2[i];
491  tmp12 += v1[i] * v2[i];
492  }
493  assert( std::abs(tmp1-1)<1e-3 && std::abs(tmp2-1)<1e-3 && std::abs(tmp12)<1e-3 );
494 
495 
496  // now try a bunch of moves:
497  for ( int r=1; r<= nrot_to_build-1; ++r ) {
498 
499 
500  // choose random starting points
502  Real dot1(0.0), dot2(0.0);
503  for ( int i=1; i<= 4; ++i ) {
504  e[i] = max_rotation - 2*RG.uniform()*max_rotation;
505  dot1 += e[i] * v1[i];
506  dot2 += e[i] * v2[i];
507  }
508 
509  for ( int i=1; i<= 4; ++i ) {
510  if ( tether_bond_distance ) e[i] -= dot1 * v1[i];
511  if ( tether_bond_angle ) e[i] -= dot2 * v2[i];
512  }
513 
514  { //debug
515  dot1 = 0; dot2 = 0;
516  for ( int i=1; i<= 4; ++i ) {
517  dot1 += e[i] * v1[i];
518  dot2 += e[i] * v2[i];
519  }
520  if ( tether_bond_distance ) assert( std::abs( dot1 ) < 1e-3 );
521  if ( tether_bond_angle ) assert( tether_bond_distance && std::abs( dot2 ) < 1e-3 );
522  }
523 
524 
525  Size const nbb( rsd.n_mainchain_atoms() );
526  for ( int i=1; i<= 4; ++i ) {
527 
528  TorsionID const id ( ( i==1 ) ? ( TorsionID( seqpos-1, BB, nbb ) ) : ( TorsionID( seqpos, BB, i-1 ) ) );
529  TorsionID const id0( ( i==1 ) ? ( TorsionID( resid-1, BB, nbb ) ) : ( TorsionID( resid, BB, i-1 ) ) );
530  mini_pose.set_torsion( id, pose.torsion( id0 ) + e[i] );
531  }
532 
533  if ( true ) { // chi
534  TorsionID const id ( seqpos, CHI, 1 );
535  TorsionID const id0( resid, CHI, 1 );
536  mini_pose.set_torsion( id, pose.torsion( id0 ) + max_rotation - 2*RG.uniform()*max_rotation );
537  }
538 
539  rotamers.push_back( mini_pose.residue(seqpos).clone() );
540 
541  // io::pdb::dump_pdb ( mini_pose, lead_zero_string_of(r, 4) );
542 
543  // this is a little tricky... maybe have to do more initialization here to match the "rotamer-constructor"
544  // behavior??
545  assert( Size(rot->seqpos()) == resid );
546  rotamers[ rotamers.size() ]->seqpos( resid );
547  rotamers[ rotamers.size() ]->chain( rot->chain() );
548  rotamers[ rotamers.size() ]->copy_residue_connections( existing_residue );
549 
550  // check dr:
551  //Vector const r0( mini_pose.residue(seqpos).xyz("O4*") - pose.residue(resid).xyz("O4*") );
552  //Vector const r ( mini_pose.residue(seqpos).xyz("O3*") - pose.residue(resid).xyz("O3*") );
553  //tt << "r: " << tag << F(9,3,r.length()) << F(9,3,r.dot( n1 )) << F(9,3,r.dot( n2 ) ) << std::endl;
554 
555  // confirm that phosphate is in the same place
556  assert( mini_pose.residue(seqpos ).xyz("P").distance( pose.residue(resid ).xyz("P")) < 1e-2 &&
557  mini_pose.residue(seqpos+1).xyz("P").distance( pose.residue(resid+1).xyz("P")) < 1e-2 );
558 
559  } // r =1,nrot_to_build
560  }
561 }
562 
563 
564 ///////////////////////////////////////////////////////////////////////////////////////////////////
565 void
567  Size const resid,
568  pose::Pose const & pose,
569  chemical::ResidueTypeCOP concrete_residue,
570  pack::task::PackerTask const & task,
572 )
573 {
575 
576  utility::vector1< ResidueOP > new_rotamers;
577 
578  pack::task::ExtraRotSample const level
579  ( task.residue_task( resid ).extrachi_sample_level( true /*buried*/, 1 /*chi*/, concrete_residue ) );
580 
581  // need to improve this logic:
582  if ( level == task::EX_SIX_QUARTER_STEP_STDDEVS ) {
583 
584  utility::io::izstream lib_stream;
585  basic::database::open( lib_stream, "rotamer/dna/VQ-DNA-64.rotlib" );
586 
587  // Read rotamers from rotamer library
589  read_DNA_rotlib( lib_stream, library );
590 
591  build_lib_dna_rotamers( library, resid, pose, concrete_residue, new_rotamers );
592 
593  // Close stream and free library memory
594  lib_stream.close();
595  utility::vector1< DihedralSet* >::iterator lib_iter = library.begin();
596  for ( ; lib_iter!=library.end(); lib_iter++ )
597  delete( *lib_iter );
598 
599  } else {
600  build_random_dna_rotamers( resid, pose, concrete_residue, level, new_rotamers );
601  }
602 
603  // check for compatibility
604  for ( Size ii=1; ii<= new_rotamers.size(); ++ii ) {
605  ResidueOP rot( new_rotamers[ii] );
606 
607 // for( Size i = 1 ; i <= rot->natoms() ; ++i ) {
608 // tt << "precompat " << rot->atom_name(i) <<
609 // " x " << rot->xyz(i)[0] <<
610 // " y " << rot->xyz(i)[1] <<
611 // " z " << rot->xyz(i)[2] << std::endl;
612 // }
613 
614 
615  if ( task.rotamer_couplings_exist() ) {
616  bool ok( true );
617  RotamerCouplings const & couplings( * (task.rotamer_couplings() ) );
618  int const other_resid( couplings[ resid ].first );
619  if ( other_resid && !task.pack_residue( other_resid ) ) {
620  conformation::ResidueMatcher const & matcher( *(couplings[resid].second ) );
621  if ( !matcher( *rot, pose.residue( other_resid ) ) ) {
622  ok = false;
623  }
624  }
625  if ( ok ) {
626  rotamers.push_back( rot );
627  }
628  } else {
629  //tt << "added dna rotamer: " << existing_residue.seqpos() << ' ' << existing_residue.name() << ' '<<
630  // concrete_residue->name() << std::endl;
631  rotamers.push_back( rot );
632  } // do rotamer couplings exist?
633  }
634 }
635 
636 
637 ///////////////////////////////////////////////////////////////////////////////////////////////////
638 void
641  utility::vector1< Real > const & chi_steps,
642  Real const & center, Real const & width )
643 {
644  using namespace conformation;
645  for (Size n = 1 ; n <= chi_steps.size(); n++ ) {
646  ResidueOP new_rot = rot->clone();
647  new_rot->set_chi( 1, center + chi_steps[n] * width );
648  rotamers.push_back( new_rot );
649  }
650 }
651 
652 ///////////////////////////////////////////////////////////////////////////////////////////////////
653 void
656  pack::task::ExtraRotSample const & level,
657  scoring::rna::Gaussian_parameter_set const & gaussian_parameter_set )
658 {
659  using namespace conformation;
660  using namespace scoring::rna;
661  using namespace pack::task;
662 
663  utility::vector1< Real > chi_steps;
664  chi_steps.push_back( 0.0 );
665 
666  //This copies code, unfortunately, from RotamerSet_.cc
667  switch ( level ) {
668  case NO_EXTRA_CHI_SAMPLES : // 0
669  // return;
670  break;
671  case EX_ONE_STDDEV : // 1
672  chi_steps.push_back(1);
673  chi_steps.push_back(-1);
674  break;
675  case EX_ONE_HALF_STEP_STDDEV : // 2
676  chi_steps.push_back(0.5);
677  chi_steps.push_back(-0.5);
678  break;
679  case EX_TWO_FULL_STEP_STDDEVS : // 3
680  chi_steps.push_back(1);
681  chi_steps.push_back(2);
682  chi_steps.push_back(-1);
683  chi_steps.push_back(-2);
684  break;
685  case EX_TWO_HALF_STEP_STDDEVS : // 4
686  chi_steps.push_back(0.5);
687  chi_steps.push_back(1);
688  chi_steps.push_back(-0.5);
689  chi_steps.push_back(-1);
690  break;
691  case EX_FOUR_HALF_STEP_STDDEVS : // 5
692  chi_steps.push_back(0.5);
693  chi_steps.push_back(1);
694  chi_steps.push_back(1.5);
695  chi_steps.push_back(2.0);
696  chi_steps.push_back(-0.5);
697  chi_steps.push_back(-1);
698  chi_steps.push_back(-1.5);
699  chi_steps.push_back(-2);
700  break;
701  case EX_THREE_THIRD_STEP_STDDEVS : // 6
702  chi_steps.push_back(0.33);
703  chi_steps.push_back(0.67);
704  chi_steps.push_back(1);
705  chi_steps.push_back(-0.33);
706  chi_steps.push_back(-0.67);
707  chi_steps.push_back(-1);
708  break;
709  case EX_SIX_QUARTER_STEP_STDDEVS : // 7
710  chi_steps.push_back(0.25);
711  chi_steps.push_back(0.5);
712  chi_steps.push_back(0.75);
713  chi_steps.push_back(1);
714  chi_steps.push_back(1.25);
715  chi_steps.push_back(1.5);
716  chi_steps.push_back(-0.25);
717  chi_steps.push_back(-0.5);
718  chi_steps.push_back(-0.75);
719  chi_steps.push_back(-1);
720  chi_steps.push_back(-1.25);
721  chi_steps.push_back(-1.5);
722  break;
724  default :
725  std::cerr << "Error in RotamerSet_::set_extrachi_samples, invalid ExtraChiSample type" << std::endl;
726  utility_exit();
727  break;
728  }
729 
730  Gaussian_parameter const & gaussian_parameter( gaussian_parameter_set[1] );
732  chi_steps,
733  gaussian_parameter.center, gaussian_parameter.width );
734 
735  //Add in syn configurations for purines.
736  if ( rot->aa() == chemical::na_rad || rot->aa() == chemical::na_rgu ) {
737  Gaussian_parameter const & gaussian_parameter2( gaussian_parameter_set[2] );
739  chi_steps,
740  gaussian_parameter2.center, gaussian_parameter2.width );
741  }
742 
743 }
744 
745 
746 ///////////////////////////////////////////////////////////////////////////////////////////////////
747 void
749  Size const resid,
750  pose::Pose const & pose,
751  chemical::ResidueTypeCOP concrete_residue,
752  pack::task::ExtraRotSample const & level,
753  bool const sample_rna_chi, bool const & include_current,
755 )
756 {
757  using namespace pose;
758  using namespace conformation;
759  using namespace id;
760  using namespace pack::task;
761 
762  // Real const max_rotation( 5.0 ); // degrees
763  // bool const tether_bond_distance( true );
764  // bool const tether_bond_angle( false );
765 
766  Residue const & existing_residue( pose.residue( resid ) );
767  assert( existing_residue.is_RNA() && concrete_residue->is_RNA() );
768 
769  // a residue of the correct type aligned to the existing backbone
770  ResidueOP rot = ResidueFactory::create_residue( *concrete_residue, existing_residue, pose.conformation(), false /*true*/ /*preserve c_beta*/ );
771 
772  //Copy over sugar pucker, chi angle, 2'-OH torsion ...
773  // for (Size n = 1; n <= rot->nchi(); n++ ) {
774  // rot->set_chi( n, existing_residue.chi(n) );
775  // }
776 
777  //To define base, need a torsion that depends on sugar pucker...
778  static scoring::rna::RNA_FittedTorsionInfo const rna_fitted_torsion_info;
779  static Real const delta_cutoff = rna_fitted_torsion_info.delta_cutoff();
780 
781  //Different chi angles depending on sugar pucker.
782  Real const delta( existing_residue.mainchain_torsion( scoring::rna::DELTA ) );
783  // if ( delta <= delta_cutoff ) {
784  // rot->set_chi( 3 /*nu1*/ , rna_fitted_torsion_info.gaussian_parameter_set_nu1_north()[1].center );
785  // } else { // South, or 2'-endo sugar pucker.
786  // rot->set_chi( 3 /*nu1*/ , rna_fitted_torsion_info.gaussian_parameter_set_nu1_south()[1].center );
787  // }
788 
789 
790  // Note: do not necessarily include current chi, unless specified by user!
791  if ( include_current && sample_rna_chi ) {
792  //Can't make a direct copy, but use ideal bonds/angles for base, and copy chi
793  ResidueOP new_rot = rot->clone();
794  rotamers.push_back( new_rot );
795  }
796 
797  if (!sample_rna_chi && level == 0) return;
798 
799  //Different chi angles depending on sugar pucker.
800  if ( delta <= delta_cutoff ) {
801  add_rna_chi_rotamers( rot, rotamers, level, rna_fitted_torsion_info.gaussian_parameter_set_chi_north() );
802  } else {
803  add_rna_chi_rotamers( rot, rotamers, level, rna_fitted_torsion_info.gaussian_parameter_set_chi_south() );
804  }
805 
806 
807 
808 }
809 
810 ///////////////////////////////////////////////////////////////////////////////////////////////////
811 void
813  Size const resid,
814  pose::Pose const & pose,
815  chemical::ResidueTypeCOP concrete_residue,
816  pack::task::PackerTask const & task,
818  Size & id_for_current_rotamer
819 )
820 {
821  using namespace conformation;
822 
823  pack::task::ExtraRotSample const level
824  ( task.residue_task( resid ).extrachi_sample_level( true /*buried*/, 1 /*chi*/, concrete_residue ) );
825 
826  //////////////////////////////////////////////////////////////////////////
827  //////////////////////////////////////////////////////////////////////////
828  // Basic set up...
829  build_rna_chi_rotamers( resid, pose, concrete_residue, level,
830  task.residue_task( resid ).sample_rna_chi(),
831  task.include_current( resid ),
832  new_rotamers );
833 
834  //////////////////////////////////////////////////////////////////////////
835  // include current... this doesn't use ideal bond lengths/angles.
836  Residue const & existing_residue( pose.residue( resid ));
837  if ( task.include_current( resid ) && existing_residue.name() == concrete_residue->name() ) {
838  ResidueOP rot = existing_residue.create_rotamer();
839  new_rotamers.push_back( rot );
840  id_for_current_rotamer = new_rotamers.size();
841  }
842 
843 
844  ///////////////////////////////////////////////////////////
845  ///////////////////////////////////////////////////////////
846  //Expand proton chi? For RNA, this covers the 2'-OH torsion -- critical!.
847  // This is a pretty generic operation
848  // Should be its own method?
849  // Combine ligand stuff?
850  // Combine protein proton chi stuff?
851  if ( task.residue_task( resid ).sample_proton_chi() ) {
852  Size const n_proton_chi = concrete_residue->n_proton_chi();
853 
854  if ( n_proton_chi > 0 ) {
855  //This seems a little silly -- suck out the chi's, then put them back into rotamers.
857  proton_chi_chisets.push_back( new pack::dunbrack::ChiSet( concrete_residue->nchi() ) );
858 
859  for ( Size ii = 1; ii <= n_proton_chi; ++ii ) {
861  task.residue_task( resid ).extrachi_sample_level(
862  true /*nneighb test*/,
863  concrete_residue->proton_chi_2_chi( ii ),
864  concrete_residue ),
865  concrete_residue,
866  ii, proton_chi_chisets);
867  }
868  // tt << "EXTRA CHI SETS: " << proton_chi_chisets.size() << std::endl;
869 
870  Size const number_of_starting_new_rotamers = new_rotamers.size();
871  for ( Size n = 1 ; n <= number_of_starting_new_rotamers; ++n ) {
872 
873  for ( Size ii = 1; ii <= proton_chi_chisets.size(); ++ii ) {
874 
875  new_rotamers.push_back( new_rotamers[n]->clone() );
876  Size const new_rotamer_number = new_rotamers.size();
877 
878  for ( Size jj = 1; jj <= n_proton_chi; ++jj ) {
879 
880  Size const jj_protchi( concrete_residue->proton_chi_2_chi( jj ) );
881  new_rotamers[ new_rotamer_number ]->set_chi( jj_protchi,
882  proton_chi_chisets[ ii ]->chi[ jj_protchi ] );
883  }
884  }
885 
886  }
887  }
888  } //proton chi
889 
890 }
891 
892 ///////////////////////////////////////////////////////////////////////////////////////////////////
893 void
896 )
897 {
899 
900  for ( Size ii=1; ii<= rotamers.size(); ++ii ) {
901  ResidueOP rot( rotamers[ii] );
902 
903  tt << "Rotamer at position " << rot->seqpos() << std::endl;
904  tt << " of type " << rot->type().name() << std::endl;
905 
906  for( Size jj=1; jj <= rot->natoms() ; ++jj ){
907  conformation::Atom const & atm = rot->atom( jj );
908  tt << "Atom " << rot->atom_name( jj ) << " at " << atm.xyz()[0] << " " << atm.xyz()[1] << " " << atm.xyz()[2] << std::endl;
909  }
910  }
911 }
912 
913 ///////////////////////////////////////////////////////////////////////////////////////////////////
916  chemical::ResidueType const & h2o_type,
917  Vector const & xyz_atom1,
918  Vector const & xyz_O,
919  Vector const & xyz_atom2,
920  std::string const & name1,
921  std::string const & name2,
922  conformation::Residue const & tp5 // for the approx geometry of the lone pairs
923 )
924 {
925 
926 
927  Vector const tp5_O( tp5.xyz("O") ), tp5_atom1( tp5.xyz( name1 ) ), tp5_atom2( tp5.xyz( name2 ) );
928 
929  Vector const xyz_midpoint( xyz_O + ( xyz_atom1 - xyz_O ).normalized() + ( xyz_atom2 - xyz_O ).normalized() );
930  Vector const tp5_midpoint( tp5_O + ( tp5_atom1 - tp5_O ).normalized() + ( tp5_atom2 - tp5_O ).normalized() );
931 
932  kinematics::Stub const xyz_stub( xyz_O, xyz_midpoint, xyz_atom1 );
933  kinematics::Stub const tp5_stub( tp5_O, tp5_midpoint, tp5_atom1 );
934 
936  assert( rot->natoms() == 3 );
937  rot->set_xyz( "O", xyz_O );
938  rot->set_xyz( "H1", xyz_stub.local2global( tp5_stub.global2local( tp5.xyz("H1") ) ) );
939  rot->set_xyz( "H2", xyz_stub.local2global( tp5_stub.global2local( tp5.xyz("H2") ) ) );
940  return rot;
941 }
942 
943 ///////////////////////////////////////////////////////////////////////////////////////////////////
944 void
946  Size const seqpos,
947  chemical::ResidueType const & h2o_type,
948  pose::Pose const & pose,
949  graph::GraphCOP packer_neighbor_graph,
951 )
952 {
953  using conformation::Residue;
955  using numeric::conversions::degrees;
956 
957  static Real const heavy_atom_cutoff2( 3.3 * 3.3 );
958  Real const min_theta( 90.0 );
959  Real const max_theta( 180.0 );
960 
961 
962  assert( h2o_type.natoms() == 3 ); // only works for this guy now
963 
964  Residue const & existing_rsd( pose.residue(seqpos) );
965  Vector const & xyz_O( existing_rsd.nbr_atom_xyz() );
966 
967  chemical::ResidueTypeSet const & residue_set( h2o_type.residue_type_set() );
968 
969  // logic: look for nearby donors/acceptors
970  // look for acceptors within 3.2
971  // look for donors with:
972  // (a) donor-base distance < 3.2 (could be more subtle by requiring good hydrogen geometry if that H isnt moving)
973  // (b) ...
974 
975  utility::vector1< Vector > acceptors, donors;
976 
978  ir = packer_neighbor_graph->get_node( seqpos )->const_edge_list_begin(),
979  ire = packer_neighbor_graph->get_node( seqpos )->const_edge_list_end();
980  ir != ire; ++ir ) {
981  Size const i( (*ir)->get_other_ind( seqpos ) );
982  assert( i != seqpos );
983  Residue const & rsd( pose.residue(i) );
984 
985  // donors
986  for ( chemical::AtomIndices::const_iterator
987  hnum = rsd.Hpos_polar().begin(),
988  hnume = rsd.Hpos_polar().end(); hnum != hnume; ++hnum ) {
989  Vector const & xyz( rsd.xyz( rsd.atom_base( *hnum ) ) );
990  if ( xyz_O.distance_squared( xyz ) < heavy_atom_cutoff2 ) {
991  donors.push_back( xyz );
992  }
993  }
994 
995  // acceptors
996  for ( chemical::AtomIndices::const_iterator
997  anum = rsd.accpt_pos().begin(),
998  anume = rsd.accpt_pos().end(); anum != anume; ++anum ) {
999  Vector const & xyz( rsd.xyz( *anum ) );
1000  if ( xyz_O.distance_squared( xyz ) < heavy_atom_cutoff2 ) {
1001  acceptors.push_back( xyz );
1002  }
1003  }
1004  } // i=1,nres
1005 
1006 
1007  ResidueOP tp5( conformation::ResidueFactory::create_residue( residue_set.name_map("TP5") ) );
1008 
1009  for ( Size i=1; i<= donors.size(); ++i ) {
1010  Vector const & xyz1( donors[i] );
1011 
1012  // donor-donor pairs ////////////////////////////////
1013  for ( Size j=i+1; j<= donors.size(); ++j ) {
1014  Vector const & xyz2( donors[j] );
1015 
1016  Real const theta( degrees( angle_of( xyz1, xyz_O, xyz2 ) ) );
1017  if ( theta > min_theta && theta < max_theta ) {
1018 
1019  new_rotamers.push_back( create_oriented_water_rotamer( h2o_type, xyz1, xyz_O, xyz2, "EP1", "EP2", *tp5 ) );
1020 
1021  }
1022  }
1023 
1024  // donor-acceptor pairs /////////////////////////////
1025  for ( Size j=1; j<= acceptors.size(); ++j ) {
1026  Vector const & xyz2( acceptors[j] );
1027 
1028  Real const theta( degrees( angle_of( xyz1, xyz_O, xyz2 ) ) );
1029  if ( theta > min_theta && theta < max_theta ) {
1030 
1031  new_rotamers.push_back( create_oriented_water_rotamer( h2o_type, xyz1, xyz_O, xyz2, "EP1", "H1", *tp5 ) );
1032  new_rotamers.push_back( create_oriented_water_rotamer( h2o_type, xyz1, xyz_O, xyz2, "EP1", "H2", *tp5 ) );
1033 
1034  }
1035  }
1036  }
1037 
1038  // acceptor-acceptor pairs ////////////////////////////
1039  for ( Size i=1; i<= acceptors.size(); ++i ) {
1040  Vector const & xyz1( acceptors[i] );
1041  for ( Size j=i+1; j<= acceptors.size(); ++j ) {
1042  Vector const & xyz2( acceptors[j] );
1043  Real const theta( degrees( angle_of( xyz1, xyz_O, xyz2 ) ) );
1044 
1045  if ( theta > min_theta && theta < max_theta ) {
1046  new_rotamers.push_back( create_oriented_water_rotamer( h2o_type, xyz1, xyz_O, xyz2, "H1", "H2", *tp5 ) );
1047  }
1048 
1049  }
1050  }
1051 
1052 
1053  // update sequence position and chain information
1054  for ( Size i=1; i<= new_rotamers.size(); ++i ) {
1055  new_rotamers[i]->seqpos( seqpos );
1056  new_rotamers[i]->chain( existing_rsd.chain() );
1057  }
1058 
1059 
1060  // now loop over pairs
1061  tt << "build_water_rotamers seqpos= " << seqpos << " found " << donors.size() << " nearby donors, " <<
1062  acceptors.size() << " nearby acceptors. Built " << new_rotamers.size() << " rotamers." << std::endl;
1063 
1064 
1065 
1066 }
1067 
1068 
1069 ///////////////////////////////////////////////////////////////////////////////////////////////////
1070 ///////////////////////////////////////////////////////////////////////////////////////////////////
1071 ///////////////////////////////////////////////////////////////////////////////////////////////////
1072 ///////////////////////////////////////////////////////////////////////////////////////////////////
1073 ///////////////////////////////////////////////////////////////////////////////////////////////////
1074 ///////////////////////////////////////////////////////////////////////////////////////////////////
1075 
1076 Vector
1078  Vector const & hxyz,
1079  Vector const & dxyz
1080 )
1081 {
1082 
1083  Real const distance( 2.75 );
1084 
1085  return ( dxyz + distance * ( hxyz - dxyz ).normalized() );
1086 }
1087 
1088 
1089 void
1091  Vector const & a_xyz,
1092  Vector b1_xyz, // local copy
1093  Vector const & b2_xyz,
1094  chemical::Hybridization const & hybrid,
1096 )
1097 {
1098  using numeric::conversions::radians;
1099  using namespace chemical;
1100 
1101  Real const distance( 2.75 ); // acceptor--O distance
1102 
1103  Real theta(0.0), step_size(0.0);
1104  utility::vector1< Real > phi_list, phi_steps;
1105  phi_steps.push_back( -4 );
1106  phi_steps.push_back( -2 );
1107  phi_steps.push_back( -1 );
1108  phi_steps.push_back( 0 );
1109  phi_steps.push_back( 1 );
1110  phi_steps.push_back( 2 );
1111  phi_steps.push_back( 4 );
1112 
1113  switch( hybrid ) {
1114  case SP2_HYBRID:
1115  theta = 180.0 - 120.0;
1116  step_size = 15.0;
1117  phi_list.push_back( 0.0 );
1118  phi_list.push_back( 180.0 );
1119  break;
1120  case SP3_HYBRID:
1121  theta = 180.0 - 109.0;
1122  step_size = 10.0;
1123  phi_list.push_back( 120.0 );
1124  phi_list.push_back( 240.0 );
1125  break;
1126  case RING_HYBRID:
1127  b1_xyz = 0.5 * ( b1_xyz + b2_xyz );
1128  theta = 0.0;
1129  phi_steps.clear();
1130  phi_steps.push_back( 0.0 );
1131  phi_list.push_back( 0.0 ); // doesnt matter
1132  step_size = 0.0; // doesnt matter
1133  break;
1134  default:
1135  tt << "Bad hybridization type for acceptor " << hybrid << '\n';
1136  utility_exit();
1137  }
1138 
1139  kinematics::Stub stub( a_xyz, b1_xyz, b2_xyz );
1140  for ( Size i=1; i<= phi_list.size(); ++i ) {
1141  for ( Size j=1; j<= phi_steps.size(); ++j ) {
1142  O_list.push_back( stub.spherical( radians( phi_list[i] + step_size * phi_steps[j]), radians( theta ), distance));
1143  }
1144  }
1145 }
1146 
1147 
1148 
1149 void
1151  conformation::Residue const & rsd1,
1152  Size const hatm1,
1153  conformation::Residue const & rsd2,
1154  Size const hatm2,
1155  chemical::ResidueType const & h2o_type,
1156  conformation::Residue const & tp5,
1157  Size const nstep,
1159 )
1160 {
1161  using namespace scoring::hbonds;
1162  HBondDatabaseCOP hb_database( HBondDatabase::get_database() );
1163  HBondOptions hbondopts; // default ctor, reads from command line
1164 
1165  Real const o12_dis2_cutoff( 25.0 ); // wild guess
1166  Real const hbond_energy_threshold( -0.10 );
1167 
1168  Vector const & hatm1_xyz( rsd1.xyz( hatm1 ) );
1169  Vector const & datm1_xyz( rsd1.xyz( rsd1.atom_base( hatm1 ) ) );
1170  Vector const & hatm2_xyz( rsd2.xyz( hatm2 ) );
1171  Vector const & datm2_xyz( rsd2.xyz( rsd2.atom_base( hatm2 ) ) );
1172 
1173  Vector const o1( build_optimal_water_O_on_donor( hatm1_xyz, datm1_xyz ) );
1174  Vector const o2( build_optimal_water_O_on_donor( hatm2_xyz, datm2_xyz ) );
1175 
1176  Real const o12_dis2( o1.distance_squared( o2 ) );
1177  if ( o1.distance_squared( o2 ) > o12_dis2_cutoff ) return;
1178 
1179  assert( nstep >= 2 && nstep%2 == 0 );
1180  for ( Size step=0; step<= nstep; ++step ) {
1181 
1182  // calculate an intermediate water position
1183  Vector const xyz_O( o1 + ( Real(step)/nstep) * ( o2 - o1 ) );
1184 
1186  rot( create_oriented_water_rotamer( h2o_type, hatm1_xyz, xyz_O, hatm2_xyz, "EP1", "EP2", tp5 ) );
1187 
1188  /// evaluate the energy of the two hbonds
1189  Real energy1(0.0), energy2(0.0);
1190  HBEvalTuple hbe1(
1191  get_hb_don_chem_type(rsd1.atom_base(hatm1),rsd1),
1192  hbacc_H2O,
1193  seq_sep_other);
1194  hb_energy_deriv( *hb_database, hbondopts, hbe1, datm1_xyz, hatm1_xyz,
1195  rot->xyz("O"), rot->xyz("H1"), rot->xyz("H2"), energy1 );
1196 
1197  //if ( energy1 > hbond_energy_threshold ) return;
1198 
1199  HBEvalTuple hbe2(
1200  get_hb_don_chem_type(rsd2.atom_base(hatm2),rsd2),
1201  hbacc_H2O,
1202  seq_sep_other);
1203  hb_energy_deriv( *hb_database, hbondopts, hbe2, datm2_xyz, hatm2_xyz,
1204  rot->xyz("O"), rot->xyz("H1"), rot->xyz("H2"), energy2 );
1205 
1206  if ( energy1 > hbond_energy_threshold ) return;
1207  if ( energy2 > hbond_energy_threshold ) return;
1208 
1209  tt << "hbenergies: dd step= " << step << " nstep= " << nstep <<
1210  " E1= " << ObjexxFCL::fmt::F(9,3,energy1) << " E2= " << ObjexxFCL::fmt::F(9,3,energy2) <<
1211  " o12_distance= " << ObjexxFCL::fmt::F(9,3,std::sqrt( o12_dis2 )) << '\n';
1212 
1213 
1214  // accept this rotamer
1215  new_waters.push_back( rot );
1216  }
1217 }
1218 
1219 
1220 void
1222  conformation::Residue const & rsd1,
1223  Size const hatm1,
1224  conformation::Residue const & rsd2,
1225  Size const aatm2,
1226  chemical::ResidueType const & h2o_type,
1227  conformation::Residue const & tp5,
1228  Size const nstep,
1230 )
1231 {
1232  using namespace scoring::hbonds;
1233  HBondDatabaseCOP hb_database( HBondDatabase::get_database());
1234  HBondOptions hbondopts; // default ctor, reads from command line
1235 
1236  Real const o12_dis2_cutoff( 25.0 ); // wild guess
1237  Real const hbond_energy_threshold( -0.10 );
1238 
1239  Vector const & hatm1_xyz( rsd1.xyz( hatm1 ) );
1240  Vector const & datm1_xyz( rsd1.xyz( rsd1.atom_base( hatm1 ) ) );
1241  Vector const & aatm2_xyz( rsd2.xyz( aatm2 ) );
1242  Vector const & aatm2_base_xyz( rsd2.xyz( rsd2.atom_base( aatm2 ) ) );
1243  Vector const & aatm2_base2_xyz( rsd2.xyz( rsd2.abase2( aatm2 ) ) );
1244 
1245  Vector const o1( build_optimal_water_O_on_donor( hatm1_xyz, datm1_xyz ) );
1246  utility::vector1< Vector > o2_pos_list;
1247  chemical::Hybridization const & hybrid( rsd2.atom_type(aatm2).hybridization() );
1248  build_optimal_water_Os_on_acceptor( aatm2_xyz, aatm2_base_xyz, aatm2_base2_xyz, hybrid, o2_pos_list );
1249 
1250  for ( Size jj=1; jj<= o2_pos_list.size(); ++jj ) {
1251  Vector const & o2( o2_pos_list[jj] );
1252 
1253  Real const o12_dis2( o1.distance_squared( o2 ) );
1254  if ( o1.distance_squared( o2 ) > o12_dis2_cutoff ) continue;
1255 
1256  assert( nstep>= 2 && nstep%2 == 0 );
1257 
1258  for ( Size step=0; step<= nstep; ++step ) {
1259 
1260  // calculate an intermediate water position
1261  Vector const xyz_O( o1 + ( Real(step)/nstep) * ( o2 - o1 ) );
1262 
1264  ( create_oriented_water_rotamer( h2o_type, hatm1_xyz, xyz_O, aatm2_xyz, "EP1", "H1", tp5 ) );
1265 
1266  /// evaluate the energy of the two hbonds
1267 
1268  // donor to water
1269  Real energy1(0.0);
1270  HBEvalTuple const hbe_type( get_hb_don_chem_type( rsd1.atom_base( hatm1 ), rsd1 ), hbacc_H2O, seq_sep_other);
1271  hb_energy_deriv( *hb_database, hbondopts, hbe_type, datm1_xyz, hatm1_xyz,
1272  rot->xyz("O"), rot->xyz("H1"), rot->xyz("H2"), energy1 );
1273 
1274  //if ( energy1 > hbond_energy_threshold ) continue;
1275 
1276  Real energy2(0.0);
1277  { // water to acceptor
1278  using namespace chemical;
1279  HBEvalTuple const hbe_type
1280  ( hbdon_H2O, get_hb_acc_chem_type( aatm2, rsd2 ) , seq_sep_other);
1281  hb_energy_deriv( *hb_database, hbondopts, hbe_type, rot->xyz("O"), rot->xyz("H1"),
1282  aatm2_xyz, aatm2_base_xyz, aatm2_base2_xyz, energy2 );
1283  }
1284 
1285  if ( energy1 > hbond_energy_threshold ) continue;
1286  if ( energy2 > hbond_energy_threshold ) continue;
1287 
1288  tt << "hbenergies: da step= " << step << " nstep= " << nstep <<
1289  " E1= " << ObjexxFCL::fmt::F(9,3,energy1) << " E2= " << ObjexxFCL::fmt::F(9,3,energy2) <<
1290  " o12_distance= " << ObjexxFCL::fmt::F(9,3,std::sqrt( o12_dis2 )) << '\n';
1291 
1292 
1293 
1294  // accept this rotamer
1295  new_waters.push_back( rot );
1296  new_waters.push_back( create_oriented_water_rotamer( h2o_type, hatm1_xyz, xyz_O, aatm2_xyz,
1297  "EP1", "H2", tp5 ) );
1298 // {
1299 // using namespace ObjexxFCL;
1300 // using namespace ObjexxFCL::fmt;
1301 
1302 // std::string const filename( "donor_acceptor_test_"+lead_zero_string_of(counter,4)+"_"+
1303 // lead_zero_string_of(step,4)+".pdb" );
1304 
1305 // tt << "hbenergy_da: step " << I(4,step) << F(9,3,energy1) << F(9,3,energy2) <<
1306 // F(9,3,std::sqrt(o12_dis2)) << ' '<< filename << '\n';
1307 
1308 // pose::Pose pose;
1309 // pose.append_residue_by_jump( rsd1, 1 );
1310 // pose.append_residue_by_jump( rsd2, 1 );
1311 // pose.append_residue_by_jump( *rot, 1 );
1312 // pose.dump_pdb( filename );
1313 // }
1314 
1315  }
1316  }
1317 }
1318 
1319 
1320 void
1322  conformation::Residue const & rsd1,
1323  Size const aatm1,
1324  conformation::Residue const & rsd2,
1325  Size const aatm2,
1326  chemical::ResidueType const & h2o_type,
1327  conformation::Residue const & tp5,
1328  Size const nstep,
1330 )
1331 {
1332  using namespace scoring::hbonds;
1333  HBondDatabaseCOP hb_database( HBondDatabase::get_database());
1334  HBondOptions hbondopts; // default ctor, reads from command line
1335 
1336  Real const o12_dis2_cutoff( 25.0 ); // wild guess
1337  Real const hbond_energy_threshold( -0.10 );
1338 
1339  Vector const & aatm1_xyz( rsd1.xyz( aatm1 ) );
1340  Vector const & aatm1_base_xyz( rsd1.xyz( rsd1.atom_base( aatm1 ) ) );
1341  Vector const & aatm1_base2_xyz( rsd1.xyz( rsd1.abase2( aatm1 ) ) );
1342 
1343  Vector const & aatm2_xyz( rsd2.xyz( aatm2 ) );
1344  Vector const & aatm2_base_xyz( rsd2.xyz( rsd2.atom_base( aatm2 ) ) );
1345  Vector const & aatm2_base2_xyz( rsd2.xyz( rsd2.abase2( aatm2 ) ) );
1346 
1347  utility::vector1< Vector > o1_pos_list;
1348  chemical::Hybridization const & hybrid1( rsd1.atom_type(aatm1).hybridization() );
1349  build_optimal_water_Os_on_acceptor( aatm1_xyz, aatm1_base_xyz, aatm1_base2_xyz, hybrid1, o1_pos_list );
1350 
1351  utility::vector1< Vector > o2_pos_list;
1352  chemical::Hybridization const & hybrid2( rsd2.atom_type(aatm2).hybridization() );
1353  build_optimal_water_Os_on_acceptor( aatm2_xyz, aatm2_base_xyz, aatm2_base2_xyz, hybrid2, o2_pos_list );
1354 
1355  for ( Size ii=1; ii<= o1_pos_list.size(); ++ii ) {
1356  Vector const & o1( o1_pos_list[ii] );
1357 
1358  for ( Size jj=1; jj<= o2_pos_list.size(); ++jj ) {
1359  Vector const & o2( o2_pos_list[jj] );
1360 
1361  Real const o12_dis2( o1.distance_squared( o2 ) );
1362  if ( o1.distance_squared( o2 ) > o12_dis2_cutoff ) continue;
1363 
1364  assert( nstep>= 2 && nstep%2 == 0 );
1365 
1366  for ( Size step=0; step<= nstep; ++step ) {
1367 
1368  // calculate an intermediate water position
1369  Vector const xyz_O( o1 + ( Real(step)/nstep) * ( o2 - o1 ) );
1370 
1371 
1373  ( create_oriented_water_rotamer( h2o_type, aatm1_xyz, xyz_O, aatm2_xyz, "H1", "H2", tp5 ) );
1374 
1375  /// evaluate the energy of the two hbonds
1376  Real energy1(0.0), energy2( 0.0 );
1377 
1378  { // water to acceptor1
1379  using namespace chemical;
1380  HBEvalTuple const hbe_type( hbdon_H2O, get_hb_acc_chem_type( aatm1, rsd1 ), seq_sep_other);
1381  hb_energy_deriv( *hb_database, hbondopts, hbe_type, rot->xyz("O"), rot->xyz("H1"),
1382  aatm1_xyz, aatm1_base_xyz, aatm1_base2_xyz, energy1 );
1383  }
1384 
1385  { // water to acceptor
1386  using namespace chemical;
1387  HBEvalTuple const hbe_type
1388  ( hbdon_H2O, get_hb_acc_chem_type( aatm2, rsd2 ), seq_sep_other);
1389  hb_energy_deriv( *hb_database, hbondopts, hbe_type, rot->xyz("O"), rot->xyz("H2"),
1390  aatm2_xyz, aatm2_base_xyz, aatm2_base2_xyz, energy2 );
1391  }
1392 
1393  if ( energy1 > hbond_energy_threshold ) continue;
1394  if ( energy2 > hbond_energy_threshold ) continue;
1395 
1396  tt << "hbenergies: aa step= " << step << " nstep= " << nstep <<
1397  " E1= " << ObjexxFCL::fmt::F(9,3,energy1) << " E2= " << ObjexxFCL::fmt::F(9,3,energy2) <<
1398  " o12_distance= " << ObjexxFCL::fmt::F(9,3,std::sqrt( o12_dis2 )) << '\n';
1399 
1400 
1401 
1402  // accept this rotamer
1403  new_waters.push_back( rot );
1404  } // step=0,nstep
1405  }
1406  }
1407 }
1408 
1409 
1410 void
1412  conformation::Residue const & rsd1,
1413  Size const anchor_atom,
1414  conformation::Residue const & rsd2,
1415  chemical::ResidueType const & h2o_type,
1416  conformation::Residue const & tp5,
1417  Size const nstep,
1418 // utility::vector1< id::AtomID > & atom_ids,
1420 )
1421 {
1422  Real const dis2_cutoff( 36.0 );
1423 
1425 
1426  tt << "build_moving_O_bridge_waters " << rsd1.seqpos() << ' ' << rsd1.name() << ' ' << rsd2.seqpos() <<
1427  ' ' << rsd2.name() << '\n';
1428 
1429  // get info about the anchor atom
1430  bool const anchor_is_donor( rsd1.atom_type( anchor_atom ).is_polar_hydrogen() );
1431  Vector const & anchor_xyz( rsd1.xyz( anchor_atom ) );
1432 
1433  // look for donors or acceptors that could be making an interaction with the water
1434  //
1435  // donors
1436  for ( chemical::AtomIndices::const_iterator
1437  hnum = rsd2.Hpos_polar().begin(),
1438  hnume = rsd2.Hpos_polar().end(); hnum != hnume; ++hnum ) {
1439  Size const hatm( *hnum );
1440 
1441  if ( rsd2.xyz( hatm ).distance_squared( anchor_xyz ) > dis2_cutoff ) continue;
1442 
1443  Size const old_size( new_rotamers.size() );
1444 
1445  if ( anchor_is_donor ) {
1446  build_donor_donor_waters( rsd1, anchor_atom, rsd2, hatm, h2o_type, tp5, nstep, new_rotamers );
1447  } else {
1448  build_donor_acceptor_waters( rsd2, hatm, rsd1, anchor_atom, h2o_type, tp5, nstep, new_rotamers );
1449  }
1450 
1451  if ( new_rotamers.size() > old_size ) {
1452  tt << "built " << new_rotamers.size() - old_size << " rotamers between " <<
1453  rsd1.seqpos() << ' ' << rsd1.name() << ' ' << rsd1.atom_name( anchor_atom ) << " and " <<
1454  rsd2.seqpos() << ' ' << rsd2.name() << ' ' << rsd2.atom_name( hatm ) << '\n';
1455  atom_ids.push_back( id::AtomID( hatm, rsd2.seqpos() ) );
1456  }
1457  }
1458 
1459  // acceptors
1460  for ( chemical::AtomIndices::const_iterator
1461  anum = rsd2.accpt_pos().begin(),
1462  anume = rsd2.accpt_pos().end(); anum != anume; ++anum ) {
1463  Size const aatm( *anum );
1464 
1465  if ( rsd2.xyz( aatm ).distance_squared( anchor_xyz ) > dis2_cutoff ) continue;
1466 
1467  Size const old_size( new_rotamers.size() );
1468 
1469  if ( anchor_is_donor ) {
1470  build_donor_acceptor_waters( rsd1, anchor_atom, rsd2, aatm, h2o_type, tp5, nstep, new_rotamers );
1471  } else {
1472  build_acceptor_acceptor_waters( rsd1, anchor_atom, rsd2, aatm, h2o_type, tp5, nstep, new_rotamers );
1473  }
1474 
1475  if ( new_rotamers.size() > old_size ) {
1476  tt << "built " << new_rotamers.size() - old_size << " rotamers between " <<
1477  rsd1.seqpos() << ' ' << rsd1.name() << ' ' << rsd1.atom_name( anchor_atom ) << " and " <<
1478  rsd2.seqpos() << ' ' << rsd2.name() << ' ' << rsd2.atom_name( aatm ) << '\n';
1479  atom_ids.push_back( id::AtomID( aatm, rsd2.seqpos() ) );
1480  }
1481  }
1482 }
1483 
1484 void
1486  RotamerSets const & rotsets,
1487  //Size const seqpos_water,
1488  WaterAnchorInfo const & water_info,
1489  chemical::ResidueType const & h2o_type,
1490  pack::task::PackerTask const & task,
1491  pose::Pose const & pose,
1492  graph::GraphCOP packer_neighbor_graph,
1494 )
1495 {
1496  using conformation::Residue;
1498  using numeric::conversions::degrees;
1499 
1500  assert( h2o_type.natoms() == 3 ); // only works for this guy now
1501 
1502  Size nstep( water_info.nstep() );
1503  if ( nstep < 2 ) nstep = 2;
1504  if ( nstep%2 == 1 ) ++nstep;
1505 
1506  // who are we "attached to" ?
1507  //
1508  //
1509 
1510  Size const i( water_info.anchor_residue() );
1511 
1512  tt << "build_moving_O_water_rotamers_dependent: anchor_pos= " << i << '\n';
1513 
1514  // build a tp5 water for geometry calculations below
1516 
1517  // build a list of residue/rotamers at this dna position to loop over
1519  if ( task.pack_residue(i) ) {
1520  // get the rotamerset
1521  RotamerSetCOP rotset( rotsets.rotamer_set_for_residue( i ) );
1522  for ( Size ii=1; ii<= rotset->num_rotamers(); ++ii ) {
1523  rsd1_list.push_back( rotset->rotamer(ii)() );
1524  }
1525  } else {
1526  rsd1_list.push_back( &(pose.residue(i) ) );
1527  }
1528 
1529  // here we assume that the two residues bridged by water must be neighbors...
1530  // this may not be completely true: D-O + A-O could be bigger than 5.5, but prob not much
1531  //
1532  // may want to refine this
1533 
1535  jr = packer_neighbor_graph->get_node( i )->const_edge_list_begin(),
1536  jre = packer_neighbor_graph->get_node( i )->const_edge_list_end();
1537  jr != jre; ++jr ) {
1538  Size const j( (*jr)->get_other_ind( i ) );
1539  assert( i != j );
1540 
1541  //if ( !pose.residue(j).is_protein() ) continue; // first just protein-DNA bridges
1542  if ( pose.residue(j).name() == "TP3" ) continue;
1543 
1544  // fixed-fixed interactions were already hit inside the first pass of building
1545  if ( !task.pack_residue( i ) && !task.pack_residue( j ) ) continue;
1546 
1548  if ( task.pack_residue(j) ) {
1549  // get the rotamerset
1550  RotamerSetCOP rotset( rotsets.rotamer_set_for_residue( j ) );
1551  for ( Size jj=1; jj<= rotset->num_rotamers(); ++jj ) {
1552  rsd2_list.push_back( rotset->rotamer(jj)() );
1553  }
1554  } else {
1555  rsd2_list.push_back( &(pose.residue(j) ) );
1556  }
1557 
1558 
1559  /// now loop over residue pairs
1560 
1561  /// now build the waters
1562  for ( Size ii=1; ii<= rsd1_list.size(); ++ii ) {
1563  Residue const & rsd1( *rsd1_list[ii] );
1564  if ( ! water_info.attaches_to_residue_type( rsd1.type() ) ) continue;
1565  Size const anchor_atom( water_info.anchor_atom( rsd1.type() ) );
1566 
1567  for ( Size jj=1; jj<= rsd2_list.size(); ++jj ) {
1568  build_moving_O_bridge_waters( rsd1, anchor_atom, *( rsd2_list[jj] ), h2o_type, *tp5, nstep, new_rotamers );
1569  }
1570  }
1571  } // nbrs of anchor_pos
1572 }
1573 
1574 ///////////////////////////////////////////////////////////////////////////////////////////////////
1575 void
1577  WaterAnchorInfo const & water_info,
1578  chemical::ResidueType const & h2o_type,
1579  pack::task::PackerTask const & task,
1580  pose::Pose const & pose,
1581  graph::GraphCOP packer_neighbor_graph,
1583 )
1584 {
1585  using conformation::Residue;
1587  using numeric::conversions::degrees;
1588 
1589  assert( h2o_type.natoms() == 3 ); // only works for this guy now
1590 
1591  Size nstep( water_info.nstep() );
1592  if ( nstep < 2 ) nstep = 2;
1593  if ( nstep%2 == 1 ) ++nstep;
1594 
1595  Size const i( water_info.anchor_residue() );
1596 
1597  tt << "build_moving_O_water_rotamers_independent: anchor_pos= " << i << '\n';
1598 
1599  if ( task.pack_residue(i) ) return; // have to wait
1600 
1601  Residue const & rsd1( pose.residue(i) );
1602  if ( ! water_info.attaches_to_residue_type( rsd1.type() ) ) return;
1603  Size const anchor_atom( water_info.anchor_atom( rsd1.type() ) );
1604 
1605  // build a tp5 water for geometry calculations below
1607 
1608  // here we assume that the two residues bridged by water must be neighbors...
1609  // this may not be completely true: D-O + A-O could be bigger than 5.5, but prob not much
1610  //
1611  // may want to refine this
1612 
1614  jr = packer_neighbor_graph->get_node( i )->const_edge_list_begin(),
1615  jre = packer_neighbor_graph->get_node( i )->const_edge_list_end();
1616  jr != jre; ++jr ) {
1617  Size const j( (*jr)->get_other_ind( i ) );
1618  assert( i != j );
1619 
1620  //if ( !pose.residue(j).is_protein() ) continue; // first just protein-DNA bridges
1621  if ( pose.residue(j).name() == "TP3" ) continue;
1622 
1623  if ( task.pack_residue( j ) ) continue;
1624 
1625  build_moving_O_bridge_waters( rsd1, anchor_atom, pose.residue(j), h2o_type, *tp5, nstep, new_rotamers );
1626 
1627  } // nbrs of anchor_pos
1628 }
1629 
1630 void
1632  Size const seqpos_water,
1633  chemical::ResidueType const & h2o_type,
1634  pack::task::PackerTask const & task,
1635  pose::Pose const & pose,
1636  graph::GraphCOP packer_neighbor_graph,
1638 )
1639 {
1640  //using core::pose::datacache::CacheableDataType::WATER_PACKING_INFO;
1641 
1642  {
1643  tt << "water " << seqpos_water << " nbrs:";
1645  jr = packer_neighbor_graph->get_node( seqpos_water )->const_edge_list_begin(),
1646  jre = packer_neighbor_graph->get_node( seqpos_water )->const_edge_list_end();
1647  jr != jre; ++jr ) {
1648  tt << ' ' << (*jr)->get_other_ind( seqpos_water );
1649  }
1650  tt << '\n';
1651  }
1652 
1653 
1655  WaterPackingInfo const & water_info
1656  ( static_cast< WaterPackingInfo const & >( pose.data().get( core::pose::datacache::CacheableDataType::WATER_PACKING_INFO ) ) );
1657 
1658  build_moving_O_water_rotamers_independent( water_info[ seqpos_water], h2o_type, task, pose,
1659  packer_neighbor_graph, new_rotamers );
1660  } else {
1661 
1662  build_fixed_O_water_rotamers_independent( seqpos_water, h2o_type, pose, packer_neighbor_graph, new_rotamers );
1663 
1664  }
1665 }
1666 
1667 
1668 void
1670  RotamerSets const & rotsets,
1671  Size const seqpos_water,
1672  chemical::ResidueType const & h2o_type,
1673  pack::task::PackerTask const & task,
1674  pose::Pose const & pose,
1675  graph::GraphCOP packer_neighbor_graph,
1677 )
1678 {
1679  //using core::pose::datacache::CacheableDataType::WATER_PACKING_INFO;
1680 
1682  WaterPackingInfo const & water_info
1683  ( static_cast< WaterPackingInfo const & >( pose.data().get( core::pose::datacache::CacheableDataType::WATER_PACKING_INFO ) ) );
1684 
1685  build_moving_O_water_rotamers_dependent( rotsets, /*seqpos_water,*/ water_info[ seqpos_water], h2o_type, task, pose,
1686  packer_neighbor_graph, new_rotamers );
1687  } else {
1688 
1689  // doesnt exist yet
1690  //build_fixed_O_water_rotamers_dependent( rotsets, seqpos_water, h2o_type, pose, packer_neighbor_graph,
1691  // new_rotamers );
1692 
1693  }
1694 
1695 
1696 
1697 }
1698 } // rotamer_set
1699 } // pack
1700 } // core
1701