Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
DihedralConstraint.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 src/core/scoring/DihedralConstraint.cc
11 /// @brief
12 
16 
17 #include <core/pose/Pose.hh>
18 #include <core/pose/util.hh>
20 #include <basic/Tracer.hh>
21 
22 #include <numeric/xyz.functions.hh>
23 #include <numeric/trig.functions.hh>
24 #include <numeric/deriv/dihedral_deriv.hh>
25 
26 #include <utility/exit.hh>
27 
28 //Auto Headers
29 #include <core/id/NamedAtomID.hh>
33 #include <utility/vector1.hh>
34 
35 namespace core {
36 namespace scoring {
37 namespace constraints {
38 
39 static basic::Tracer TR("core.io.constraints");
40 
41 /////////////////////////////////////////////////////////////////////////////
42 // contributions for a term that looks like
43 //
44 // d(M-F)
45 // ( ------ x v ) dot w
46 // d phi
47 //
48 // F1 collects terms f1 that look like: (-u_phi) dot f1
49 // F2 collects terms f2 that look like: (-u_phi x R_phi) dot f2
50 //
51 //
52 // where u_phi is the torsion axis of rotation
53 // and R_phi is a terminal atom of this axis
54 //
55 // static class function
56 void
58  Vector const & M,
59  Vector const & v,
60  Vector const & w,
61  Vector & F1,
62  Vector & F2
63 )
64 {
65  Vector const f2 = cross(v,w);
66  F2 += f2;
67  F1 += cross(f2,M);
68 }
69 
70 /////////////////////////////////////////////////////////////////////////////
71 //
72 // static class function
73 void
75  Vector const & p1,
76  Vector const & p2,
77  Vector const & p3,
78  Vector const & p4,
79  Real & x,
80  Vector & F1,
81  Vector & F2
82 )
83 {
84  F1 = 0.0;
85  F2 = 0.0;
86 
87  Vector v1( p1-p2 );
88  Vector v2( p2-p3 );
89  Vector v3( p3-p4 );
90 
91  Vector v12( cross( v1, v2 ));
92  Vector v23( cross( v2, v3 ));
93 
94  Real const n12( v12.length() );
95  Real const n23( v23.length() );
96 
97  if ( n12 < 1e-9 || n23 < 1e-9 ) return;
98 
99  x = dot( v12, v23) / ( n12 * n23 );
100 
101  // first term:
102  {
103  Real const f( 1.0f/ ( n12 * n23 ) );
104  helper( p1, f * v2, v23 , F1, F2);
105  }
106 
107  // second term
108  {
109  Real const f( -1.0f * x / ( n12 * n12 ) );
110  helper( p1, f * v2, v12, F1, F2 );
111  }
112 
113 
114  // debugging
115  // translation of p1 in the place spanned by v1 and v2
116  // does not affect the torsion angle
117  // ==> rotation of p1 about an axis perpendicular to this plane
118  // also does not change the torsion angle, ie deriv should be 0
119  assert( std::abs( dot( F2, v1 ) ) < 1e-3 );
120  assert( std::abs( dot( F2, v2 ) ) < 1e-3 );
121  assert( std::abs( dot( F1, cross( v1, v2 ) ) ) < 1e-3 );
122 }
123 
124 /////////////////////////////////////////////////////////////////////////////
125 // static class function
126 //
127 void
129  Vector const & p1,
130  Vector const & p2,
131  Vector const & p3,
132  Vector const & p4,
133  Real & x,
134  Vector & F1,
135  Vector & F2
136 )
137 {
138  //std::cout << "p2_cosine_deriv!" << std::endl;
139 
140  F1 = 0.0;
141  F2 = 0.0;
142 
143  typedef Vector Vec;
144  Vector v1( p1-p2 );
145  Vector v2( p2-p3 );
146  Vector v3( p3-p4 );
147 
148  Vector v12( cross( v1, v2 ));
149  Vector v23( cross( v2, v3 ));
150 
151  Real const n12( v12.length() );
152  Real const n23( v23.length() );
153 
154  if ( n12 < 1e-9 || n23 < 1e-9 ) return;
155 
156  x = dot( v12, v23) / ( n12 * n23 );
157 
158  // here we are taking derivatives of an expression that looks like
159  //
160  // dot( v12, v23 )
161  // x = cos theta = -----------------
162  // n12 * n23
163  //
164  // where theta is our dihedral angle
165  //
166 
167  { // derivatives of the numerator
168  // v1 and v2 both depend on position of p2
169 
170  { // first term
171  Real const f( -1.0f/ ( n12 * n23 ) );
172  helper( p2, f * v2, v23 , F1, F2);
173  }
174 
175  { // second term
176  Real const f( -1.0f/ ( n12 * n23 ) );
177  helper( p2, f * v1, v23 , F1, F2);
178  }
179 
180  { // third term
181  Real const f( 1.0f/ ( n12 * n23 ) );
182  helper( p2, f * v3, v12 , F1, F2);
183  }
184  }
185 
186  { // derivatives of the denominator
187  // v1 and v2 both depend on position of p2
188 
189  { // first term
190  Real const f( x/ ( n12 * n12 ) );
191  helper( p2, f * v2, v12, F1, F2 );
192  }
193 
194  { // second term
195  Real const f( x/ ( n12 * n12 ) );
196  helper( p2, f * v1, v12, F1, F2 );
197  }
198 
199  { // third term
200  Real const f( -1.0f * x/ ( n23 * n23 ) );
201  helper( p2, f * v3, v23, F1, F2 );
202  }
203  }
204 
205  // debugging
206  // translation of p2 along v2 does not change the torsion angle
207  assert( std::abs( dot( F2, v2 ) ) < 1e-3 );
208 
209 }
210 
211 /////////////////////////////////////////////////////////////////////////////
212 Real
214  conformation::Conformation const & conformation
215 ) const
216 {
217  return score( conformation.xyz( atom1_ ),conformation.xyz( atom2_ ),
218  conformation.xyz( atom3_ ),conformation.xyz( atom4_ ) );
219 }
220 
221 
222 /////////////////////////////////////////////////////////////////////////////
223 void
225  AtomID const & atom,
226  XYZ_Func const & xyz,
227  Vector & F1,
228  Vector & F2,
229  EnergyMap const & weights
230 ) const
231 {
232 
233 
234  /*using numeric::conversions::radians;
235 
236  //static bool dihedral_deriv( true );
237  //if ( dihedral_deriv ) { std::cout << "DIHEDRAL DERIV" << std::endl; }
238  //dihedral_deriv = false;
239 
240  // to avoid problems with dtheta/dx around 0 and 180 degrees
241  // truncate x a bit in the calculation of the derivative
242  static Real const small_angle( radians( Real(0.1) ) );
243  static Real const big_angle( radians( Real(179.9) ) );
244  static Real const max_x( std::cos( small_angle ));
245  static Real const min_x( std::cos( big_angle ));
246  // dtheta_dx has a value of ~ 572.96 for min_x and max_x
247  // this goes to infinity as x goes to -1 or 1
248 
249  Vector f1(0.0) ,f2(0.0);
250 
251  Real x(0.0); // cos theta
252  if ( atom == atom1_ ) {
253  p1_cosine_deriv( conformation.xyz( atom1_ ),conformation.xyz( atom2_ ),
254  conformation.xyz( atom3_ ),conformation.xyz( atom4_ ), x, f1, f2 );
255  } else if ( atom == atom2_ ) {
256  p2_cosine_deriv( conformation.xyz( atom1_ ),conformation.xyz( atom2_ ),
257  conformation.xyz( atom3_ ),conformation.xyz( atom4_ ), x, f1, f2 );
258  } else if ( atom == atom3_ ) {
259  p2_cosine_deriv( conformation.xyz( atom4_ ),conformation.xyz( atom3_ ),
260  conformation.xyz( atom2_ ),conformation.xyz( atom1_ ), x, f1, f2 );
261  } else if ( atom == atom4_ ) {
262  p1_cosine_deriv( conformation.xyz( atom4_ ),conformation.xyz( atom3_ ),
263  conformation.xyz( atom2_ ),conformation.xyz( atom1_ ), x, f1, f2 );
264  } else {
265  return;
266  }
267 
268  Real const thetaU( numeric::arccos( x )); // unsigned version of theta
269 
270  Real const theta ( dihedral_radians( conformation.xyz( atom1_ ),conformation.xyz( atom2_ ),
271  conformation.xyz( atom3_ ),conformation.xyz( atom4_ ) ) );
272 
273  assert( std::abs( std::abs( theta ) - thetaU ) < 1e-2 );
274 
275  Real const dE_dtheta( dfunc( theta ) );
276 
277  x = std::min( std::max( min_x, x ), max_x );
278  Real const dthetaU_dx = -1 / sqrt( 1- x*x );
279  Real const dtheta_dthetaU( theta < 0 ? -1 : 1 );
280 
281  F1 += ( dE_dtheta * dtheta_dthetaU * dthetaU_dx * f1 ) * weights[ this->score_type() ];
282 
283  F2 += ( dE_dtheta * dtheta_dthetaU * dthetaU_dx * f2 ) * weights[ this->score_type() ];
284 
285 *//**/
286 
287  using namespace numeric::deriv;
288 
289  Vector f1(0.0) ,f2(0.0);
290 
291  Real theta(0.0);
292  if ( atom == atom1_ ) {
293  dihedral_p1_cosine_deriv( xyz( atom1_ ),xyz( atom2_ ), xyz( atom3_ ), xyz( atom4_ ), theta, f1, f2 );
294  } else if ( atom == atom2_ ) {
295  dihedral_p2_cosine_deriv( xyz( atom1_ ), xyz( atom2_ ), xyz( atom3_ ), xyz( atom4_ ), theta, f1, f2 );
296  } else if ( atom == atom3_ ) {
297  dihedral_p2_cosine_deriv( xyz( atom4_ ), xyz( atom3_ ), xyz( atom2_ ), xyz( atom1_ ), theta, f1, f2 );
298  } else if ( atom == atom4_ ) {
299  dihedral_p1_cosine_deriv( xyz( atom4_ ), xyz( atom3_ ), xyz( atom2_ ), xyz( atom1_ ), theta, f1, f2 );
300  } else {
301  return;
302  }
303 
304  Real const dE_dtheta( dfunc( theta ) );
305 
306  F1 += dE_dtheta * weights[ this->score_type() ] * f1;
307  F2 += dE_dtheta * weights[ this->score_type() ] * f2;
308 /**/
309 }
310 
313  core::id::SequenceMapping const & seqmap
314 ) const {
315  if ( seqmap[atom1_.rsd()] != 0 && seqmap[atom2_.rsd()] != 0 && seqmap[atom3_.rsd()] != 0 && seqmap[atom4_.rsd()] != 0 ) {
316  AtomID remap_a1( atom1_.atomno(), seqmap[atom1_.rsd()] ),
317  remap_a2( atom2_.atomno(), seqmap[atom2_.rsd()] ),
318  remap_a3( atom3_.atomno(), seqmap[atom3_.rsd()] ),
319  remap_a4( atom4_.atomno(), seqmap[atom4_.rsd()] );
320  return ConstraintOP( new DihedralConstraint( remap_a1, remap_a2, remap_a3, remap_a4, this->func_ ) );
321  } else {
322  return NULL;
323  }
324 }
325 
326 
327 /// @brief Copies the data from this Constraint into a new object and returns an OP
328 /// atoms are mapped to atoms with the same name in dest pose ( e.g. for switch from centroid to fullatom )
329 /// if a sequence_mapping is present it is used to map residue numbers .. NULL = identity mapping
330 /// to the new object. Intended to be implemented by derived classes.
336 // std::cout << "making a clone";
337  if ( smap ) {
338  atom1.rsd() = (*smap)[ atom1_.rsd() ];
339  atom2.rsd() = (*smap)[ atom2_.rsd() ];
340  atom3.rsd() = (*smap)[ atom3_.rsd() ];
341  atom4.rsd() = (*smap)[ atom4_.rsd() ];
342  }
343 
344  //get AtomIDs for target pose
349  if ( id1.valid() && id2.valid() && id3.valid() && id4.valid() ) {
350  return new DihedralConstraint( id1, id2, id3, id4, func_, score_type() );
351  } else {
352  return NULL;
353  }
354 }
355 
356 
357 id::AtomID const &
358 DihedralConstraint::atom( Size const n ) const {
359  switch( n ) {
360  case 1:
361  return atom1_;
362  case 2:
363  return atom2_;
364  case 3:
365  return atom3_;
366  case 4:
367  return atom4_;
368  default:
369  utility_exit_with_message( "DihedralConstraint::atom() bad argument" );
370  }
371  return atom1_;
372 }
373 
374 
375 
376 ////////////////////////////////////////////////////////////////////////////////////////////////////
377 ///@details one line definition "Dihedral atom1 res1 atom2 res2 atom3 res3 atom4 res4 function_type function_definition"
378 void
380  std::istream & in,
381  pose::Pose const & pose,
382  FuncFactory const & func_factory
383 ) {
384  Size res1, res2, res3, res4;
385  std::string tempres1, tempres2, tempres3, tempres4;
386  std::string name1, name2, name3, name4;
387  std::string func_type;
389 
390  in
391  >> name1 >> tempres1
392  >> name2 >> tempres2
393  >> name3 >> tempres3
394  >> name4 >> tempres4
395  >> func_type;
396 
397  ConstraintIO::parse_residue( pose, tempres1, res1 );
398  ConstraintIO::parse_residue( pose, tempres2, res2 );
399  ConstraintIO::parse_residue( pose, tempres3, res3 );
400  ConstraintIO::parse_residue( pose, tempres4, res4 );
401 
402  TR.Debug << "read: " << name1 << " " << name2 << " " << name3 << " " << name4 << " "
403  << res1 << " " << res2 << " " << res3 << " " << res4 << " func: " << func_type
404  << std::endl;
405  if ( res1 > pose.total_residue() || res2 > pose.total_residue() || res3 > pose.total_residue() || res4 > pose.total_residue() ) {
406  TR.Warning << "ignored constraint (no such atom in pose!)"
407  << name1 << " " << name2 << " " << name3 << " " << name4 << " "
408  << res1 << " " << res2 << " " << res3 << " " << res4 << " func: " << func_type
409  << std::endl;
410  in.setstate( std::ios_base::failbit );
411  return;
412  }
413 
418 
419  if ( atom1_.atomno() == 0 || atom2_.atomno() == 0 || atom3_.atomno() == 0 || atom4_.atomno() == 0 ) {
420  TR.Warning << "Error reading atoms: read in atom names("
421  << name1 << "," << name2 << "," << name3 << "," << name4 << "), "
422  << "and found AtomIDs (" << atom1_ << "," << atom2_ << "," << atom3_ << "," << atom4_ << ")"
423  << std::endl;
424  in.setstate( std::ios_base::failbit );
425  return;
426  }
427 
428  func_ = func_factory.new_func( func_type );
429  func_->read_data( in );
430 
431  //chu skip the rest of line since this is a single line defintion.
432  while( in.good() && (in.get() != '\n') ) {}
433 
434  if ( TR.Debug.visible() ) {
435  func_->show_definition( std::cout );
436  std::cout << std::endl;
437  }
438 }
439 
440 
441 
442 /////////////////////////////////////////////////////////////////////////////
443 Real
445  Vector const & p1,
446  Vector const & p2,
447  Vector const & p3,
448  Vector const & p4
449 ) const
450 {
451  return func( dihedral_radians( p1, p2, p3, p4 ) );
452 }
453 
454 
455 bool
457 {
458  if( !dynamic_cast< DihedralConstraint const * > ( &other_cst ) ) return false;
459 
460  DihedralConstraint const & other( static_cast< DihedralConstraint const & > (other_cst) );
461 
462  if( atom1_ != other.atom1_ ) return false;
463  if( atom2_ != other.atom2_ ) return false;
464  if( atom3_ != other.atom3_ ) return false;
465  if( atom4_ != other.atom4_ ) return false;
466  if( func_ != other.func_ ) return false;
467  if( this->score_type() != other.score_type() ) return false;
468 
469  return true;
470 }
471 
472 void
474  XYZ_Func const & xyz,
475  EnergyMap const &,
476  EnergyMap & emap
477 ) const {
478  emap[ this->score_type() ] += score(
479  xyz( atom1_ ), xyz( atom2_ ), xyz( atom3_ ), xyz( atom4_ )
480  );
481 }
482 
483 void DihedralConstraint::show( std::ostream & out ) const {
484  out << "DihedralConstraint";
485  for ( Size i = 1; i <= natoms(); ++i ) {
486  AtomID const & id = atom(i);
487  out << ' ' << id.rsd() << ' ' << id.atomno();
488  }
489  out << ' ';
490  func_->show_definition(out);
491 }
492 
493 void DihedralConstraint::show_def( std::ostream& out, pose::Pose const& pose ) const {
494  out << type();
495  for ( Size i = 1; i <= natoms(); ++i ) {
496  AtomID const & id = atom(i);
497  out << ' ' << atom_id_to_named_atom_id( id, pose );
498  }
499  func_->show_definition( out );
500 }
501 
502 
504  std::ostream& out,
505  pose::Pose const& pose,
506  Size verbose_level,
507  Real threshold
508 ) const {
509 
510  if ( verbose_level > 80 ) {
511  out << "Dihedral ("
512  << pose.residue_type(atom1_.rsd() ).atom_name( atom1_.atomno() ) << ":"
513  << atom1_.atomno() << "," << atom1_.rsd() << "-"
514  << pose.residue_type(atom2_.rsd() ).atom_name( atom2_.atomno() ) << ":"
515  << atom2_.atomno() << "," << atom2_.rsd() << ") ";
516  }
517  if ( verbose_level > 120 ) { //don't ask but I had a really weird bug to track down!
518  conformation::Conformation const & conformation( pose.conformation() );
519  Vector const & xyz1( conformation.xyz( atom1_ ) ), xyz2( conformation.xyz( atom2_ ) );
520  out << "\ncoords1: " << xyz1[ 1 ] << " " << xyz1[ 2 ] << " " << xyz1[ 3 ] << " --- ";
521  out << "coords1: " << xyz2[ 1 ] << " " << xyz2[ 2 ] << " " << xyz2[ 3 ] << "\n";
522  }
523 
524  return func_->show_violations( out, 0.0, verbose_level, threshold );
525 }
526 
527 
528 Real
529 DihedralConstraint::func( Real const theta ) const {
530  return func_->func( theta );
531 }
532 
533 Real
534 DihedralConstraint::dfunc( Real const theta ) const {
535  return func_->dfunc( theta );
536 }
537 
538 } // constraints
539 } // scoring
540 } // core