Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
AngleConstraint.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
11 /// @brief Definition of AngularConstraints
12 
13 // Unit headers
15 
16 // Project headers
24 #include <core/pose/Pose.hh>
25 #include <core/pose/util.hh>
26 #include <basic/Tracer.hh>
27 #include <core/id/AtomID.hh>
28 #include <core/id/NamedAtomID.hh>
29 
30 // Numeric headers
31 // AUTO-REMOVED #include <numeric/xyz.functions.hh>
32 #include <numeric/trig.functions.hh>
33 #include <numeric/deriv/angle_deriv.hh>
34 
35 #include <utility/vector1.hh>
36 #include <utility/assert.hh>
37 
38 namespace core {
39 namespace scoring {
40 namespace constraints {
41 
42 static basic::Tracer TRACER("core.io.constraints");
43 
44 void AngleConstraint::show( std::ostream & out ) const {
45  out << "Angle";
46  for ( Size i = 1; i <= natoms(); ++i ) {
47  AtomID const & id = atom(i);
48  out << ' ' << id.rsd() << ' ' << id.atomno();
49  }
50  out << ' ';
51  func_->show_definition(out);
52 }
53 
54 void AngleConstraint::show_def( std::ostream& out, pose::Pose const& pose ) const {
55  out << type();
56  for ( Size i = 1; i <= natoms(); ++i ) {
57  AtomID const & id = atom(i);
58  out << ' ' << atom_id_to_named_atom_id( id, pose );
59  }
60  func_->show_definition( out );
61 }
62 
63 /////////////////////////////////////////////////////////////////////////////
64 ///@details one line definition "Angle atom1 res1 atom2 res2 atom3 res3 function_type function_definition"
65 ///SML: It appears to be reading the angle in radians, because score ultimately uses std:acos, which returns radians.
66 void
68  std::istream & data,
69  pose::Pose const & pose,
70  FuncFactory const & func_factory
71 )
72 {
73  Size res1, res2, res3;
74  std::string tempres1, tempres2, tempres3;
75  std::string name1, name2, name3;
76  std::string func_type;
78 
79  data
80  >> name1 >> tempres1
81  >> name2 >> tempres2
82  >> name3 >> tempres3
83  >> func_type;
84 
85  ConstraintIO::parse_residue( pose, tempres1, res1 );
86  ConstraintIO::parse_residue( pose, tempres2, res2 );
87  ConstraintIO::parse_residue( pose, tempres3, res3 );
88 
89  TRACER.Debug << "read: " << name1 << " " << name2 << " " << name3 << " "
90  << res1 << " " << res2 << " " << res3 << " func: " << func_type
91  << std::endl;
92  if ( res1 > pose.total_residue() || res2 > pose.total_residue() || res3 > pose.total_residue() ) {
93  TRACER.Warning << "ignored constraint (no such atom in pose!)"
94  << name1 << " " << name2 << " " << res1 << " " << res2 << std::endl;
95  data.setstate( std::ios_base::failbit );
96  return;
97  }
98 
99  atom1_ = id::AtomID( pose.residue(res1).atom_index(name1), res1 );
100  atom2_ = id::AtomID( pose.residue(res2).atom_index(name2), res2 );
101  atom3_ = id::AtomID( pose.residue(res3).atom_index(name3), res3 );
102  if ( atom1_.atomno() == 0 || atom2_.atomno() == 0 || atom3_.atomno() == 0 ) {
103  TRACER.Warning << "Error reading atoms: read in atom names("
104  << name1 << "," << name2 << "," << name3 << "), "
105  << "and found AtomIDs (" << atom1_ << "," << atom2_ << "," << atom3_ << ")"
106  << std::endl;
107  data.setstate( std::ios_base::failbit );
108  return;
109  }
110 
111  func_ = func_factory.new_func( func_type );
112  func_->read_data( data );
113 
114  //chu skip the rest of line since this is a single line defintion.
115  while( data.good() && (data.get() != '\n') ) {}
116 
117  if ( TRACER.Debug.visible() ) {
118  func_->show_definition( std::cout );
119  std::cout << std::endl;
120  }
121 
122 } // read_def
123 
124 /// @brief Copies the data from this Constraint into a new object and returns an OP
125 /// atoms are mapped to atoms with the same name in dest pose ( e.g. for switch from centroid to fullatom )
126 /// if a sequence_mapping is present it is used to map residue numbers .. NULL = identity mapping
127 /// to the new object. Intended to be implemented by derived classes.
130  id::NamedAtomID atom1( atom_id_to_named_atom_id( atom(1), src ) );
131  id::NamedAtomID atom2( atom_id_to_named_atom_id( atom(2), src ) );
132  id::NamedAtomID atom3( atom_id_to_named_atom_id( atom(3), src ) );
133 
134  if ( smap ) {
135  atom1.rsd() = (*smap)[ atom1_.rsd() ];
136  atom2.rsd() = (*smap)[ atom2_.rsd() ];
137  atom3.rsd() = (*smap)[ atom3_.rsd() ];
138  }
139 
140  //get AtomIDs for target pose
141  id::AtomID id1( named_atom_id_to_atom_id( atom1, dest ) );
142  id::AtomID id2( named_atom_id_to_atom_id( atom2, dest ) );
143  id::AtomID id3( named_atom_id_to_atom_id( atom3, dest ) );
144  if ( id1.valid() && id2.valid() && id3.valid() ) {
145  return new AngleConstraint( id1, id2, id3, func_, score_type() );
146  } else {
147  return NULL;
148  }
149 }
150 
151 
152 bool
153 AngleConstraint::operator == ( Constraint const & other_cst ) const
154 {
155  if( !dynamic_cast< AngleConstraint const * > ( &other_cst ) ) return false;
156 
157  AngleConstraint const & other( static_cast< AngleConstraint const & > (other_cst) );
158 
159  if( atom1_ != other.atom1_ ) return false;
160  if( atom2_ != other.atom2_ ) return false;
161  if( atom3_ != other.atom3_ ) return false;
162  if( func_ != other.func_ ) return false;
163  if( this->score_type() != other.score_type() ) return false;
164 
165  return true;
166 }
167 
168 /////////////////////////////////////////////////////////////////////////////
169 Real
171  Vector const & p1,
172  Vector const & p2,
173  Vector const & p3
174 ) const
175 {
176  Vector u1( p1 - p2 );
177  Vector u2( p3 - p2 );
178  Real const n1( u1.length() );
179  Real const n2( u2.length() );
180  if ( n1 > 1e-12 && n2 > 1e-12 ) {
181  Real const theta = numeric::arccos( dot( u1,u2 ) / ( n1 * n2 ) );
182  return func( theta );
183  }
184  std::cout << "AngleConstraint::score: warning: 0-length bonds!" << std::endl;
185  return 0.0;
186 }
187 
188 
189 /////////////////////////////////////////////////////////////////////////////
190 // accumulate F1, F2 contributions from terms that look like
191 //
192 // d(M-F)
193 // dot( -------- , w )
194 // d phi
195 //
196 // where phi is moving M and F is fixed.
197 //
198 // F1 collects terms f1 that look like: (-u_phi) dot f1
199 // F2 collects terms f2 that look like: (-u_phi x R_phi) dot f2
200 //
201 // where u_phi is the unit vector axis of phi and R_phi is a point
202 // on the axis
203 //
204 // basic id: d(M-F)/dphi = u_phi x ( M - R_phi )
205 //
206 // and dot( a, b x c ) = dot( b, c x a )
207 //
208 //
209 void
211  Vector const & M,
212  Vector const & w,
213  Vector & F1,
214  Vector & F2
215 )
216 {
217  F2 += w;
218  F1 += cross( w, M );
219 }
220 
221 /////////////////////////////////////////////////////////////////////////////
222 // calculates f1,f2 contributions for dtheta_dphi
223 //
224 // where phi is a torsion angle moving p1 while p2 and p3 are fixed
225 void
227  Vector const & p1,
228  Vector const & p2,
229  Vector const & p3,
230  Vector & F1,
231  Vector & F2
232 )
233 {
234  using numeric::conversions::radians;
235 
236  // to avoid problems with dtheta/dx around 0 and 180 degrees
237  // truncate x a bit in the calculation of the derivative
238  static Real const small_angle( radians( Real(0.1) ) );
239  static Real const big_angle( radians( Real(179.9) ) );
240  static Real const max_x( std::cos( small_angle ));
241  static Real const min_x( std::cos( big_angle ));
242  // dtheta_dx has a value of ~ 572.96 for min_x and max_x
243  // this goes to infinity as x goes to -1 or 1
244 
245  Vector v1( p1 - p2 );
246  Vector v2( p3 - p2 );
247  Real const n1( v1.length() );
248  Real const n2( v2.length() );
249  if ( n1 < 1e-9 || n2 < 1e-9 ) {
250  return;
251  }
252 
253  // calculate dx/dphi where x = cos theta = dot( v1,v2) / (n1*n2)
254 
255  Real x = dot(v1,v2)/(n1*n2);
256 
257  // only v1 depends on phi, not v2 (we are assuming only p1 is moving)
258  // so we get two terms, one from v1 on top and one from n1 = |v1| on
259  // the bottom
260 
261  Vector f1(0.0),f2(0.0);
262 
263  { // first term
264  Real const f = 1.0f / ( n1 * n2 );
265  helper( p1, f * v2, f1, f2 );
266  }
267 
268  { // second term
269  Real const f = -1.0f * x / ( n1 * n1 );
270  helper( p1, f * v1, f1, f2 );
271  }
272 
273  x = std::min( std::max( min_x, x ), max_x );
274  Real const dtheta_dx = -1.0f / sqrt( 1.0f - x*x );
275  f1 *= dtheta_dx;
276  f2 *= dtheta_dx;
277 
278  // translation of p1 along v1 or perpendicular to v1 and v2 ==> deriv=0
279  assert( f1.distance( cross(f2,p1) ) < 1e-3 && // see helper fcn
280  std::abs( dot( f2, v1 ) ) < 1e-3 &&
281  std::abs( dot( f2, cross( v1, v2 ) ) ) < 1e-3 );
282 
283 
284  { // more debugging
285  // pretend axis = u2, R_phi = p2
286  ASSERT_ONLY(Vector const u_phi( v2.normalized() );)
287  ASSERT_ONLY(Vector const R_phi( p2 );)
288  ASSERT_ONLY(Real const deriv = - dot( u_phi, f1 ) - dot( cross( u_phi, R_phi ), f2);)
289  assert( std::abs( deriv ) < 1e-3 );
290  //std::cout << "deriv: " << deriv<< ' ' <<
291  // F(9,3,u_phi(1)) << F(9,3,u_phi(2)) << F(9,3,u_phi(3)) << ' ' <<
292  // F(9,3,R_phi(1)) << F(9,3,R_phi(2)) << F(9,3,R_phi(3)) << "\nF1,F2: " <<
293  // F(9,3,f1(1)) << F(9,3,f1(2)) << F(9,3,f1(3)) << ' ' <<
294  // F(9,3,f2(1)) << F(9,3,f2(2)) << F(9,3,f2(3)) << std::endl;
295  }
296 
297 
298  F1 += f1;
299  F2 += f2;
300 }
301 
302 /////////////////////////////////////////////////////////////////////////////
303 void
305  Vector const & p1,
306  Vector const & p2,
307  Vector const & p3,
308  Vector & F1,
309  Vector & F2
310 ) const
311 {
312  Vector u1( p1 - p2 );
313  Vector u2( p3 - p2 );
314  Real const n1_n2( u1.length() * u2.length() );
315  if ( n1_n2 < 1e-12 ) {
316  std::cout << "AngleConstraint::p1_deriv: short bonds: " << n1_n2 <<
317  std::endl;
318  return;
319  }
320 
321  Vector f1(0.0),f2(0.0);
322  p1_theta_deriv( p1, p2, p3, f1, f2 );
323 
324  Real d( dot(u1,u2) / n1_n2 );
325  Real const tol(0.001);
326  if ( d <= -1.0 + tol ) {
327  //std::cout << "out-of-tol: " << d << ' ' << std::endl;
328  d = -1.0+tol;
329  } else if ( d >= 1.0 - tol ) {
330  //std::cout << "out-of-tol: " << d << std::endl;
331  d = 1.0-tol;
332  }
333  Real const theta = numeric::arccos( d );
334 
335 
336  Real const dE_dtheta = dfunc( theta );
337 
338  //std::cout << "dE_dtheta_p1_deriv: " << dE_dtheta << ' ' <<
339  // f1(1) << ' ' << f1(2) << ' ' << f1(3) << std::endl;
340 
341  F1 += dE_dtheta * f1;
342  F2 += dE_dtheta * f2;
343 
344 }
345 
346 /////////////////////////////////////////////////////////////////////////////
347 void
349  Vector const & p1,
350  Vector const & p2,
351  Vector const & p3,
352  Vector & F1,
353  Vector & F2
354 ) const {
355  Vector v1( p1 - p2 );
356  Vector v2( p3 - p2 );
357  Real const v12( v1.length() * v2.length() );
358  if ( v12 < 1e-12 ) return;
359 
360  // here we use the trick that theta = pi - alpha - beta
361  //
362  // where alpha and beta are the other angles in the p1,p2,p3 triangle
363  // so dtheta_dphi = -dalpha_dphi - dbeta_dphi
364  //
365  // for these we can use the p1_theta_deriv formula
366  //
367  Vector f1(0.0),f2(0.0);
368  p1_theta_deriv( p2, p1, p3, f1, f2 ); // alpha deriv
369  p1_theta_deriv( p2, p3, p1, f1, f2 ); // beta deriv
370 
371  // translation of p2 atom perpendicular to plane ==> deriv = 0
372  //std::cout << "p2 deriv check: " << std::endl;
373  assert( std::abs( dot( f2, cross( v1,v2) ) ) < 1e-3 );
374 
375  Real d( dot(v1,v2) / v12 );
376  Real const tol(0.001);
377  if ( d <= -1.0 + tol ) {
378  //std::cout << "out-of-tol: " << d << ' ' << std::endl;
379  d = -1.0+tol;
380  } else if ( d >= 1.0 - tol ) {
381  //std::cout << "out-of-tol: " << d << std::endl;
382  d = 1.0-tol;
383  }
384  Real const theta = numeric::arccos( d );
385  //Real const theta = arccos( dot( v1,v2 ) / v12 );
386  Real const dE_dtheta = dfunc( theta );
387 
388  //
389  //std::cout << "dE_dtheta_p2_deriv: " << dE_dtheta << ' ' <<
390  // f1(1) << ' ' << f1(2) << ' ' << f1(3) << std::endl;
391 
392  F1 += -1.0f * dE_dtheta * f1;
393  F2 += -1.0f * dE_dtheta * f2;
394 }
395 
396 
397 void
398 AngleConstraint::score( XYZ_Func const & xyz, EnergyMap const &, EnergyMap & emap ) const
399 {
400  emap[ this->score_type() ] += score( xyz( atom1_ ), xyz( atom2_ ), xyz( atom3_ ) );
401 }
402 
403 /////////////////////////////////////////////////////////////////////////////
404 void
406  AtomID const & atom,
407  XYZ_Func const & xyz,
408  Vector & F1,
409  Vector & F2,
410  EnergyMap const & weights
411 ) const {
412 
413  Vector unweighted_F1(0.);
414  Vector unweighted_F2(0.);
415  using numeric::deriv::angle_p1_deriv;
416  using numeric::deriv::angle_p2_deriv;
417  Real theta( 0.0 );
418  if ( atom == atom1_ ) {
419  angle_p1_deriv( xyz( atom1_ ), xyz( atom2_ ), xyz( atom3_ ), theta, unweighted_F1, unweighted_F2 );
420  } else if ( atom == atom2_ ) {
421  angle_p2_deriv( xyz( atom1_ ), xyz( atom2_ ), xyz( atom3_ ), theta, unweighted_F1, unweighted_F2 );
422  } else if ( atom == atom3_ ) {
423  angle_p1_deriv( xyz( atom3_ ), xyz( atom2_ ), xyz( atom1_ ), theta, unweighted_F1, unweighted_F2 );
424  } else {
425  return;
426  }
427 
428  Real dfunc_dtheta( dfunc( theta ));
429 
430  F1 += weights[ this->score_type() ] * dfunc_dtheta * unweighted_F1;
431  F2 += weights[ this->score_type() ] * dfunc_dtheta * unweighted_F2;
432 }
433 
436  core::id::SequenceMapping const & seqmap
437 ) const {
438  if ( seqmap[atom1_.rsd()] != 0 && seqmap[atom2_.rsd()] != 0 && seqmap[atom3_.rsd()] != 0 ) {
439  AtomID remap_a1( atom1_.atomno(), seqmap[atom1_.rsd()] ),
440  remap_a2( atom2_.atomno(), seqmap[atom2_.rsd()] ),
441  remap_a3( atom3_.atomno(), seqmap[atom3_.rsd()] );
442  return ConstraintOP( new AngleConstraint( remap_a1, remap_a2, remap_a3, this->func_ ) );
443  } else {
444  return NULL;
445  }
446 }
447 
448 id::AtomID const &
449 AngleConstraint::atom( Size const n ) const
450 {
451  switch( n ) {
452  case 1:
453  return atom1_;
454  case 2:
455  return atom2_;
456  case 3:
457  return atom3_;
458  default:
459  utility_exit_with_message( "AngleConstraint::atom() bad argument" );
460  }
461  return atom1_;
462 }
463 
464 /// @details show violations of angular constraint. Control verbosity level between 1 .. 100
465 /// >80 : write MET 4 CA
466 /// otherwise: compute angle and call func_->show_violations
468  std::ostream & out,
469  pose::Pose const & pose,
470  Size verbose_level,
471  Real threshold
472 ) const {
473  conformation::Conformation const & conformation( pose.conformation() );
474  if (verbose_level > 80) {
475  out << "AngleConstraint ("
476  << pose.residue_type(atom1_.rsd() ).atom_name( atom1_.atomno() ) << ":" << atom1_.atomno() << "," << atom1_.rsd() << "-"
477  << pose.residue_type(atom2_.rsd() ).atom_name( atom2_.atomno() ) << ":" << atom2_.atomno() << "," << atom2_.rsd() << "-"
478  << pose.residue_type(atom3_.rsd() ).atom_name( atom3_.atomno() ) << ":" << atom3_.atomno() << "," << atom3_.rsd() << ") ";
479  };
480 
481  // compute angle
482  Vector const & p1( conformation.xyz( atom1_ ) ), p2( conformation.xyz( atom2_ ) ), p3( conformation.xyz( atom3_ ) );
483  Vector u1( p1 - p2 );
484  Vector u2( p3 - p2 );
485  Real const n1( u1.length() );
486  Real const n2( u2.length() );
487  if ( n1 > 1e-12 && n2 > 1e-12 ) {
488  Real const theta = numeric::arccos( dot( u1,u2 ) / ( n1 * n2 ) );
489 
490  // angle is meaningful, call show_violation of func_
491  return func_->show_violations( out, theta, verbose_level, threshold );
492  };
493  std::cout << "AngleConstraint::show_violations: error: 0-length bonds!"
494  << std::endl;
495  return 0;
496 }
497 
498 } // constraints
499 } // scoring
500 } // core
501 
502