Rosetta
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
angle_deriv.hh
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 numeric/deriv/distance_deriv.hh
11 /// @brief inline function for computing f1/f2 derivatives for a function of an angle
12 /// @author Phil Bradley did all the hard work deriving the math represented here.
13 /// @author Andrew Leaver-Fay copy-and-pasted Phil's code into this file from
14 /// the AngleConstraint.cc file for general use.
15 
16 #ifndef INCLUDED_numeric_deriv_angle_deriv_hh
17 #define INCLUDED_numeric_deriv_angle_deriv_hh
18 
19 #include <numeric/xyzVector.hh>
20 #include <numeric/conversions.hh>
21 #include <utility/assert.hh>
22 
23 namespace numeric {
24 namespace deriv {
25 
26 /////////////////////////////////////////////////////////////////////////////
27 // accumulate F1, F2 contributions from terms that look like
28 //
29 // d(M-F)
30 // dot( -------- , w )
31 // d phi
32 //
33 // where phi is moving M and F is fixed.
34 //
35 // F1 collects terms f1 that look like: (-u_phi) dot f1
36 // F2 collects terms f2 that look like: (-u_phi x R_phi) dot f2
37 //
38 // where u_phi is the unit vector axis of phi and R_phi is a point
39 // on the axis
40 //
41 // basic id: d(M-F)/dphi = u_phi x ( M - R_phi )
42 //
43 // and dot( a, b x c ) = dot( b, c x a )
44 //
45 //
46 template < class P >
47 inline
48 void
50  xyzVector< P > const & M,
51  xyzVector< P > const & w,
52  xyzVector< P > & F1,
53  xyzVector< P > & F2
54 )
55 {
56  F2 += w;
57  F1 += cross( w, M );
58 }
59 
60 /////////////////////////////////////////////////////////////////////////////
61 // calculates f1,f2 contributions for dtheta_dphi
62 //
63 // where phi is a torsion angle moving p1 while p2 and p3 are fixed
64 template < class P >
65 inline
66 void
68  xyzVector< P > const & p1,
69  xyzVector< P > const & p2,
70  xyzVector< P > const & p3,
71  xyzVector< P > & F1,
72  xyzVector< P > & F2
73 )
74 {
75  typedef P Real;
76  typedef xyzVector< P > Vector;
77 
79 
80  // to avoid problems with dtheta/dx around 0 and 180 degrees
81  // truncate x a bit in the calculation of the derivative
82  static Real const small_angle( radians( Real(0.1) ) );
83  static Real const big_angle( radians( Real(179.9) ) );
84  static Real const max_x( std::cos( small_angle ));
85  static Real const min_x( std::cos( big_angle ));
86  // dtheta_dx has a value of ~ 572.96 for min_x and max_x
87  // this goes to infinity as x goes to -1 or 1
88 
89  Vector v1( p1 - p2 );
90  Vector v2( p3 - p2 );
91  Real const n1( v1.length() );
92  Real const n2( v2.length() );
93  if ( n1 < Real(1e-9) || n2 < Real(1e-9) ) {
94  return;
95  }
96 
97  // calculate dx/dphi where x = cos theta = dot( v1,v2) / (n1*n2)
98 
99  Real x = dot(v1,v2)/(n1*n2);
100 
101  // only v1 depends on phi, not v2 (we are assuming only p1 is moving)
102  // so we get two terms, one from v1 on top and one from n1 = |v1| on
103  // the bottom
104 
105  Vector f1(0.0),f2(0.0);
106 
107  { // first term
108  Real const f = Real(1.0) / ( n1 * n2 );
109  helper( p1, f * v2, f1, f2 );
110  }
111 
112  { // second term
113  Real const f = Real(-1.0) * x / ( n1 * n1 );
114  helper( p1, f * v1, f1, f2 );
115  }
116 
117  x = std::min( std::max( min_x, x ), max_x );
118  Real const dtheta_dx = Real(-1.0) / sqrt( Real(1.0) - x*x );
119  f1 *= dtheta_dx;
120  f2 *= dtheta_dx;
121 
122  // translation of p1 along v1 or perpendicular to v1 and v2 ==> deriv=0
123  assert( f1.distance( cross(f2,p1) ) < Real(1e-3) && // see helper fcn
124  std::abs( dot( f2, v1 ) ) < Real(1e-3) &&
125  std::abs( dot( f2, cross( v1, v2 ) ) ) < Real(1e-3) );
126 
127 
128  { // more debugging
129  // pretend axis = u2, R_phi = p2
130  ASSERT_ONLY(Vector const u_phi( v2.normalized() );)
131  ASSERT_ONLY(Vector const R_phi( p2 );)
132  ASSERT_ONLY(Real const deriv = - dot( u_phi, f1 ) - dot( cross( u_phi, R_phi ), f2);)
133  assert( std::abs( deriv ) < Real(1e-3) );
134  //std::cout << "deriv: " << deriv<< ' ' <<
135  // F(9,3,u_phi(1)) << F(9,3,u_phi(2)) << F(9,3,u_phi(3)) << ' ' <<
136  // F(9,3,R_phi(1)) << F(9,3,R_phi(2)) << F(9,3,R_phi(3)) << "\nF1,F2: " <<
137  // F(9,3,f1(1)) << F(9,3,f1(2)) << F(9,3,f1(3)) << ' ' <<
138  // F(9,3,f2(1)) << F(9,3,f2(2)) << F(9,3,f2(3)) << std::endl;
139  }
140 
141 
142  F1 += f1;
143  F2 += f2;
144 }
145 
146 /////////////////////////////////////////////////////////////////////////////
147 // calculates x and dtheta_dx where
148 // v1 = p1-p2,
149 // v2 = p3-p2
150 // n1 = norm( v1 )
151 // n2 = norm( v2 )
152 // x = dot(v1,v2) / (n1*n2), and
153 // dtheta_dx = Real(-1.0) / sqrt( Real(1.0) - x*x );
154 template < class P >
155 inline
156 void
158  xyzVector< P > const & v1,
159  xyzVector< P > const & v2,
160  P const n1,
161  P const n2,
162  P & x,
163  P & dtheta_dx
164 )
165 {
166  typedef P Real;
167 
169  static Real const small_angle( radians( Real(0.1) ) );
170  static Real const big_angle( radians( Real(179.9) ) );
171  static Real const max_x( std::cos( small_angle ));
172  static Real const min_x( std::cos( big_angle ));
173 
174  x = dot(v1,v2)/(n1*n2);
175  x = std::min( std::max( min_x, x ), max_x );
176  dtheta_dx = Real(-1.0) / sqrt( Real(1.0) - x*x );
177 
178 }
179 
180 /////////////////////////////////////////////////////////////////////////////
181 // calculates f1,f2 contributions for dtheta_dphi where
182 // v1 = p1-p2,
183 // v2 = p3-p2
184 // n1 = norm( v1 )
185 // n2 = norm( v2 )
186 // x = dot(v1,v2) / (n1*n2), and
187 // dtheta_dx = Real(-1.0) / sqrt( Real(1.0) - x*x );
188 //
189 // where phi is a torsion angle moving p1 while p2 and p3 are fixed
190 template < class P >
191 inline
192 void
194  xyzVector< P > const & p1,
195  xyzVector< P > const & v1,
196  xyzVector< P > const & v2,
197  P const n1,
198  P const n2,
199  P const x,
200  P const dtheta_dx,
201  xyzVector< P > & F1,
202  xyzVector< P > & F2
203 )
204 {
205  typedef P Real;
206  typedef xyzVector< P > Vector;
207 
209 
210  // to avoid problems with dtheta/dx around 0 and 180 degrees
211  // truncate x a bit in the calculation of the derivative
212  //static Real const small_angle( radians( Real(0.1) ) );
213  //static Real const big_angle( radians( Real(179.9) ) );
214  // dtheta_dx has a value of ~ 572.96 for min_x and max_x
215  // this goes to infinity as x goes to -1 or 1
216 
217  //Vector v1( p1 - p2 );
218  //Vector v2( p3 - p2 );
219  //Real const n1( v1.length() );
220  //Real const n2( v2.length() );
221  if ( n1 < Real(1e-9) || n2 < Real(1e-9) ) {
222  return;
223  }
224 
225  // calculate dx/dphi where x = cos theta = dot( v1,v2) / (n1*n2)
226 
227  //Real x = dot(v1,v2)/(n1*n2);
228 
229  // only v1 depends on phi, not v2 (we are assuming only p1 is moving)
230  // so we get two terms, one from v1 on top and one from n1 = |v1| on
231  // the bottom
232 
233  Vector f1(0.0),f2(0.0);
234 
235  { // first term
236  Real const f = Real(1.0) / ( n1 * n2 );
237  helper( p1, f * v2, f1, f2 );
238  }
239 
240  { // second term
241  Real const f = Real(-1.0) * x / ( n1 * n1 );
242  helper( p1, f * v1, f1, f2 );
243  }
244 
245  f1 *= dtheta_dx;
246  f2 *= dtheta_dx;
247 
248  // translation of p1 along v1 or perpendicular to v1 and v2 ==> deriv=0
249  //assert( f1.distance( cross(f2,p1) ) < Real(1e-3) && // see helper fcn
250  // std::abs( dot( f2, v1 ) ) < Real(1e-3) &&
251  // std::abs( dot( f2, cross( v1, v2 ) ) ) < Real(1e-3) );
252 
253 
254  //{ // more debugging
255  // // pretend axis = u2, R_phi = p2
256  // Vector const u_phi( v2.normalized() ), R_phi( p2 );
257  // Real const deriv = - dot( u_phi, f1 ) - dot( cross( u_phi, R_phi ), f2);
258  // assert( std::abs( deriv ) < Real(1e-3) );
259  // //std::cout << "deriv: " << deriv<< ' ' <<
260  // // F(9,3,u_phi(1)) << F(9,3,u_phi(2)) << F(9,3,u_phi(3)) << ' ' <<
261  // // F(9,3,R_phi(1)) << F(9,3,R_phi(2)) << F(9,3,R_phi(3)) << "\nF1,F2: " <<
262  // // F(9,3,f1(1)) << F(9,3,f1(2)) << F(9,3,f1(3)) << ' ' <<
263  // // F(9,3,f2(1)) << F(9,3,f2(2)) << F(9,3,f2(3)) << std::endl;
264  //}
265 
266 
267  F1 += f1;
268  F2 += f2;
269 }
270 
271 
272 /////////////////////////////////////////////////////////////////////////////
273 /// @brief compute f1/f2 atom derivative vectors for the first point defining
274 /// an angle. Templated on the precision of the coordinates being represented.
275 /// Returns the angle, theta, defined by p1->p2->p3, which should be used
276 /// to evaluate dE_dtheta. dE_dtheta should then be multiplied into both
277 /// derivative vectors that are returned. The values of the output variables
278 /// f1 and f2 are overwritten. Theta is computed in radians.
279 template < class P >
280 inline
281 void
283  xyzVector< P > const & p1,
284  xyzVector< P > const & p2,
285  xyzVector< P > const & p3,
286  P & theta,
287  xyzVector< P > & f1,
288  xyzVector< P > & f2
289 )
290 {
291  //std::cout << "core.mm.MMBondAngleEnergy: p1 angle deriv:" <<
292  //" p1 (" << p1.x() << "," << p1.y() << "," << p1.z() <<
293  //") p2 (" << p2.x() << "," << p2.y() << "," << p2.z() <<
294  //") p3 (" << p3.x() << "," << p3.y() << "," << p3.z() << ")" <<
295  //std::endl;
296 
297 
298  typedef P Real;
299  typedef xyzVector< P > Vector;
300 
301  f1 = Real(0.0);
302  f2 = Real(0.0);
303  theta = 0.0;
304 
305  Vector u1( p1 - p2 );
306  Vector u2( p3 - p2 );
307  Real const n1_n2( u1.length() * u2.length() );
308  if ( n1_n2 < Real(1e-12) ) {
309  std::cout << "AngleConstraint::p1_deriv: short bonds: " << n1_n2 <<
310  std::endl;
311  return;
312  }
313 
314  p1_theta_deriv( p1, p2, p3, f1, f2 );
315 
316  Real d( dot(u1,u2) / n1_n2 );
317  Real const tol(1.0e-8);
318  if ( d <= Real(-1.0) + tol ) {
319  //std::cout << "out-of-tol: " << d << ' ' << std::endl;
320  d = Real(-1.0) + tol;
321  } else if ( d >= Real(1.0) - tol ) {
322  //std::cout << "out-of-tol: " << d << std::endl;
323  d = Real(1.0) - tol;
324  }
325  theta = numeric::arccos( d );
326 
327 }
328 
329 
330 /// @brief compute f1/f2 atom derivative vectors for the middle point defining
331 /// an angle. Templated on the precision of the coordinates being represented.
332 /// Returns the angle, theta, defined by p1->p2->p3, which should be used
333 /// to evaluate the dfunc. dE_dtheta should then be multiplied into both
334 /// derivative vectors that are returned. The values of the output variables
335 /// f1 and f2 are overwritten. Theta is computed in radians.
336 template < class P >
337 inline
338 void
340  xyzVector< P > const & p1,
341  xyzVector< P > const & p2,
342  xyzVector< P > const & p3,
343  P & theta,
344  xyzVector< P > & f1,
345  xyzVector< P > & f2
346 )
347 {
348  //std::cout << "core.mm.MMBondAngleEnergy: p2 angle deriv:" <<
349  //" p1 (" << p1.x() << "," << p1.y() << "," << p1.z() <<
350  //") p2 (" << p2.x() << "," << p2.y() << "," << p2.z() <<
351  //") p3 (" << p3.x() << "," << p3.y() << "," << p3.z() << ")" <<
352  //std::endl;
353 
354  typedef P Real;
355  typedef xyzVector< P > Vector;
356 
357  f1 = Real(0.0);
358  f2 = Real(0.0);
359  theta = 0.0;
360 
361  Vector v1( p1 - p2 );
362  Vector v2( p3 - p2 );
363  Real const v12( v1.length() * v2.length() );
364  if ( v12 < Real(1e-12) ) return;
365 
366  // here we use the trick that theta = pi - alpha - beta
367  //
368  // where alpha and beta are the other angles in the p1,p2,p3 triangle
369  // so dtheta_dphi = -dalpha_dphi - dbeta_dphi
370  //
371  // for these we can use the p1_theta_deriv formula
372  //
373  f1 = Real(0.0);
374  f2 = Real(0.0);
375  p1_theta_deriv( p2, p1, p3, f1, f2 ); // alpha deriv
376  p1_theta_deriv( p2, p3, p1, f1, f2 ); // beta deriv
377 
378  // translation of p2 atom perpendicular to plane ==> deriv = 0
379  //std::cout << "p2 deriv check: " << std::endl;
380  assert( std::abs( dot( f2, cross( v1,v2) ) ) < Real(1e-3) );
381 
382  Real d( dot(v1,v2) / v12 );
383  Real const tol(0.001);
384  if ( d <= Real(-1.0) + tol ) {
385  //std::cout << "out-of-tol: " << d << ' ' << std::endl;
386  d = Real(-1.0) +tol;
387  } else if ( d >= Real(1.0) - tol ) {
388  //std::cout << "out-of-tol: " << d << std::endl;
389  d = Real(1.0) -tol;
390  }
391  theta = numeric::arccos( d );
392 
393  f1 *= Real(-1.0);
394  f2 *= Real(-1.0);
395 
396 }
397 
398 /// @details useful for computing all three f1/f2 derivative vectors simultaneously.
399 /// Basically a small refactoring / copy and pasting of the above code.
400 template < class P >
401 inline
402 void
404  xyzVector< P > const & p1,
405  xyzVector< P > const & p2,
406  xyzVector< P > const & p3,
407  P & theta,
408  xyzVector< P > & f1_p1,
409  xyzVector< P > & f2_p1,
410  xyzVector< P > & f1_p2,
411  xyzVector< P > & f2_p2,
412  xyzVector< P > & f1_p3,
413  xyzVector< P > & f2_p3
414 )
415 {
416  typedef P Real;
417  typedef xyzVector< P > Vector;
418 
419  f1_p1 = f2_p1 = f1_p2 = f2_p2 = f1_p3 = f2_p3 = Real(0.0);
420  theta = 0.0;
421 
422  Vector v12( p1 - p2 );
423  Vector v32( p3 - p2 );
424 
425  Real const n12( v12.length() );
426  Real const n23( v32.length() );
427 
428  Real const n12n23( n12 * n23 );
429  if ( n12n23 < Real(1e-12) ) return;
430 
431  Real x13, dtheta_dx13;
432  x_and_dtheta_dx( v12, v32, n12, n23, x13, dtheta_dx13 );
433  p1_theta_deriv( p1, v12, v32, n12, n23, x13, dtheta_dx13, f1_p1, f2_p1 );
434  p1_theta_deriv( p3, v32, v12, n23, n12, x13, dtheta_dx13, f1_p3, f2_p3 );
435 
436  /// Point 2 Derivatives. Comments stolen from above:
437  // here we use the trick that theta = pi - alpha - beta
438  //
439  // where alpha and beta are the other angles in the p1,p2,p3 triangle
440  // so dtheta_dphi = -dalpha_dphi - dbeta_dphi
441  //
442  // for these we can use the p1_theta_deriv formula
443 
444 
445  // alpha deriv for point 2
446  Vector v21 = -1 * v12;
447  Vector v31 = p3 - p1;
448  Real const n13 = v31.length();
449  Real alpha_x, alpha_dtheta_dx;
450  x_and_dtheta_dx( v21, v31, n12, n13, alpha_x, alpha_dtheta_dx );
451  p1_theta_deriv( p2, v21, v31, n12, n13, alpha_x, alpha_dtheta_dx, f1_p2, f2_p2 );
452 
453  // beta deriv for point 2
454  Vector v23 = -1 * v32;
455  Vector v13 = -1 * v31;
456  Real beta_x, beta_dtheta_dx;
457  x_and_dtheta_dx( v23, v13, n23, n13, beta_x, beta_dtheta_dx );
458  p1_theta_deriv( p2, v23, v13, n23, n13, beta_x, beta_dtheta_dx, f1_p2, f2_p2 );
459 
460  f1_p2 *= Real( -1.0 );
461  f2_p2 *= Real( -1.0 );
462 
463  Real d( dot(v12,v32) / n12n23 );
464  Real const tol(0.001);
465  if ( d <= Real(-1.0) + tol ) {
466  //std::cout << "out-of-tol: " << d << ' ' << std::endl;
467  d = Real(-1.0) +tol;
468  } else if ( d >= Real(1.0) - tol ) {
469  //std::cout << "out-of-tol: " << d << std::endl;
470  d = Real(1.0) -tol;
471  }
472  theta = numeric::arccos( d );
473 
474  /*{ // debug point 1
475  Vector test_p1_f1, test_p1_f2; Real test_theta;
476  angle_p1_deriv( p1, p2, p3, test_theta, test_p1_f1, test_p1_f2 );
477  if ( f1_p1.distance_squared( test_p1_f1 ) > 1e-4 ) {
478  std::cout << "Point 1 f1 vector in error: " << f1_p1.x() << " " << f1_p1.y() << " " << f1_p1.z() <<
479  " vs " << test_p1_f1.x() << " " << test_p1_f1.y() << " " << test_p1_f1.z() << std::endl;
480  }
481 
482  if ( f2_p1.distance_squared( test_p1_f2 ) > 1e-4 ) {
483  std::cout << "Point 1 f2 vector in error: " << f2_p1.x() << " " << f2_p1.y() << " " << f2_p1.z() <<
484  " vs " << test_p1_f2.x() << " " << test_p1_f2.y() << " " << test_p1_f2.z() << std::endl;
485  }
486  }
487 
488  { // debug point 2
489  Vector test_p2_f1, test_p2_f2; Real test_theta;
490  angle_p2_deriv( p1, p2, p3, test_theta, test_p2_f1, test_p2_f2 );
491  if ( f1_p2.distance_squared( test_p2_f1 ) > 1e-4 ) {
492  std::cout << "Point 1 f1 vector in error: " << f1_p2.x() << " " << f1_p2.y() << " " << f1_p2.z() <<
493  " vs " << test_p2_f1.x() << " " << test_p2_f1.y() << " " << test_p2_f1.z() << std::endl;
494  }
495 
496  if ( f2_p2.distance_squared( test_p2_f2 ) > 1e-4 ) {
497  std::cout << "Point 1 f2 vector in error: " << f2_p2.x() << " " << f2_p2.y() << " " << f2_p2.z() <<
498  " vs " << test_p2_f2.x() << " " << test_p2_f2.y() << " " << test_p2_f2.z() << std::endl;
499  }
500  }
501 
502  { // debug point 3
503  Vector test_p3_f1, test_p3_f2; Real test_theta;
504  angle_p1_deriv( p3, p2, p1, test_theta, test_p3_f1, test_p3_f2 );
505  if ( f1_p3.distance_squared( test_p3_f1 ) > 1e-4 ) {
506  std::cout << "Point 1 f1 vector in error: " << f1_p3.x() << " " << f1_p3.y() << " " << f1_p3.z() <<
507  " vs " << test_p3_f1.x() << " " << test_p3_f1.y() << " " << test_p3_f1.z() << std::endl;
508  }
509 
510  if ( f2_p3.distance_squared( test_p3_f2 ) > 1e-4 ) {
511  std::cout << "Point 1 f2 vector in error: " << f2_p3.x() << " " << f2_p3.y() << " " << f2_p3.z() <<
512  " vs " << test_p3_f2.x() << " " << test_p3_f2.y() << " " << test_p3_f2.z() << std::endl;
513  }
514  }*/
515 
516 }
517 
518 }
519 }
520 
521 #endif
522 
523 
static T min(T x, T y)
Definition: Svm.cc:16
void normalized(xyzVector &a) const
Normalized.
Definition: xyzVector.hh:735
cmplx w(cmplx z, double relerr)
Definition: functions.cc:470
def x
#define ASSERT_ONLY(x)
Macro wrapper for paramters that used only indebug_assert(...) statments. Intended to supress 'unused...
Definition: assert.hh:28
Conversions between degrees and radians.
Value length() const
Length.
Definition: xyzVector.hh:1638
void p1_theta_deriv(xyzVector< P > const &p1, xyzVector< P > const &p2, xyzVector< P > const &p3, xyzVector< P > &F1, xyzVector< P > &F2)
Definition: angle_deriv.hh:67
xyzVector: Fast (x,y,z)-coordinate numeric vector
xyzVector< Real > Vector
T abs(T const &x)
std::abs( x ) == | x |
Definition: Fmath.hh:295
void x_and_dtheta_dx(xyzVector< P > const &v1, xyzVector< P > const &v2, P const n1, P const n2, P &x, P &dtheta_dx)
Definition: angle_deriv.hh:157
void angle_p1_p2_p3_deriv(xyzVector< P > const &p1, xyzVector< P > const &p2, xyzVector< P > const &p3, P &theta, xyzVector< P > &f1_p1, xyzVector< P > &f2_p1, xyzVector< P > &f1_p2, xyzVector< P > &f2_p2, xyzVector< P > &f1_p3, xyzVector< P > &f2_p3)
Definition: angle_deriv.hh:403
void helper(xyzVector< P > const &M, xyzVector< P > const &w, xyzVector< P > &F1, xyzVector< P > &F2)
Definition: angle_deriv.hh:49
double Real
Definition: types.hh:39
xyzTriple< T > cross(xyzTriple< T > const &a, xyzTriple< T > const &b)
Cross product.
ocstream cout(std::cout)
Wrapper around std::cout.
Definition: ocstream.hh:287
float tol
Definition: loops_kic.py:75
T radians(T const &degrees)
Radians of degrees.
Definition: conversions.hh:32
void angle_p2_deriv(xyzVector< P > const &p1, xyzVector< P > const &p2, xyzVector< P > const &p3, P &theta, xyzVector< P > &f1, xyzVector< P > &f2)
compute f1/f2 atom derivative vectors for the middle point defining an angle. Templated on the precis...
Definition: angle_deriv.hh:339
Fast (x,y,z)-coordinate numeric vector.
T arccos(T const x)
like std::acos but with range checking
static T max(T x, T y)
Definition: Svm.cc:19
T dot(Quaternion< T > const &q1, Quaternion< T > const &q2)
Dot product.
void angle_p1_deriv(xyzVector< P > const &p1, xyzVector< P > const &p2, xyzVector< P > const &p3, P &theta, xyzVector< P > &f1, xyzVector< P > &f2)
compute f1/f2 atom derivative vectors for the first point defining an angle. Templated on the precisi...
Definition: angle_deriv.hh:282