Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
MMBondAngleEnergy.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/scoring/methods/MMBondAngleAnergy.cc
11 /// @brief molecular mechanics torsion energy
12 /// @author Colin A. Smith (colin.smith@ucsf.edu)
13 
14 // Unit headers
17 
18 // Package headers
21 
22 // Project headers
24 #include <core/chemical/AtomType.hh> // for is_virtual()
28 #include <core/pose/Pose.hh>
29 #include <basic/Tracer.hh>
30 
31 // Utility headers
32 #include <utility/string_util.hh>
33 
34 // Numeric headers
35 #include <numeric/xyz.functions.hh>
36 #include <numeric/deriv/angle_deriv.hh>
37 
38 // C++ headers
39 #include <iostream>
40 
41 #include <core/id/AtomID.hh>
42 #include <utility/vector1.hh>
43 
44 
45 namespace core {
46 namespace scoring {
47 namespace methods {
48 
49 
50 /// @details This must return a fresh instance of the MMBondAngleEnergy class,
51 /// never an instance already in use
54  methods::EnergyMethodOptions const & options
55 ) const {
56  return new MMBondAngleEnergy( options );
57 }
58 
61  ScoreTypes sts;
62  sts.push_back( mm_bend );
63  return sts;
64 }
65 
66 
67 static basic::Tracer TR("core.mm.MMBondAngleEnergy");
68 
71  param_set_( NULL ),
72  central_atoms_to_score_( options.bond_angle_central_atoms_to_score() )
73 {
74  if ( options.bond_angle_residue_type_param_set() ) {
76  }
77  //param_set_ = new core::scoring::mm::MMBondAngleResidueTypeParamSet();
78 }
79 
81  parent( src ),
82  param_set_( NULL ),
83  central_atoms_to_score_( src.central_atoms_to_score_ )
84 {
85  if ( src.param_set_ ) {
87  }
88 }
89 
91 
92 
93 /// clone
96 {
97  return new MMBondAngleEnergy( *this );
98 }
99 
100 ///
101 void
103  pose::Pose & pose,
104  utility::vector1< bool > const &,
105  utility::vector1< bool > const & ) const
106 {
108  pose.update_actcoords();
109 }
110 
111 ///
112 void
114 {
116  pose.update_actcoords();
117 
118  // make sure the parameters for all residues are loaded
119  if ( param_set_ ) {
120  for ( Size i = 1; i <= pose.total_residue(); ++i ) {
121  param_set_->get(pose.residue_type(i));
122  }
123  }
124 }
125 
126 ///
127 void
129 {
131  pose.update_actcoords();
132 }
133 
134 ///
135 bool
137 {
138  return true;
139 }
140 
141 void
143  conformation::Residue const & rsd1,
144  conformation::Residue const & rsd2,
145  pose::Pose const & pose,
146  ScoreFunction const & ,
147  EnergyMap & emap
148 ) const
149 {
150  // bail out if the residues aren't bonded
151  if (!rsd1.is_bonded(rsd2)) return;
152 
153  Real energy = 0;
154 
155 /*
156  //TR << "Processing residues " << rsd1.seqpos() << "-" << rsd2.seqpos() << std::endl;
157 
158  // get residue types
159  chemical::ResidueType const & rsd_type1 = rsd1.type();
160  chemical::ResidueType const & rsd_type2 = rsd2.type();
161 
162  utility::vector1< Size > const resconn_ids( rsd1.connections_to_residue( rsd2 ) );
163 
164  // loop over all connections of residue 1 to residue 2
165  for ( Size i = 1; i <= resconn_ids.size(); ++i ) {
166 
167  // get residue connection ids
168  Size const resconn_id1( resconn_ids[i] );
169  Size const resconn_id2( rsd1.residue_connection_conn_id( resconn_id1 ) );
170 
171  // get connection atom numbers
172  Size const resconn_atomno1( rsd1.residue_connection( resconn_id1 ).atomno() );
173  Size const resconn_atomno2( rsd2.residue_connection( resconn_id2 ).atomno() );
174 
175  // get mm atom type indecies
176  Size resconn_mmat1 = rsd_type1.mm_atom_type_index( resconn_atomno1 );
177  Size resconn_mmat2 = rsd_type2.mm_atom_type_index( resconn_atomno2 );
178 
179  // determine if residue connection atoms should be scored
180  bool should_score1(true);
181  bool should_score2(true);
182 
183  if (central_atoms_to_score_.size()) {
184 
185  should_score1 = false;
186  for ( Size central_atomindex = 1; central_atomindex <= central_atoms_to_score_.size(); ++central_atomindex) {
187  if (rsd_type1.has_atom_name(central_atoms_to_score_[central_atomindex]) &&
188  rsd_type1.atom_index(central_atoms_to_score_[central_atomindex]) == resconn_atomno1) {
189  should_score1 = true;
190  break;
191  }
192  }
193 
194  should_score2 = false;
195  for ( Size central_atomindex = 1; central_atomindex <= central_atoms_to_score_.size(); ++central_atomindex) {
196  if (rsd_type2.has_atom_name(central_atoms_to_score_[central_atomindex]) &&
197  rsd_type2.atom_index(central_atoms_to_score_[central_atomindex]) == resconn_atomno2) {
198  should_score2 = true;
199  break;
200  }
201  }
202  }
203 
204  //TR << "Found residue connection id " << resconn_id1 << "-" << resconn_id2 << ": "
205  //<< rsd1.atom_name( resconn_atomno1 ) << "-" << rsd2.atom_name( resconn_atomno2 ) << "\n";
206 
207  if (should_score1) {
208  core::chemical::AtomIndices const & bonded_neighbors1( rsd1.bonded_neighbor( resconn_atomno1 ) );
209  Size const num_bonded_neighbors1( bonded_neighbors1.size() );
210 
211  // loop over all atoms neighboring resconn_atomno1
212  for ( Size neighbor = 1; neighbor <= num_bonded_neighbors1; ++neighbor ) {
213 
214  // get neihbor atom number and mm atom type index
215  Size const neighbor_atomno( bonded_neighbors1[neighbor] );
216  Size neighbor_mmat = rsd_type1.mm_atom_type_index( neighbor_atomno );
217 
218  // get angle
219  Real angle = numeric::angle_radians( rsd1.atom( neighbor_atomno ).xyz(), rsd1.atom( resconn_atomno1 ).xyz(),
220  rsd2.atom( resconn_atomno2 ).xyz() );
221 
222  //TR << rsd1.atom_name( neighbor_atomno ) << "(" << rsd_type1.atom( neighbor_atomno ).mm_name() << ") - "
223  //<< rsd1.atom_name( resconn_atomno1 ) << "(" << rsd_type1.atom( resconn_atomno1 ).mm_name() << ") - "
224  //<< rsd2.atom_name( resconn_atomno2 ) << "(" << rsd_type2.atom( resconn_atomno2 ).mm_name() << ")" << std::endl;
225 
226  // score bond angle
227  energy += potential_.mm::MMBondAngleScore::score
228  ( mm::mm_bondangle_atom_tri( neighbor_mmat, resconn_mmat1, resconn_mmat2 ), angle );
229 
230  // debug code
231  //TR << rsd1.atom_name( neighbor_atomno ) << "(" << rsd_type1.atom( neighbor_atomno ).mm_name() << ") - "
232  //<< rsd1.atom_name( resconn_atomno1 ) << "(" << rsd_type1.atom( resconn_atomno1 ).mm_name() << ") - "
233  //<< rsd2.atom_name( resconn_atomno2 ) << "(" << rsd_type2.atom( resconn_atomno2 ).mm_name() << ") \t"
234  //<< potential_.mm::MMBondAngleScore::score
235  //( mm::mm_bondangle_atom_tri( neighbor_mmat, resconn_mmat1, resconn_mmat2 ), angle ) << std::endl;
236  }
237  }
238 
239  if (should_score2) {
240  core::chemical::AtomIndices const & bonded_neighbors2( rsd2.bonded_neighbor( resconn_atomno2 ) );
241  Size const num_bonded_neighbors2( bonded_neighbors2.size() );
242 
243  // loop over all atoms neighboring resconn_atomno2
244  for ( Size neighbor = 1; neighbor <= num_bonded_neighbors2; ++neighbor ) {
245 
246  // get neihbor atom number and mm atom type index
247  Size const neighbor_atomno( bonded_neighbors2[neighbor] );
248  Size neighbor_mmat = rsd_type2.mm_atom_type_index( neighbor_atomno );
249 
250  // get angle
251  Real angle = numeric::angle_radians( rsd1.atom( resconn_atomno1 ).xyz(), rsd2.atom( resconn_atomno2 ).xyz(),
252  rsd2.atom( neighbor_atomno ).xyz() );
253 
254  //TR << rsd1.atom_name( resconn_atomno1 ) << "(" << rsd_type1.atom( resconn_atomno1 ).mm_name() << ") - "
255  //<< rsd2.atom_name( resconn_atomno2 ) << "(" << rsd_type2.atom( resconn_atomno2 ).mm_name() << ") - "
256  //<< rsd2.atom_name( neighbor_atomno ) << "(" << rsd_type2.atom( neighbor_atomno ).mm_name() << ")" << std::endl;
257 
258  // score bond angle
259  energy += potential_.mm::MMBondAngleScore::score
260  ( mm::mm_bondangle_atom_tri( resconn_mmat1, resconn_mmat2, neighbor_mmat ), angle );
261 
262  // debug code
263  //TR << rsd1.atom_name( resconn_atomno1 ) << "(" << rsd_type1.atom( resconn_atomno1 ).mm_name() << ") - "
264  //<< rsd2.atom_name( resconn_atomno2 ) << "(" << rsd_type2.atom( resconn_atomno2 ).mm_name() << ") - "
265  //<< rsd2.atom_name( neighbor_atomno ) << "(" << rsd_type2.atom( neighbor_atomno ).mm_name() << ") \t"
266  //<< potential_.mm::MMBondAngleScore::score
267  //( mm::mm_bondangle_atom_tri( resconn_mmat1, resconn_mmat2, neighbor_mmat ), angle ) << std::endl;
268  }
269  }
270  }
271 
272 */
273 
274 /**/
275 
276  // get residue types
277  chemical::ResidueType const & rsd1_type = rsd1.type();
278  chemical::ResidueType const & rsd2_type = rsd2.type();
279 
280  TR(basic::t_trace) << "residue_pair_energy: processing residues "
281  << rsd1.seqpos() << "." << rsd1_type.name() << "-"
282  << rsd2.seqpos() << "." << rsd2_type.name() << std::endl;
283 
284  utility::vector1< Size > const & r1_resconn_ids( rsd1.connections_to_residue( rsd2 ) );
285 
286  for ( Size ii = 1; ii <= r1_resconn_ids.size(); ++ii ) {
287 
288  Size const resconn_id1( r1_resconn_ids[ii] );
289  Size const resconn_id2( rsd1.residue_connection_conn_id( resconn_id1 ) );
290 
291  Size const resconn_atomno1( rsd1.residue_connection( resconn_id1 ).atomno() );
292  Size const resconn_atomno2( rsd2.residue_connection( resconn_id2 ).atomno() );
293 
294 
295  TR(basic::t_trace) << "Found residue connection id " << resconn_id1 << "-" << resconn_id2 << ": "
296  << rsd1.atom_name( resconn_atomno1 ) << "-" << rsd2.atom_name( resconn_atomno2 ) << std::endl;
297 
298  Size const resconn_mmat1 = rsd1_type.atom( resconn_atomno1 ).mm_atom_type_index();
299  Size const resconn_mmat2 = rsd2_type.atom( resconn_atomno2 ).mm_atom_type_index();
300 
301  /// Score only a subset of the bong angles using the central_atoms_to_score_ list
302  /// of atom names. If this list is empty, then score all atom pairs.
303  /// determine if residue connection atoms should be scored
304  bool should_score1( true );
305  bool should_score2( true );
306 
307  if ( !param_set_ && central_atoms_to_score_.size() != 0 ) {
308  should_score1 = score_atom_centrally( rsd1_type, resconn_atomno1 );
309  should_score2 = score_atom_centrally( rsd2_type, resconn_atomno2 );
310  }
311 
312  if ( should_score1 ) {
313  /// compute the bond-angle energies from pairs of atoms within-1 bond on rsd1 with
314  /// the the connection atom on rsd2.
315  utility::vector1< chemical::two_atom_set > const & rsd1_atoms_wi1_bond_of_ii(
316  rsd1_type.atoms_within_one_bond_of_a_residue_connection( resconn_id1 ));
317  for ( Size jj = 1; jj <= rsd1_atoms_wi1_bond_of_ii.size(); ++jj ) {
318  assert( rsd1_atoms_wi1_bond_of_ii[ jj ].key1() == resconn_atomno1 );
319  Size const res1_lower_atomno = rsd1_atoms_wi1_bond_of_ii[ jj ].key2();
320  Size const res1_lower_mmtype = rsd1_type.atom( res1_lower_atomno ).mm_atom_type_index();
321 
322  Real const angle = numeric::angle_radians(
323  rsd1.atom( res1_lower_atomno ).xyz(),
324  rsd1.atom( resconn_atomno1 ).xyz(),
325  rsd2.atom( resconn_atomno2 ).xyz() );
326 
327  TR(basic::t_trace)
328  << "r1 " << res1_lower_atomno << " " << rsd1.atom_name( res1_lower_atomno ) << "("
329  << rsd1_type.atom( res1_lower_atomno ).mm_name() << ") - "
330  << "r1 " << resconn_atomno1 << " " << rsd1.atom_name( resconn_atomno1 ) << "("
331  << rsd1_type.atom( resconn_atomno1 ).mm_name() << ") - "
332  << "r2 " << resconn_atomno2 << " " << rsd2.atom_name( resconn_atomno2 ) << "("
333  << rsd2_type.atom( resconn_atomno2 ).mm_name() << ")" << std::endl;
334 
335  if ( param_set_ ) {
336 
337  // lookup Ktheta and theta0
338  Real Ktheta;
339  Real theta0;
340  param_set_->lookup(
341  pose.conformation(),
342  id::AtomID(res1_lower_atomno, rsd1.seqpos()),
343  id::AtomID(resconn_atomno1, rsd1.seqpos()),
344  id::AtomID(resconn_atomno2, rsd2.seqpos()),
345  Ktheta,
346  theta0
347  );
348 
349  // accumulate the energy
350  energy += potential_.score( Ktheta, theta0, angle );
351 
352  continue;
353  }
354 
355  energy += potential_.mm::MMBondAngleScore::score
356  ( mm::mm_bondangle_atom_tri( res1_lower_mmtype, resconn_mmat1, resconn_mmat2 ), angle );
357 
358  //TR << rsd1.atom_name( res1_lower_atomno ) << "(" << rsd1_type.atom( res1_lower_atomno ).mm_name() << ") - "
359  //<< rsd1.atom_name( resconn_atomno1 ) << "(" << rsd1_type.atom( resconn_atomno1 ).mm_name() << ") - "
360  //<< rsd2.atom_name( resconn_atomno2 ) << "(" << rsd2_type.atom( resconn_atomno2 ).mm_name() << ") \t"
361  //<< potential_.mm::MMBondAngleScore::score
362  //( mm::mm_bondangle_atom_tri( res1_lower_mmtype, resconn_mmat1, resconn_mmat2 ), angle ) << std::endl;
363 
364  }
365  }
366 
367  if ( should_score2 ) {
368  /// compute the bond-angle energies from pairs of atoms within-1 bond on rsd2 with
369  /// the the connection atom on rsd1.
370  utility::vector1< chemical::two_atom_set > const & rsd2_atoms_wi1_bond_of_ii(
371  rsd2_type.atoms_within_one_bond_of_a_residue_connection( resconn_id2 ));
372  for ( Size jj = 1; jj <= rsd2_atoms_wi1_bond_of_ii.size(); ++jj ) {
373  assert( rsd2_atoms_wi1_bond_of_ii[ jj ].key1() == resconn_atomno2 );
374  Size const res2_lower_atomno = rsd2_atoms_wi1_bond_of_ii[ jj ].key2();
375  Size const res2_lower_mmtype = rsd2_type.atom( res2_lower_atomno ).mm_atom_type_index();
376 
377  Real const angle = numeric::angle_radians(
378  rsd2.atom( res2_lower_atomno ).xyz(),
379  rsd2.atom( resconn_atomno2 ).xyz(),
380  rsd1.atom( resconn_atomno1 ).xyz() );
381 
382  TR(basic::t_trace) << "r2 " << res2_lower_atomno << " "
383  << rsd2.atom_name( res2_lower_atomno ) << "("
384  << rsd2_type.atom( res2_lower_atomno ).mm_name() << ") - " << "r2 " << resconn_atomno2
385  << " " << rsd2.atom_name( resconn_atomno2 ) << "("
386  << rsd2_type.atom( resconn_atomno2 ).mm_name() << ") - " << "r1 " << resconn_atomno1
387  << " " << rsd1.atom_name( resconn_atomno1 ) << "("
388  << rsd1_type.atom( resconn_atomno1 ).mm_name() << ")" << std::endl;
389 
390  if ( param_set_ ) {
391 
392  // lookup Ktheta and theta0
393  Real Ktheta;
394  Real theta0;
395  param_set_->lookup(
396  pose.conformation(),
397  id::AtomID(res2_lower_atomno, rsd2.seqpos()),
398  id::AtomID(resconn_atomno2, rsd2.seqpos()),
399  id::AtomID(resconn_atomno1, rsd1.seqpos()),
400  Ktheta,
401  theta0
402  );
403 
404  // accumulate the energy
405  energy += potential_.score( Ktheta, theta0, angle );
406 
407  continue;
408  }
409 
410  energy += potential_.mm::MMBondAngleScore::score
411  ( mm::mm_bondangle_atom_tri( res2_lower_mmtype, resconn_mmat2, resconn_mmat1 ), angle );
412  //TR << rsd2.atom_name( res2_lower_atomno ) << "(" << rsd2_type.atom( res2_lower_atomno ).mm_name() << ") - "
413  //<< rsd2.atom_name( resconn_atomno2 ) << "(" << rsd2_type.atom( resconn_atomno2 ).mm_name() << ") - "
414  //<< rsd1.atom_name( resconn_atomno1 ) << "(" << rsd1_type.atom( resconn_atomno1 ).mm_name() << ") \t"
415  //<< potential_.mm::MMBondAngleScore::score
416  //( mm::mm_bondangle_atom_tri( res2_lower_mmtype, resconn_mmat2, resconn_mmat1 ), angle ) << std::endl;
417 
418  }
419  }
420 
421  }
422 /**/
423  emap[ mm_bend ] += energy;
424 }
425 
426 void
428  conformation::Residue const & rsd,
429  pose::Pose const & ,
430  ScoreFunction const & ,
431  EnergyMap & emap
432 ) const
433 {
434  Real energy = 0;
435 
436  // get residue type
437  chemical::ResidueType const & rsd_type = rsd.type();
438 
439  if (param_set_) {
440 
441  mm::MMBondAngleResidueTypeParam const & rsd_param(param_set_->get(rsd_type));
442 
443  for ( Size bondang = 1; bondang <= rsd_param.num_bondangles(); ++bondang ) {
444 
445  if ( rsd_param.Ktheta( bondang ) ) {
446 
447  // get ResidueType ints
448  Size rt1 = ( rsd_param.bondangle( bondang ) ).key1();
449  Size rt2 = ( rsd_param.bondangle( bondang ) ).key2();
450  Size rt3 = ( rsd_param.bondangle( bondang ) ).key3();
451 
452  // get angle
453  Real angle = numeric::angle_radians
454  ( rsd.atom( rt1 ).xyz(), rsd.atom( rt2 ).xyz(), rsd.atom( rt3 ).xyz() );
455 
456  // accumulate the energy
457  energy += potential_.score( rsd_param.Ktheta( bondang ), rsd_param.theta0( bondang ), angle );
458  }
459  }
460 
461  // add energy to emap
462  emap[ mm_bend ] += energy;
463 
464  return;
465  }
466 
467  TR(basic::t_trace) << "MMIntrares Processing residue " << rsd.seqpos() << " " << rsd_type.name()
468  << std::endl;
469 
470  // for each dihedral angle in the residue type
471  for ( Size bondang = 1; bondang <= rsd_type.num_bondangles(); ++bondang )
472  {
473  // get ResidueType ints
474  Size rt1 = ( rsd_type.bondangle( bondang ) ).key1();
475  Size rt2 = ( rsd_type.bondangle( bondang ) ).key2();
476  Size rt3 = ( rsd_type.bondangle( bondang ) ).key3();
477 
478  if (central_atoms_to_score_.size()) {
479 
480  bool should_score( score_atom_centrally( rsd_type, rt2 ));
481  if (!should_score) continue;
482  }
483 
484  // check for vrt
485  if ( rsd_type.atom_type(rt1).is_virtual()
486  || rsd_type.atom_type(rt2).is_virtual()
487  || rsd_type.atom_type(rt3).is_virtual() )
488  continue;
489 
490  // get mm atom type index
491  int mmat1 = rsd_type.atom( rt1 ).mm_atom_type_index();
492  int mmat2 = rsd_type.atom( rt2 ).mm_atom_type_index();
493  int mmat3 = rsd_type.atom( rt3 ).mm_atom_type_index();
494 
495  // get angle
496  Real angle = numeric::angle_radians
497  ( rsd.atom( rt1 ).xyz(), rsd.atom( rt2 ).xyz(), rsd.atom( rt3 ).xyz() );
498 
499  TR(basic::t_trace) << rt1 << " " << rsd.atom_name( rt1 ) << "(" << rsd_type.atom( rt1 ).mm_name()
500  << ") - " << rt2 << " " << rsd.atom_name( rt2 ) << "(" << rsd_type.atom( rt2 ).mm_name()
501  << ") - " << rt3 << " " << rsd.atom_name( rt3 ) << "(" << rsd_type.atom( rt3 ).mm_name()
502  << ") angle " << angle << std::endl;
503 
504  // score bond angle
505  energy += potential_.mm::MMBondAngleScore::score
506  ( mm::mm_bondangle_atom_tri( mmat1, mmat2, mmat3 ), angle );
507 
508  // debug code
509  //TR << rsd.atom_name( rt1 ) << "(" << rsd_type.atom( rt1 ).mm_name() << ") - "
510  // << rsd.atom_name( rt2 ) << "(" << rsd_type.atom( rt2 ).mm_name() << ") - "
511  // << rsd.atom_name( rt3 ) << "(" << rsd_type.atom( rt3 ).mm_name() << ") \t"
512  // << potential_.mm::MMBondAngleScore::score
513  // ( mm::mm_bondangle_atom_tri( mmat1, mmat2, mmat3 ), angle ) << std::endl;
514  }
515 
516  // add energy to emap
517  emap[ mm_bend ] += energy;
518 }
519 
520 bool
522  core::chemical::ResidueType const & restype,
523  Size atomno
524 ) const
525 {
526  if ( central_atoms_to_score_.size() == 0 ) return true;
527 
528  for ( Size ii = 1; ii <= central_atoms_to_score_.size(); ++ii ) {
529  if ( utility::same_ignoring_spaces( restype.atom_name( atomno ), central_atoms_to_score_[ ii ] )) {
530  //std::cout << "Counting atom " << atomno << " " << restype.name() << " " << restype.atom_name( atomno ) << std::endl;
531  return true;
532  }
533  }
534  return false;
535 }
536 
537 void
539  id::AtomID const & id,
540  pose::Pose const & pose,
541  kinematics::DomainMap const &,
542  ScoreFunction const &,
543  EnergyMap const & weights,
544  Vector & F1,
545  Vector & F2
546 ) const
547 {
548  //TR << "Evaluating derivatives for rsd# " << id.rsd() << " atom# " << id.atomno() << std::endl;
549 
550  Vector LF1( 0.0 );
551  Vector LF2( 0.0 );
552 
553  //Vector f1(0.0), f2(0.0);
554  /// 0. If we're scoring only a subset of atom centers,
555  /// Ask if this atom should be scored as a center atom and
556  /// then for each neighbor of this atom, ask if
557  /// it should be scored. If this atom forms an inter-residue
558  /// connection or is bonded to an atom that does, figure out
559  /// if the interresidue bond angles should be scored.
560  /// 1. Evaluate intraresidue bond angle derivatives.
561  /// for bonds where this atom is scored
562  /// 2. Evaluate interresidue bond angle derivatives.
563  /// KNOWN BUG: This does not evaluate derivatives for bond angles
564  /// spanning three or more residues.
565  /// a. Calculate derivatives when exactly two of the atoms come from id.rsd()
566  /// b. Calculate derivatives when exactly one of the atoms comes from id.rsd()
567 
568  core::chemical::ResidueType const & restype( pose.residue_type( id.rsd() ) );
569  core::conformation::Residue const & res( pose.residue( id.rsd() ) );
570  Size const atomno( id.atomno());
571 
572  bool const score_everything( central_atoms_to_score_.size() == 0 || param_set_ );
573  bool const score_this_atom_centrally( score_everything || score_atom_centrally( restype, atomno ));
574 
575  /// 1.
576  utility::vector1< Size > const & angs( restype.bondangles_for_atom( id.atomno() ) );
577 
578  for ( Size ii = 1, ii_end = angs.size(); ii <= ii_end; ++ii ) {
579  chemical::bondangle_atom_set const & ii_bangle( restype.bondangle( angs[ ii ] ) );
580  assert( ii_bangle.key1() == atomno || ii_bangle.key2() == atomno || ii_bangle.key3() == atomno );
581  if ( score_everything ||
582  ( score_this_atom_centrally && ii_bangle.key2() == atomno ) ||
583  ( score_atom_centrally( restype, ii_bangle.key2() ) ) ) { // could be faster here
584 
585  //TR << " 1. Deriv for angle# " << angs[ ii ] << " between " << ii_bangle.key1() << " " << ii_bangle.key2() << " " << ii_bangle.key3() << std::endl;
586 
587  Real Ktheta;
588  Real theta0;
589  if ( param_set_ ) {
590  param_set_->lookup(
591  pose.conformation(),
592  id::AtomID(ii_bangle.key1(), id.rsd()),
593  id::AtomID(ii_bangle.key2(), id.rsd()),
594  id::AtomID(ii_bangle.key3(), id.rsd()),
595  Ktheta,
596  theta0
597  );
598  // skip this bond angle if Ktheta is 0
599  if ( !Ktheta ) continue;
600  }
601 
602  // check for vrt
603  if ( restype.atom_type(ii_bangle.key1()).is_virtual()
604  || restype.atom_type(ii_bangle.key2()).is_virtual()
605  || restype.atom_type(ii_bangle.key3()).is_virtual() )
606  continue;
607 
608  Vector f1(0.0), f2(0.0);
609  Real theta(0.0);
610  if ( ii_bangle.key1() == atomno ) {
611  numeric::deriv::angle_p1_deriv(
612  res.xyz( ii_bangle.key1() ),
613  res.xyz( ii_bangle.key2() ),
614  res.xyz( ii_bangle.key3() ),
615  theta, f1, f2 );
616  } else if ( ii_bangle.key2() == atomno ) {
617  numeric::deriv::angle_p2_deriv(
618  res.xyz( ii_bangle.key1() ),
619  res.xyz( ii_bangle.key2() ),
620  res.xyz( ii_bangle.key3() ),
621  theta, f1, f2 );
622  } else {
623  numeric::deriv::angle_p1_deriv(
624  res.xyz( ii_bangle.key3() ),
625  res.xyz( ii_bangle.key2() ),
626  res.xyz( ii_bangle.key1() ),
627  theta, f1, f2 );
628  }
629 
630  Real dE_dtheta;
631  if ( param_set_ ) {
632  dE_dtheta = weights[ mm_bend ] * potential_.dscore( Ktheta, theta0, theta );
633  } else {
634  Size const mmat1 = restype.atom( ii_bangle.key1() ).mm_atom_type_index();
635  Size const mmat2 = restype.atom( ii_bangle.key2() ).mm_atom_type_index();
636  Size const mmat3 = restype.atom( ii_bangle.key3() ).mm_atom_type_index();
637 
638  dE_dtheta = weights[ mm_bend ] * potential_.mm::MMBondAngleScore::dscore(
639  mm::mm_bondangle_atom_tri( mmat1, mmat2, mmat3 ), theta );
640  }
641  //TR << " theta " << numeric::conversions::degrees( theta ) << " dE_dtheta " << dE_dtheta << " f1: " << f1.x() << " " << f1.y() << " " << f1.z() << " f2: " << f2.x() << " " << f2.y() << " " << f2.z() << std::endl;
642 
643 
644  LF1 += dE_dtheta * f1;
645  LF2 += dE_dtheta * f2;
646  }
647 
648  }
649 
650  /// 2.
651  /// a. Bond angles involving two atoms on this residue.
652  utility::vector1< std::pair< Size, Size > > const & interres_wi1_for_this_atom(
653  restype.within1bonds_sets_for_atom( atomno ));
654  for ( Size ii = 1; ii <= interres_wi1_for_this_atom.size(); ++ii ) {
655  Size const ii_resconn = interres_wi1_for_this_atom[ ii ].first;
656  Size const ii_whichpair = interres_wi1_for_this_atom[ ii ].second;
657  chemical::two_atom_set const & ii_pair = restype.
658  atoms_within_one_bond_of_a_residue_connection( ii_resconn )[ ii_whichpair ];
659  assert( ii_pair.key1() == atomno || ii_pair.key2() == atomno );
660 
661  /// Find the neighbor residue and atom
662  Size const ii_neighb = res.residue_connection_partner( ii_resconn );
663  Size const neighb_resconn = res.residue_connection_conn_id( ii_resconn );
664  conformation::Residue const & neighb_res( pose.residue( ii_neighb ));
665  chemical::ResidueType const & neighb_restype( pose.residue_type( ii_neighb ) );
666  Size const neighb_atom = neighb_restype.residue_connection( neighb_resconn ).atomno();
667 
668  if ( score_everything ||
669  ( score_this_atom_centrally && ii_pair.key1() == atomno ) ||
670  ( score_atom_centrally( restype, ii_pair.key1() )) ) {
671 
672  //TR << " 2a. Deriv for interres angle between (" << ii_neighb << "," << neighb_atom << ") " << ii_pair.key1() << " " << ii_pair.key2() << std::endl;
673 
674  Real Ktheta;
675  Real theta0;
676  if ( param_set_ ) {
677  param_set_->lookup(
678  pose.conformation(),
679  id::AtomID(neighb_atom, neighb_res.seqpos()),
680  id::AtomID(ii_pair.key1(), id.rsd()),
681  id::AtomID(ii_pair.key2(), id.rsd()),
682  Ktheta,
683  theta0
684  );
685  // skip this bond angle if Ktheta is 0
686  if ( !Ktheta ) continue;
687  }
688 
689  Vector f1(0.0), f2(0.0);
690  Real theta(0.0);
691  if ( ii_pair.key1() == atomno ) {
692  numeric::deriv::angle_p2_deriv(
693  neighb_res.xyz( neighb_atom ),
694  res.xyz( ii_pair.key1() ),
695  res.xyz( ii_pair.key2() ),
696  theta, f1, f2 );
697  } else { // ( ii_pair.key2() == atomno )
698  numeric::deriv::angle_p1_deriv(
699  res.xyz( ii_pair.key2() ),
700  res.xyz( ii_pair.key1() ),
701  neighb_res.xyz( neighb_atom ),
702  theta, f1, f2 );
703  }
704 
705  Real dE_dtheta;
706  if ( param_set_ ) {
707  dE_dtheta = weights[ mm_bend ] * potential_.dscore( Ktheta, theta0, theta );
708  } else {
709  Size const mmat1 = neighb_restype.atom( neighb_atom ).mm_atom_type_index();
710  Size const mmat2 = restype.atom( ii_pair.key1() ).mm_atom_type_index();
711  Size const mmat3 = restype.atom( ii_pair.key2() ).mm_atom_type_index();
712 
713  dE_dtheta = weights[ mm_bend ] * potential_.mm::MMBondAngleScore::dscore(
714  mm::mm_bondangle_atom_tri( mmat1, mmat2, mmat3 ), theta );
715  }
716 
717  //TR << " theta " << numeric::conversions::degrees( theta ) << " dE_dtheta " << dE_dtheta << " f1: " << f1.x() << " " << f1.y() << " " << f1.z() << " f2: " << f2.x() << " " << f2.y() << " " << f2.z() << std::endl;
718 
719  LF1 += dE_dtheta * f1;
720  LF2 += dE_dtheta * f2;
721  }
722  }
723 
724  /// b. Bond angles involving two atoms on the neighbor residues.
725  /// Iterate across residue connections for this atom -- for each residue connection,
726  /// find the residue connection partner, and the list of within-1-bond atom pairs
727  /// for the atom forming the residue connection. Then iterate across this list.
728  utility::vector1< Size > const & connections( restype.residue_connections_for_atom( atomno ) );
729  for ( Size ii = 1; ii <= connections.size(); ++ii ) {
730  Size const ii_resconn = connections[ ii ];
731 
732  /// Find the neighbor residue and connection atom
733  Size const ii_neighb = res.residue_connection_partner( ii_resconn );
734  Size const neighb_resconn = res.residue_connection_conn_id( ii_resconn );
735  conformation::Residue const & neighb_res( pose.residue( ii_neighb ));
736  chemical::ResidueType const & neighb_restype( pose.residue_type( ii_neighb ) );
737  Size const neighb_atom1 = neighb_restype.residue_connection( neighb_resconn ).atomno();
738 
739  if ( ! score_everything && ! score_atom_centrally( neighb_restype, neighb_atom1 )) continue;
740  // Beyond this point, we will score all atom triples
741 
742  Size const mmat1 = restype.atom( atomno ).mm_atom_type_index();
743  Size const mmat2 = neighb_restype.atom( neighb_atom1 ).mm_atom_type_index();
744 
745 
746  utility::vector1< chemical::two_atom_set > const & neighb_atoms_wi1(
747  neighb_restype.atoms_within_one_bond_of_a_residue_connection( neighb_resconn ));
748 
749  for ( Size jj = 1; jj <= neighb_atoms_wi1.size(); ++jj ) {
750 
751  chemical::two_atom_set const & neighb_pair = neighb_atoms_wi1[ jj ];
752  assert( neighb_pair.key1() == neighb_atom1 );
753 
754  Size const neighb_atom2 = neighb_pair.key2();
755  Size const mmat3 = neighb_restype.atom( neighb_atom2 ).mm_atom_type_index();
756 
757  //TR << " 2b. Deriv for interres angle between (" << ii_neighb << "," << neighb_atom2 << ") ("<< ii_neighb << "," << neighb_atom1 << ") " << atomno << std::endl;
758 
759  Real Ktheta;
760  Real theta0;
761  if ( param_set_ ) {
762  param_set_->lookup(
763  pose.conformation(),
764  id::AtomID(atomno, id.rsd()),
765  id::AtomID(neighb_atom1, neighb_res.seqpos()),
766  id::AtomID(neighb_atom2, neighb_res.seqpos()),
767  Ktheta,
768  theta0
769  );
770  // skip this bond angle if Ktheta is 0
771  if ( !Ktheta ) continue;
772  }
773 
774  Vector f1(0.0), f2(0.0);
775  Real theta(0.0);
776 
777  numeric::deriv::angle_p1_deriv(
778  res.xyz( atomno ),
779  neighb_res.xyz( neighb_atom1 ),
780  neighb_res.xyz( neighb_atom2 ),
781  theta, f1, f2 );
782 
783  Real dE_dtheta;
784  if ( param_set_ ) {
785  dE_dtheta = weights[ mm_bend ] * potential_.dscore( Ktheta, theta0, theta );
786  } else {
787  dE_dtheta = weights[ mm_bend ] * potential_.mm::MMBondAngleScore::dscore(
788  mm::mm_bondangle_atom_tri( mmat1, mmat2, mmat3 ), theta );
789  }
790 
791  //TR << " theta " << numeric::conversions::degrees( theta ) << " dE_dtheta " << dE_dtheta << " f1: " << f1.x() << " " << f1.y() << " " << f1.z() << " f2: " << f2.x() << " " << f2.y() << " " << f2.z() << std::endl;
792 
793  LF1 += dE_dtheta * f1;
794  LF2 += dE_dtheta * f2;
795 
796  }
797  }
798  //TR << "Finished derivatives for rsd# " << id.rsd() << " atom# " << id.atomno() << " F1: " << LF1.x() << " " << LF1.y() << " " << LF1.z() << " F2: " << LF2.x() << " " << LF2.y() << " " << LF2.z() << std::endl;
799  F1 += LF1;
800  F2 += LF2;
801 }
802 
803 
804 /// @brief MMBondAngleEnergy does not have an atomic interation threshold
805 Distance
807 {
808  return 0.0;
809 }
810 
811 /// @brief MMBondAngleEnergy is context independent; indicates that no context graphs are required
812 void
814 {}
817 {
818  return 1; // Initial versioning
819 }
820 
821 } // namespace methods
822 } // namespace scoring
823 } // namespace core