Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
base_geometry.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
12 /// @author
13 
17 
19 
20 #include <core/types.hh>
21 #include <basic/Tracer.hh>
22 #include <basic/basic.hh>
24 #include <core/chemical/AA.hh>
26 #include <core/kinematics/Stub.hh>
27 #include <core/pose/Pose.hh>
28 
29 // AUTO-REMOVED #include <utility/vector1.hh>
30 #include <numeric/conversions.hh>
31 #include <numeric/xyzVector.hh>
32 #include <numeric/xyzMatrix.hh>
33 #include <numeric/xyz.functions.hh>
34 
35 #include <ObjexxFCL/format.hh>
36 #include <ObjexxFCL/string.functions.hh>
37 
38 #include <utility/vector1.hh>
39 
40 
41 
42 namespace core {
43 namespace scoring {
44 namespace dna {
45 
46 using namespace ObjexxFCL;
47 using namespace ObjexxFCL::fmt;
48 
50  //using kinematics::Stub::Matrix;
52 
53 ////////////////////////////////////////////////////////////////////////////
54 /// FWD
55 
56 Vector
58  utility::vector1< Vector > const & atoms_in
59 );
60 
61 ////////////////////////////////////////////////////////////////////////////
62 void
64  conformation::Residue const & rsd,
65  std::pair< std::string, int > & pucker
66 )
67 {
68 
70  names.push_back( "C1*" );
71  names.push_back( "C2*" );
72  names.push_back( "C3*" );
73  names.push_back( "C4*" );
74  names.push_back( "O4*" );
75 
77  for ( int i=1; i<= 5; ++i ) {
78  atoms.push_back( rsd.xyz( names[i] ) );
79  }
80 
81  Real mindot = 1000.0;
82  bool exxo( false );
83  for ( int ii=1; ii<= 5; ++ii ) {
84 
85  Vector n12 = (( atoms[2]-atoms[1] ).cross( atoms[3]-atoms[2] ) ).normalized();
86  Real dot = std::abs( n12.dot( ( atoms[4]-atoms[3] ).normalized() ) );
87  if ( dot < mindot ) {
88  // get pucker
89  //Real pucker_dot = n12.dot( ( atoms[5] - Real(0.5) * ( atoms[4] + atoms[1] ) ).normalized() );
90 
91  mindot = dot;
92  pucker.first = names[5];
93  exxo = ( n12.dot( ( atoms[5] - Real(0.5) * ( atoms[4] + atoms[1] ) ).normalized() ) > 0.0 );
94  }
95 
96  atoms.push_back( atoms[1] );
97  atoms.erase( atoms.begin() );
98 
99  names.push_back( names[1] );
100  names.erase( names.begin() );
101 
102  }
103 
104 
105  // additional integer for scannability
106  {
107  int const atom_index( std::find( names.begin(), names.end(), pucker.first ) - names.begin() );
108  int const sign_index( exxo ? 0 : 1 );
109  if ( atom_index%2 == sign_index ) pucker.second = atom_index+1;
110  else pucker.second = atom_index-4;
111  }
112 
113  if ( exxo ) pucker.first += " exxo";
114  else pucker.first += " endo";
115 }
116 
117 
118 ///////////////////////////////////////////////////////////////////////////////
121 {
122  phi = basic::periodic_range( phi, 360.0 );
123  if ( -120 <= phi && phi < 0 ) return "g-";
124  else if ( 0 <= phi && phi < 120 ) return "g+";
125  else return "t ";
126 }
127 
128 ///////////////////////////////////////////////////////////////////////////////
131 {
132  std::string ag_bin, b12_bin;
133  Real const alpha ( rsd.mainchain_torsion( 1 ) );
134  Real const gamma ( rsd.mainchain_torsion( 3 ) );
135  Real const epsilon( rsd.mainchain_torsion( 5 ) );
136  Real const zeta ( rsd.mainchain_torsion( 6 ) );
137 
138  if ( rsd.is_lower_terminus() ) ag_bin = "-- --";
139  else ag_bin = dihedral_bin( alpha ) + " " + dihedral_bin( gamma );
140 
141  if ( rsd.is_upper_terminus() ) b12_bin = "-- 0";
142  else {
143  Real const dev( basic::subtract_degree_angles( epsilon, zeta ) );
144  if ( dev < 0 ) {
145  b12_bin = "B1";
146  } else {
147  b12_bin = "B2";
148  }
149  b12_bin += ObjexxFCL::right_string_of( static_cast<int>( dev/10.0 ), 4 );
150  }
151  return ag_bin + " " + b12_bin;
152 }
153 
154 
155 ///////////////////////////////////////////////////////////////////////////////
156 // y-axis goes from a1 to a2
157 //
158 void
160  chemical::ResidueType const & rsd_type,
161  int const strand, // 1 or 2
162  std::string & a1,
163  std::string & a2
164 )
165 {
166  using namespace chemical;
167  if ( rsd_type.aa() == na_ade || rsd_type.aa() == na_gua || rsd_type.aa() == na_rgu || rsd_type.aa() == na_rad ) {
168  if ( strand == 1 ) {
169  a1 = "N1";
170  a2 = "C4";
171  } else {
172  a1 = "C4";
173  a2 = "N1";
174  }
175  } else if ( rsd_type.aa() == na_cyt || rsd_type.aa() == na_thy || rsd_type.aa() == na_rcy || rsd_type.aa() == na_ura ) {
176  if ( strand == 1 ) {
177  a1 = "N3";
178  a2 = "C6";
179  } else {
180  a1 = "C6";
181  a2 = "N3";
182  }
183  } else {
184  std::cout << rsd_type.aa() << " is unknown to me, tovarisch!\n"; // AM
185  utility_exit();
186  }
187 }
188 ///////////////////////////////////////////////////////////////////////////////
189 Vector
191  conformation::Residue const & rsd,
192  int const strand
193 )
194 {
195  std::string a1,a2;
196  get_y_axis_atoms( rsd.type(), strand, a1, a2 );
197  return ( rsd.xyz( a2 ) - rsd.xyz( a1 ) ).normalized();
198 }
199 
200 
201 
202 ///////////////////////////////////////////////////////////////////////////////
203 Vector
205  conformation::Residue const & rsd
206 )
207 {
208  using namespace chemical;
209  if ( rsd.aa() == na_ade || rsd.aa() == na_gua || rsd.aa() == na_rgu || rsd.aa() == na_rad ) {
210  return rsd.xyz("C8");
211 
212  } else if ( rsd.aa() == na_thy || rsd.aa() == na_cyt || rsd.aa() == na_rcy || rsd.aa() == na_ura ) {
213  return rsd.xyz("C6");
214 
215  }
216  utility_exit_with_message("get_base_pair_y_axis_atom_xyz: bad aa");
217  return Vector(0.0);
218 }
219 
220 ///////////////////////////////////////////////////////////////////////////////
221 // only uses 6-membered ring
222 //
223 Vector
225  conformation::Residue const & rsd,
226  Vector const & y_axis
227 )
228 {
229  using namespace chemical;
230  assert( rsd.is_DNA() || rsd.is_RNA() );
231  Vector xx(0); // approximate x-axis direction
232  if ( rsd.aa() == na_ade || rsd.aa() == na_gua || rsd.aa() == na_rgu || rsd.aa() == na_rad ) {
233  xx = rsd.xyz("C5") + rsd.xyz("C6") - rsd.xyz("N3") - rsd.xyz("C2");
234  } else if ( rsd.aa() == na_thy || rsd.aa() == na_cyt || rsd.aa() == na_rcy || rsd.aa() == na_ura ) {
235  xx = rsd.xyz("C5") + rsd.xyz("C4") - rsd.xyz("N1") - rsd.xyz("C2");
236  } else {
237  utility_exit_with_message("get_z_axis: bad aa");
238  }
239 
240  return xx.cross( y_axis ).normalized();
241 }
242 
243 
244 ///////////////////////////////////////////////////////////////////////////////
245 Vector
246 strand_orientation_vector( conformation::Residue const & rsd, int const strand )
247 {
248  Vector orient( rsd.xyz("C3*") - rsd.xyz("C4*" ) );
249  if ( strand == 2 ) orient *= -1.0f;
250  orient.normalize();
251  return orient;
252 }
253 
254 ///////////////////////////////////////////////////////////////////////////////
255 // only uses 6-membered ring
256 //
257 Vector
259  conformation::Residue const & rsd,
260  Vector const & y_axis,
261  int const strand,
262  bool & flipped
263 )
264 {
265  Vector z_axis( get_z_axis( rsd, y_axis ) );
266 
267  // flip z-axis if necessary
268  Vector const orient( strand_orientation_vector( rsd, strand ) );
269  if ( dot( z_axis, orient ) < 0.0 ) {
270  flipped = true;
271  z_axis *= -1.0f;
272  } else {
273  flipped = false;
274  }
275  assert( std::abs( z_axis.dot( y_axis ) ) < 1e-3 );
276 
277  return z_axis;
278 }
279 
280 ///////////////////////////////////////////////////////////////////////////////
281 // only uses 6-membered ring
282 //
283 // dont care about flips??
284 Vector
286  conformation::Residue const & rsd,
287  Vector const & y_axis,
288  int const strand
289 )
290 {
291  bool flipped( false );
292  return get_z_axis( rsd, y_axis, strand, flipped );
293 }
294 
295 
296 
297  /// helper fxn
298 bool
300  numeric::xyzMatrix< Real > const & M,
301  //Matrix const & M,
302  Real const tol
303 )
304 {
305  Matrix X( M*M.transposed() );
306  float dev( 0.0 );
307  for( int i=1; i<=3; ++i ) {
308  for( int j=1; j<=3; ++j ) {
309  dev += std::abs( X(i,j) - ( i == j ? 1.0 : 0.0 ) );
310  }
311  }
312  return dev < tol;
313 }
314 
315 
316 ///////////////////////////////////////////////////////////////////////////////
317 // stolen/borrowed from Alex Morozov!
318 //
319 
322  conformation::Residue const & rsd,
323  int const strand
324 )
325 {
326  using numeric::conversions::degrees;
327 
328  std::string a1,a2;
329  get_y_axis_atoms( rsd.type(), strand, a1, a2 );
330 
331  Vector const & v1( rsd.xyz( a1 ) );
332  Vector const & v2( rsd.xyz( a2 ) );
333 
334  Vector x_axis, y_axis, z_axis, origin;
335 
336  y_axis = v2 - v1;
337  y_axis.normalize();
338 
339  origin = 0.5f * (v1 + v2 );
340 
341  bool flipped( false );
342  z_axis = get_z_axis( rsd, y_axis, strand, flipped );
343  if ( flipped ) {
344  basic::T( "core.scoring.dna.base_geometry", basic::t_warning ) << "base flip in get_base_stub!!!" << '\n';
345  }
346  assert( std::abs( dot(y_axis, z_axis) ) < 1e-3 );
347 
348  x_axis = cross( y_axis, z_axis );
349  x_axis.normalize();
350 
351  return kinematics::Stub( kinematics::Stub::Matrix::cols( x_axis, y_axis, z_axis ), origin );
352 }
353 
354 ///////////////////////////////////////////////////////////////////////////////
355 
358  conformation::Residue const & rsd1, // on strand I
359  conformation::Residue const & rsd2 // on strand II
360 )
361 {
362  using numeric::conversions::degrees;
363 
364  Vector const y1( get_base_pair_y_axis_atom_xyz( rsd1 ) );
365  Vector const y2( get_base_pair_y_axis_atom_xyz( rsd2 ) );
366  Vector const origin( Real( 0.5 )* ( y1 + y2 ) );
367  Vector const y_axis( ( y1 - y2 ).normalized() );
368 
369  Vector const z1_axis( get_z_axis( rsd1, y_axis, 1 ) );
370  Vector const z2_axis( get_z_axis( rsd2, y_axis, 2 ) );
371  Vector z_axis;
372  if ( z1_axis.dot( z2_axis ) < 0.0 ) {
373  basic::T( "core.scoring.dna.base_geometry", basic::t_warning ) << "wacky base flip in get_base_pair_stub!!!" << '\n';
374  z_axis = z1_axis;
375  } else {
376  z_axis = ( z1_axis + z2_axis ).normalized();
377  }
378  assert( std::abs( y_axis.dot( z_axis ) ) <1e-3 );
379  Vector x_axis( cross( y_axis, z_axis ) );
380  x_axis.normalize(); // prob unnecessary
381 
382  return kinematics::Stub( kinematics::Stub::Matrix::cols( x_axis, y_axis, z_axis ), origin );
383 }
384 
385 ///////////////////////////////////////////////////////////////////////////////
386 
389  conformation::Residue const & rsd1, // on strand I
390  conformation::Residue const & rsd2 // on strand II
391 )
392 {
393  using numeric::conversions::degrees;
394 
395  Vector const y1( get_base_pair_y_axis_atom_xyz( rsd1 ) );
396  Vector const y2( get_base_pair_y_axis_atom_xyz( rsd2 ) );
397  Vector const origin( Real( 0.5 )* ( y1 + y2 ) );
398  Vector const y_axis( ( y1 - y2 ).normalized() );
399 
400  assert( rsd1.atom_is_backbone( rsd1.chi_atoms(1)[2] ) && !rsd1.atom_is_backbone( rsd1.chi_atoms(1)[3] ) &&
401  rsd2.atom_is_backbone( rsd2.chi_atoms(1)[2] ) && !rsd2.atom_is_backbone( rsd2.chi_atoms(1)[3] ) );
402 
403  utility::vector1< Vector > basepair_atoms;
404 
405  Size first_base_sidechain_atom = rsd1.first_sidechain_atom();
406  if ( rsd1.is_RNA() ) {
407  ++first_base_sidechain_atom;
408  }
409  for ( Size i = first_base_sidechain_atom; i<= rsd1.nheavyatoms(); ++i ) {
410  basepair_atoms.push_back( rsd1.xyz(i) );
411  }
412 
413  first_base_sidechain_atom = rsd2.first_sidechain_atom();
414  if ( rsd1.is_RNA() ) {
415  ++first_base_sidechain_atom;
416  }
417  for ( Size i = first_base_sidechain_atom; i<= rsd2.nheavyatoms(); ++i ) {
418  basepair_atoms.push_back( rsd2.xyz(i) );
419  }
420 
421  Vector z_axis( lsf_normal( basepair_atoms ) );
422  z_axis = ( z_axis - y_axis.dot( z_axis ) * y_axis ).normalized();
423  assert( z_axis.is_normalized( 1e-3 ) && z_axis.dot( y_axis ) < 1e-3 );
424  if ( z_axis.dot( strand_orientation_vector( rsd1, 1 ) ) < 0.0 ) z_axis *= Real(-1.0);
425 
426  Vector x_axis( cross( y_axis, z_axis ) );
427  x_axis.normalize(); // prob unnecessary
428 
429  return kinematics::Stub( kinematics::Stub::Matrix::cols( x_axis, y_axis, z_axis ), origin );
430 }
431 
432 ///////////////////////////////////////////////////////////////////////////////
433 void
435  conformation::Residue const & rsd1,
436  conformation::Residue const & rsd2,
437  std::ostream & out
438 )
439 {
440  DNA_BasePotential const & potential( ScoringManager::get_instance()->get_DNA_BasePotential() );
441 
442  using namespace fmt;
443  Params params(6);
444  get_base_pair_params(rsd1,rsd2,params);
445  utility::vector1< Real > z_scores(6,0.0);
446 
447  potential.eval_base_pair_Z_scores( rsd1, rsd2, z_scores );
448  Real dev(0.0);
449  for ( Size i=1; i<= 6; ++i ) dev += z_scores[i]*z_scores[i];
450  out << "BP_PARAMS " <<
451  F(7,1,potential.base_pair_score( rsd1, rsd2 ) ) << F(7,1,dev) <<
452  I(4,rsd1.seqpos()) << I(4,rsd2.seqpos()) << ' ' << rsd1.name1() << rsd2.name1() <<
453  " Prop: " << F(7,1,params[1]) << F(6,1,z_scores[1]) <<
454  " Buck: " << F(7,1,params[2]) << F(6,1,z_scores[2]) <<
455  " Open: " << F(7,1,params[3]) << F(6,1,z_scores[3]) <<
456  " Sher: " << F(7,2,params[4]) << F(6,1,z_scores[4]) <<
457  " Strc: " << F(7,2,params[5]) << F(6,1,z_scores[5]) <<
458  " Stag: " << F(7,2,params[6]) << F(6,1,z_scores[6]) << '\n';
459 }
460 
461 ///////////////////////////////////////////////////////////////////////////////
462 void
464  conformation::Residue const & rsd1,
465  conformation::Residue const & rsd2,
466  std::ostream & out
467 )
468 {
469  //DNA_BasePotential const & potential( ScoringManager::get_instance()->get_DNA_BasePotential() );
470 
471  using namespace fmt;
472  Params params(6);
473  get_base_pair_params(rsd1,rsd2,params);
474  out << "BP_PARAMS " << I(4,rsd1.seqpos()) << I(4,rsd2.seqpos()) << ' ' << rsd1.name1() << rsd2.name1() <<
475  " Prop:" << F(6,1,params[1]) <<
476  " Buck:" << F(6,1,params[2]) <<
477  " Open:" << F(6,1,params[3]) <<
478  " Sher:" << F(6,2,params[4]) <<
479  " Strc:" << F(6,2,params[5]) <<
480  " Stag:" << F(6,2,params[6]) << '\n';
481 }
482 
483 ///////////////////////////////////////////////////////////////////////////////
484 void
486  conformation::Residue const & rsd1,
487  conformation::Residue const & rsd2
488 )
489 {
490  show_base_pair_params( rsd1, rsd2, std::cout );
491 }
492 ///////////////////////////////////////////////////////////////////////////////
493 /**
494  works as-is for base pair with stub1 ~ strand I, stub2 ~ strand II
495  for base-step we use the mapping:
496 
497  step pair
498  ------------
499  z -> y
500  y -> x
501  x -> z
502  ------------
503  i+1 -> I (stub1)
504  i -> II (stub2)
505  ------------
506  ------------
507 
508 
509  mid-stub coordsys generated by aligning the y-axes.
510 
511  params[1] = oriented angle from the stub2 z-axis to the stub1 z-axis after aligning y-axes
512  = ( same as oriented angle from the stub2 x-axis to the stub1 x-axis after aligning y-axes )
513  = atan2( dot( stub1-z, stub2-x ), dot( stub1-z, stub2-z ) )
514  = atan2( y-coord( stub1-z ), x-coord( stub1-z ) ) in z-x coordinate system.
515  = propeller (twist)
516 
517  params[2] = x-component of the rotation axis from stub2-y to stub1-y, weighted by rotation angle
518  = buckle (roll)
519 
520  params[3] = z-component of the rotation axis from stub2-y to stub1-y, weighted by rotation angle
521  = opening (tilt)
522 
523  params[4] = x-coordinate of the vector from stub2-origin to stub1-origin
524  = shear (slide)
525 
526  params[5] = y-coordinate of the vector from stub2-origin to stub1-origin
527  = stretch (rise)
528 
529  params[6] = z-coordinate of the vector from stub2-origin to stub1-origin
530  = stagger (shift)
531 
532 
533  NAMES pair step
534  ------------------------------
535  params[1] = propeller twist
536  params[2] = buckle roll
537  params[3] = opening tilt
538  params[4] = shear slide
539  params[5] = stretch rise
540  params[6] = stagger shift
541 
542 **/
543 
544 void
546  kinematics::Stub const & stub1,
547  kinematics::Stub const & stub2,
548  Params & params
549 )
550 {
551  using namespace std;
552  using numeric::conversions::degrees;
553  using numeric::arccos;
554 
555  bool const local_debug( true ); // PBHACK!!!!!!!!!!!!!!!!!!!!!!
556  params.resize(6);
557 
558  // copy matrices
559  Matrix M1( stub1.M ), M2( stub2.M );
560 
561  assert( is_orthonormal( M1, 1e-3 ) );
562  assert( is_orthonormal( M2, 1e-3 ) );
563 
564  bool base_flipped = false;
565  if ( dot( M1.col_z(), M2.col_z() ) < 0.0 ) {
566  base_flipped = true;
567  basic::T("core.scoring.base_geometry") << "get_stub_stub_params: base flip!!!\n";
568  for (Size i = 1; i <= 6; ++i) {
569  params[i] = -9999;
570  }
571  return;
572  //utility::exit( EXIT_FAILURE, __FILE__, __LINE__);
573  }
574 
575  // get angle between the y-axes
576  Real const gamma( arccos( dot( M1.col_y(), M2.col_y() ) ) );
577 
578  Vector const bo( ( cross( M2.col_y(), M1.col_y() ) ).normalized() );
579 
580  Matrix R_gamma_2( rotation_matrix( bo, gamma/2.0f ) );
581 
582  M2 = R_gamma_2 * M2;
583  M1 = R_gamma_2.transposed() * M1;
584 
585  assert( is_orthonormal( M1, 1e-3 ) );
586  assert( is_orthonormal( M2, 1e-3 ) );
587 
588  // build mid-stub triad
589  assert( M1.col_y().distance( M2.col_y() ) < 1e-3 );
590  assert( std::abs( dot( bo, M1.col_y() ) ) < 1e-3 );
591 
592  Matrix MBT;
593  MBT.col_y( M1.col_y() );
594 
595  assert( std::abs( dot( M1.col_z(), MBT.col_y() ) ) < 1e-3 );
596  assert( std::abs( dot( M2.col_z(), MBT.col_y() ) ) < 1e-3 );
597  assert( std::abs( dot( M1.col_x(), MBT.col_y() ) ) < 1e-3 );
598  assert( std::abs( dot( M2.col_x(), MBT.col_y() ) ) < 1e-3 );
599 
600  // get
601  MBT.col_x( ( 0.5f * ( M1.col_x() + M2.col_x() ) ).normalized() );
602  MBT.col_z( ( 0.5f * ( M1.col_z() + M2.col_z() ) ).normalized() );
603 
604  assert( is_orthonormal( MBT, 1e-3 ) );
605 
606  // angular params
607 
608  // propellor
609  // z,x,y make rh coord system
610  params[1] = std::atan2( dot( M1.col_z(), M2.col_x() ),
611  dot( M1.col_z(), M2.col_z() ) );
612 
613  assert( !local_debug || ( std::abs( std::abs( params[1] ) - arccos( dot( M1.col_z(), M2.col_z() ) ) ) < 1e-2 ) );
614 
615  // buckle:
616  params[2] = gamma * dot( bo, MBT.col_x() );
617 
618  // opening
619  params[3] = gamma * dot( bo, MBT.col_z() );
620 
621  // translational params
622  Vector const displacement( stub1.v - stub2.v );
623 
624  params[4] = dot( displacement, MBT.col_x() );
625  params[5] = dot( displacement, MBT.col_y() );
626  params[6] = dot( displacement, MBT.col_z() );
627 
628  /////////////
629  // remove this debugging stuff, preserved in old code at the end of the file
630  if ( local_debug ) {
631  { // sin gamma version of params[2] is a simple dot product:
632  //Real const tmp1 = (sin( gamma ) * params[2] / gamma);
633  //Real const tmp2 = dot( Vector( cross( stub2.M.col_y(), stub1.M.col_y() ) ), MBT.col_x() );
634  assert( abs( (sin( gamma ) * params[2] / gamma) -
635  dot( Vector( cross( stub2.M.col_y(), stub1.M.col_y() ) ), MBT.col_x() )) < 1e-2 );
636  }
637 
638  { // sin gamma version of params[3] is a simple dot product:
639  //Real const tmp1( sin( gamma ) * params[3] / gamma );
640  //Real const tmp2( dot( Vector( cross( stub2.M.col_y(), stub1.M.col_y() )), MBT.col_z() ) );
641  assert( abs( ( sin( gamma ) * params[3] / gamma ) -
642  dot( Vector( cross( stub2.M.col_y(), stub1.M.col_y() )), MBT.col_z() ) ) < 1e-2 );
643  }
644 
645  // check sign conventions
646  Real phi_prime( arccos( dot( bo, MBT.col_x() ) ) );
647  if ( dot( cross( bo, MBT.col_x() ), MBT.col_y() ) < 0.0f ) {
648  phi_prime *= -1.0f;
649  }
650 
651  Vector tmp( cross( M2.col_z(), M1.col_z() ) );
652  assert( cross( tmp, MBT.col_y() ).length() <1e-2 );
653 
654  //Real const p1x = std::asin( dot( MBT.col_y(), cross( M2.col_x(), M1.col_x() ) ) );
655  //Real const p1z = std::asin( dot( MBT.col_y(), cross( M2.col_z(), M1.col_z() ) ) );
656  assert( ( base_flipped ) ||
657  ( abs( params[1] - asin( dot( MBT.col_y(), cross( M2.col_x(), M1.col_x() ) ) ) ) +
658  abs( params[1] - asin( dot( MBT.col_y(), cross( M2.col_z(), M1.col_z() ) ) ) ) < 1e-2 ) );
659  //std::cout << "equal? p1: " << params[1] << ' ' << p1x << ' ' << p1z <<
660  // std::endl;
661 
662  //Real const p2 = gamma * cos( phi_prime );
663  //Real const p3 = gamma * sin( phi_prime );
664  //Real const dev( std::abs( p2 - params[2] ) + std::abs( p3 - params[3] ) );
665  //std::cout << "dev: " << dev << std::endl;
666  assert( abs( gamma * cos( phi_prime ) - params[2] ) + abs( gamma * sin( phi_prime ) - params[3] ) < 1e-2 );
667 
668  // check sign conventions
669  assert( params[1] * dot( MBT.col_y(), cross( M2.col_x(), M1.col_x() ) ) > 0);
670  }
671 
672  // convert to degrees
673  params[1] = degrees( params[1] );
674  params[2] = degrees( params[2] );
675  params[3] = degrees( params[3] );
676 
677 }
678 
679 
680 ///////////////////////////////////////////////////////////////////////////////
681 ///////////////////////////////////////////////////////////////////////////////
682 // checking these with X3DNA
683 //
684 // use find_pair followed by cehs:
685 //
686 // 1111 ~/X3DNA/bin/find_pair -t pap1_subset.pdb pap1_subset.pdb.inp
687 // 1112 ~/X3DNA/bin/cehs pap1_subset.pdb.inp
688 // 1113 new
689 // 1114 more pap1_subset.outc
690 //
691 ///////////////////////////////////////////////////////////////////////////////
692 ///////////////////////////////////////////////////////////////////////////////
693 //
694 // aa1 is in strand1, aa2 is in strand2
695 //
696 void
698  conformation::Residue const & rsd1,
699  conformation::Residue const & rsd2,
700  Params & params // output
701 )
702 {
703  get_stub_stub_params( get_base_stub( rsd1, 1 /*strand*/ ),
704  get_base_stub( rsd2, 2 /*strand*/ ), params );
705 }
706 
707 
708 
709 ///////////////////////////////////////////////////////////////////////////////
710 //
711 // aa1 is in strand1, aa2 is in strand2
712 //
713 void
715  conformation::Residue const & rsd11, // pair1 strand I
716  conformation::Residue const & rsd12, // pair1 strand II
717  conformation::Residue const & rsd21, // pair2 strand I
718  conformation::Residue const & rsd22, // pair2 strand II
719  Params & params // output
720 )
721 {
722  using kinematics::Stub;
723 
724  assert( rsd21.seqpos() == rsd11.seqpos() + 1 && rsd12.seqpos() == rsd22.seqpos() + 1 );
725 
726  //Stub const stub1( get_base_pair_stub( rsd11, rsd12)), stub2( get_base_pair_stub( rsd21, rsd22 ) );
727  Stub const stub1( get_base_pair_stub_slow( rsd11, rsd12)), stub2( get_base_pair_stub_slow( rsd21, rsd22 ) );
728 
729  get_stub_stub_params( Stub( Stub::Matrix::cols( stub2.M.col_y(), stub2.M.col_z(), stub2.M.col_x() ), stub2.v ),
730  Stub( Stub::Matrix::cols( stub1.M.col_y(), stub1.M.col_z(), stub1.M.col_x() ), stub1.v ),
731  params );
732 
733 }
734 
735 
736 
737 ///////////////////////////////////////////////////////////////////////////////
738 bool
740  Size const seqpos,
741  pose::Pose const & pose
742 )
743 {
744  BasePartner const & partner( retrieve_base_partner_from_pose( pose ) );
745  conformation::Residue const & rsd( pose.residue( seqpos ) );
746 
747  return ( seqpos < pose.total_residue() && ( rsd.is_DNA() || rsd.is_RNA() )&& !rsd.is_lower_terminus() && partner[ seqpos ] &&
748  partner[ seqpos+1 ] && partner[seqpos] == partner[seqpos+1]+1 && partner[seqpos] != seqpos+1 );
749 }
750 
751 
752 ///////////////////////////////////////////////////////////////////////////////
753 
754 void
756  Size const seqpos,
757  pose::Pose const & pose,
758  std::ostream & out
759 )
760 {
761 
762  using namespace fmt;
763  Params params(6);
764 
765  BasePartner const & partner( retrieve_base_partner_from_pose( pose ) );
766 
767  if ( !seqpos_is_base_step_anchor( seqpos, pose ) ) {
768  out << "BS_PARAMS " << seqpos << " N/A\n";
769  return;
770  }
771 
772  conformation::Residue const & rsd11( pose.residue( seqpos ) );
773  conformation::Residue const & rsd12( pose.residue( partner[ seqpos ] ) );
774  conformation::Residue const & rsd21( pose.residue( seqpos+1 ) );
775  conformation::Residue const & rsd22( pose.residue( partner[ seqpos+1 ] ) );
776  get_base_step_params( rsd11, rsd12, rsd21, rsd22, params );
777 
778  out << "BS_PARAMS " <<
779  I(4,seqpos ) << I(4,partner[seqpos ]) << ' ' << rsd11.name1() << rsd12.name1() << " to " <<
780  I(4,seqpos+1) << I(4,partner[seqpos+1]) << ' ' << rsd21.name1() << rsd22.name1() <<
781  " Twst:" << F(6,1,params[1]) <<
782  " Roll:" << F(6,1,params[2]) <<
783  " Tilt:" << F(6,1,params[3]) <<
784  " Slid:" << F(6,2,params[4]) <<
785  " Rise:" << F(6,2,params[5]) <<
786  " Shft:" << F(6,2,params[6]) << '\n';
787 }
788 
789 void
791  conformation::Residue const & rsd1,
792  conformation::Residue const & rsd2
793 )
794 {
795  DNA_BasePotential const & potential( ScoringManager::get_instance()->get_DNA_BasePotential() );
796 
797  using namespace fmt;
798  Params params(6);
799  get_base_step_params(rsd1,rsd2,params);
800  utility::vector1< Real > z_scores(6,0.0);
801  potential.eval_base_step_Z_scores( rsd1, rsd2, z_scores );
802  Real dev(0.0);
803  for ( Size i=1; i<= 6; ++i ) dev += z_scores[i]*z_scores[i];
804  std::cout << "BS-params: " <<
805  F(7,1,potential.base_step_score( rsd1, rsd2 ) ) << F(7,1,dev) <<
806  I(4,rsd1.seqpos()) << I(4,rsd2.seqpos()) << ' ' << rsd1.name1() << rsd2.name1() <<
807  " Twst: " << F(7,1,params[1]) << F(6,1,z_scores[1]) <<
808  " Roll: " << F(7,1,params[2]) << F(6,1,z_scores[2]) <<
809  " Tilt: " << F(7,1,params[3]) << F(6,1,z_scores[3]) <<
810  " Shft: " << F(7,2,params[4]) << F(6,1,z_scores[4]) <<
811  " Slid: " << F(7,2,params[5]) << F(6,1,z_scores[5]) <<
812  " Rise: " << F(7,2,params[6]) << F(6,1,z_scores[6]) << std::endl;
813 }
814 
815 ///////////////////////////////////////////////////////////////////////////////
816 void
818  pose::Pose const & pose,
819  std::ostream & out
820  )
821 {
822 
823  for ( Size i=1; i<= pose.total_residue(); ++i ) {
824  if ( seqpos_is_base_step_anchor( i, pose ) ) {
825  show_base_step_params( i, pose, out );
826  }
827  }
828 
829 }
830 
831 ///////////////////////////////////////////////////////////////////////////////
832 void
834  pose::Pose const & pose,
835  std::ostream & out
836  )
837 {
838  BasePartner const & partner( retrieve_base_partner_from_pose( pose ) );
839 
840  for ( Size i=1; i<= pose.total_residue(); ++i ) {
841  if ( partner[i] > i ) {
842  show_base_pair_params( pose.residue(i), pose.residue(partner[i]), out );
843  }
844  }
845 }
846 
847 /////////////////////////////////////////////////////////////////////////////////////////////
848 // might be useful at some point to get them from coordinates. in case atomtree has breaks...
849 //
850 // void
851 // get_dna_dihedrals(
852 // Size const seqpos,
853 // pose::Pose const & pose
854 // vector1< Real > & dihedrals
855 // )
856 // {
857 // dihedrals.resize( 7 );
858 // Residue const & rsd( pose.residue(seqpos) );
859 
860 
861 // }
862 
863 
864 /////////////////////////////////////////////////////////////////////////////////////////////
865 void
867  pose::Pose const & pose,
868  std::ostream & out
869  )
870 {
871 
872  // dihedrals + a/g bin + typeI,II + pucker
873  Size const nres( pose.total_residue() );
874 
875  for ( Size i=1; i<= nres; ++i ) {
876  conformation::Residue const & rsd( pose.residue(i) );
877  if ( !rsd.is_DNA() || rsd.is_RNA() ) continue;
878  std::pair< std::string, int > pucker;
879  get_base_pucker( rsd, pucker );
880 
881  out << "DNA_DIHEDRALS " << I(4,i) << ' ' << rsd.name1() << ' ' <<
882  pucker.first << right_string_of( pucker.second, 3 ) << ' ' << get_DNA_backbone_bin( rsd ) <<
883  F(7,1,rsd.mainchain_torsion(1)) <<
884  F(7,1,rsd.mainchain_torsion(2)) <<
885  F(7,1,rsd.mainchain_torsion(3)) <<
886  F(7,1,rsd.mainchain_torsion(4)) <<
887  F(7,1,rsd.mainchain_torsion(5)) <<
888  F(7,1,rsd.mainchain_torsion(6)) <<
889  F(7,1,rsd.chi(1)) << '\n';
890  }
891 
892  // base-pair params
893  show_base_pair_params( pose, out );
894 
895  // base-step params
896  show_base_step_params( pose, out );
897 
898 }
899 
900 ///////////////////////////////////////////////////////////////////
901 /// if you really want the least-squares plane:
902 /// Thanks to Alex Morozov for implementing this:
903 ///
904 /// V.Schomaker et al. Acta Cryst. (1959) 12, 600-604
905 /// D.M.Blow Acta Cryst. (1960) 13, 168
906 ///
907 /// Note: no guarantee about the orientation of the returned vector...
908 ///
909 
910 Vector
912  utility::vector1< Vector > const & atoms_in
913 )
914 {
915  // translate the atoms so center of mass is at the origin
916  Vector cm(0.0);
917  int const natoms( atoms_in.size() );
918  for ( int i=1; i<= natoms; ++i ) {
919  cm += atoms_in[i];
920  }
921 
922  cm /= natoms;
923 
924  utility::vector1< Vector > atoms; atoms.reserve( natoms );
925  for ( int i=1; i<= natoms; ++i ) {
926  atoms.push_back( atoms_in[i] - cm );
927  }
928 
929  // Create a matrix which provides coeffs for the cubic equation.
930  // Note that A(i,j) = A(j,i).
931  //FArray2D_Real A( 3, 3, 0.0f );
932  Matrix A( 0.0 );
933  for ( int i = 1; i <= 3; ++i ) {
934  for ( int j = i; j <= 3; ++j ) {
935  for ( int a = 1; a <= natoms; ++a ) {
936  A(i,j) += atoms[a](i) * atoms[a](j);//coords2fit(i,a)*coords2fit(j,a);
937  }
938  }
939  }
940 
941  // Compute cubic eqn. coeffs:
942  Real a = A(1,1) + A(2,2) + A(3,3); // alpha
943  Real b = A(1,3)*A(1,3) + A(1,2)*A(1,2) + A(2,3)*A(2,3)
944  - A(2,2)*A(3,3) - A(1,1)*A(3,3) - A(1,1)*A(2,2); // beta
945  Real g = A(1,1)*A(2,2)*A(3,3) + 2*A(1,2)*A(2,3)*A(1,3)
946  - A(1,1)*A(2,3)*A(2,3) - A(2,2)*A(1,3)*A(1,3)
947  - A(3,3)*A(1,2)*A(1,2); // gamma
948 
949  // The solution to the cubic eqn. is obtained through neglecting the
950  // lambda**3 term (lambda is small for nearly planar atom sets):
951  // WARNING: bound to fail for REALLY nonplanar atom sets!
952  Real lambda;
953  if (b*b - 4*a*g > 0) {
954  lambda = (-b - std::sqrt(b*b - 4*a*g) )/(2*a);
955  } else {
956  lambda = 0;
957  }
958 
959  // debug
960  //std::cout << "lambda = " << lambda << std::endl;
961  //std::cout << "D = " << (b*b - 4*a*g) << std::endl;
962  // Finally, compute the eigenvector corresponding to the least squares plane:
963 
964  Vector normal_f;
965  normal_f(1) = (A(2,2)-lambda)*A(1,3) - A(1,2)*A(2,3);
966  normal_f(2) = (A(1,1)-lambda)*A(2,3) - A(1,2)*A(1,3);
967  normal_f(3) = A(1,2)*A(1,2) - (A(2,2)-lambda)*(A(1,1)-lambda);
968 
969  normal_f.normalize();
970  return normal_f;
971 }
972 /////////////////////////////////////////////////////////////////////////////////////////////
973 /////////////////////////////////////////////////////////////////////////////////////////////
974 /////////////////////////////////////////////////////////////////////////////////////////////
975 /////////////////////////////////////////////////////////////////////////////////////////////
976 /////////////////////////////////////////////////////////////////////////////////////////////
977 /////////////////////////////////////////////////////////////////////////////////////////////
978 /////////////////////////////////////////////////////////////////////////////////////////////
979 /////////////////////////////////////////////////////////////////////////////////////////////
980 /////////////////////////////////////////////////////////////////////////////////////////////
981 /// saved for comparison and debugging purposes
982 /////////////////////////////////////////////////////////////////////////////////////////////
983 /////////////////////////////////////////////////////////////////////////////////////////////
984 
985 void
987  conformation::Residue const & rsd1,
988  conformation::Residue const & rsd2,
989  Params & params // output
990 )
991 {
992  using numeric::conversions::degrees;
993  using numeric::arccos;
994 
995  bool const local_debug( false );
996 
997  params.resize(6);
998 
999  kinematics::Stub const stub1( get_base_stub( rsd1, 1 /*strand*/ )), stub2( get_base_stub( rsd2, 2 /*strand*/ ) );
1000 
1001  // copy matrices
1002  Matrix M1( stub1.M ), M2( stub2.M );
1003 
1004  assert( is_orthonormal( M1, 1e-3 ) );
1005  assert( is_orthonormal( M2, 1e-3 ) );
1006 
1007  bool base_flipped = false;
1008  if ( dot( M1.col_z(), M2.col_z() ) < 0.0 ) {
1009  base_flipped = true;
1010  basic::T("core.scoring.base_geometry") << "base_pair_params: base flip!!!\n";
1011  //utility::exit( EXIT_FAILURE, __FILE__, __LINE__);
1012  }
1013 
1014  // get angle between the y-axes
1015  Real const gamma( arccos( dot( M1.col_y(), M2.col_y() ) ) );
1016 
1017  Vector const bo( ( cross( M2.col_y(), M1.col_y() ) ).normalized() );
1018 
1019  Matrix R_gamma_2( rotation_matrix( bo, gamma/2.0f ) );
1020 
1021  M2 = R_gamma_2 * M2;
1022  M1 = R_gamma_2.transposed() * M1;
1023 
1024  assert( is_orthonormal( M1, 1e-3 ) );
1025  assert( is_orthonormal( M2, 1e-3 ) );
1026 
1027  // build mid-base-pair triad
1028  assert( M1.col_y().distance( M2.col_y() ) < 1e-3 );
1029  assert( std::abs( dot( bo, M1.col_y() ) ) < 1e-3 );
1030 
1031  Matrix MBT;
1032  MBT.col_y( M1.col_y() );
1033 
1034  assert( std::abs( dot( M1.col_z(), MBT.col_y() ) ) < 1e-3 );
1035  assert( std::abs( dot( M2.col_z(), MBT.col_y() ) ) < 1e-3 );
1036  assert( std::abs( dot( M1.col_x(), MBT.col_y() ) ) < 1e-3 );
1037  assert( std::abs( dot( M2.col_x(), MBT.col_y() ) ) < 1e-3 );
1038 
1039  // get
1040  MBT.col_x( ( 0.5f * ( M1.col_x() + M2.col_x() ) ).normalized() );
1041  MBT.col_z( ( 0.5f * ( M1.col_z() + M2.col_z() ) ).normalized() );
1042 
1043  assert( is_orthonormal( MBT, 1e-3 ) );
1044 
1045  // angular params
1046 
1047  // propellor
1048  // z,x,y make rh coord system
1049  params[1] = std::atan2( dot( M1.col_z(), M2.col_x() ),
1050  dot( M1.col_z(), M2.col_z() ) );
1051 
1052  if ( local_debug ) {
1053  assert( abs( abs( params[1] ) - arccos( dot( M1.col_z(), M2.col_z() ) ) ) < 1e-2 );
1054  }
1055 
1056  // buckle:
1057  params[2] = gamma * dot( bo, MBT.col_x() );
1058 
1059  // opening
1060  params[3] = gamma * dot( bo, MBT.col_z() );
1061 
1062  // translational params
1063  Vector const displacement( stub1.v - stub2.v );
1064 
1065  params[4] = dot( displacement, MBT.col_x() );
1066  params[5] = dot( displacement, MBT.col_y() );
1067  params[6] = dot( displacement, MBT.col_z() );
1068 
1069  /////////////
1070  // debugging:
1071  if ( local_debug ) {
1072  { // sin gamma version of params[2] is a simple dot product:
1073  //Real const tmp1 = sin( gamma ) * params[2] / gamma;
1074  //Real const tmp2 = dot( Vector( cross( stub2.M.col_y(), stub1.M.col_y() ) ), MBT.col_x() );
1075  assert( abs(sin( gamma ) * params[2] / gamma -
1076  dot( Vector( cross( stub2.M.col_y(), stub1.M.col_y() ) ), MBT.col_x() )) < 1e-2 );
1077  }
1078 
1079  { // sin gamma version of params[3] is a simple dot product:
1080  //Real const tmp1( sin( gamma ) * params[3] / gamma );
1081  //Real const tmp2( dot( Vector( cross( stub2.M.col_y(), stub1.M.col_y() )), MBT.col_z() ) );
1082  assert( abs(sin( gamma ) * params[3] / gamma -
1083  dot( Vector( cross( stub2.M.col_y(), stub1.M.col_y() )), MBT.col_z() )) < 1e-2 );
1084  }
1085 
1086  // check sign conventions
1087  Real phi_prime( arccos( dot( bo, MBT.col_x() ) ) );
1088  if ( dot( cross( bo, MBT.col_x() ), MBT.col_y() ) < 0.0f ) {
1089  phi_prime *= -1.0f;
1090  }
1091 
1092  Vector tmp( cross( M2.col_z(), M1.col_z() ) );
1093  assert( cross( tmp, MBT.col_y() ).length() <1e-2 );
1094 
1095  //Real const p1x = std::asin( dot( MBT.col_y(), cross( M2.col_x(), M1.col_x() ) ) );
1096  //Real const p1z = std::asin( dot( MBT.col_y(), cross( M2.col_z(), M1.col_z() ) ) );
1097  assert( ( base_flipped ) ||
1098  ( abs( params[1] - asin( dot( MBT.col_y(), cross( M2.col_x(), M1.col_x() ) ) ) ) +
1099  abs( params[1] - asin( dot( MBT.col_y(), cross( M2.col_z(), M1.col_z() ) ) ) ) < 1e-2 ) );
1100  //std::cout << "equal? p1: " << params[1] << ' ' << p1x << ' ' << p1z <<
1101  // std::endl;
1102 
1103  //Real const p2 = gamma * cos( phi_prime );
1104  //Real const p3 = gamma * sin( phi_prime );
1105  //Real const dev( std::abs( p2 - params[2] ) + std::abs( p3 - params[3] ) );
1106  //std::cout << "dev: " << dev << std::endl;
1107  assert( abs( gamma * cos( phi_prime ) - params[2] ) + abs( gamma * sin( phi_prime ) - params[3] ) < 1e-2 );
1108 
1109  // check sign conventions
1110  assert( params[1] * dot( MBT.col_y(), cross( M2.col_x(), M1.col_x() ) ) > 0);
1111  }
1112 
1113  // convert to degrees
1114  params[1] = degrees( params[1] );
1115  params[2] = degrees( params[2] );
1116  params[3] = degrees( params[3] );
1117 
1118 }
1119 
1120 ///////////////////////////////////////////////////////////////////////////////
1121 //
1122 //// saved for comparison and debugging purposes
1123 void
1125  conformation::Residue const & rsd1,
1126  conformation::Residue const & rsd2,
1127  Params & params // output
1128 )
1129 {
1130  using numeric::conversions::degrees;
1131  using numeric::arccos;
1132  using numeric::cross;
1133 
1134  bool const local_debug( false );
1135 
1136  params.resize(6);
1137 
1138  kinematics::Stub const stub1( get_base_stub( rsd1, 1 ) ), stub2( get_base_stub( rsd2, 1 ) ); // strand = 2
1139 
1140  // copy matrices
1141  Matrix M1( stub1.M ), M2( stub2.M );
1142 
1143  assert( is_orthonormal( M1, 1e-3 ) );
1144  assert( is_orthonormal( M2, 1e-3 ) );
1145 
1146  if ( dot( M1.col_z(), M2.col_z() ) < 0.0 ) {
1147  // BASE FLIP !!!!!!!!!!!!!!!!!!!!!!!!!!!!
1148  basic::T("core.scoring.base_geometry") << "base_pair_params: base flip!!!\n";
1149  //std::cout << "new_base_step_params: base flip!" << std::endl;
1150  //utility::exit( EXIT_FAILURE, __FILE__, __LINE__);
1151  }
1152 
1153  // get angle between the z-axes
1154  Real const gamma( arccos( dot( M1.col_z(), M2.col_z() ) ) );
1155 
1156  Vector const rt( ( cross( M2.col_z(), M1.col_z() ) ).normalized() );
1157 
1158  Matrix R_gamma_2( rotation_matrix( rt, gamma/2.0f ) );
1159 
1160  M2 = R_gamma_2 * M2;
1161  M1 = R_gamma_2.transposed() * M1;
1162 
1163  assert( is_orthonormal( M1, 1e-3 ) );
1164  assert( is_orthonormal( M2, 1e-3 ) );
1165 
1166  // build mid-base-pair triad
1167  assert( M1.col_z().distance( M2.col_z() ) < 1e-3 );
1168  assert( std::abs( dot( rt, M1.col_z() ) ) < 1e-3 );
1169 
1170  Matrix MBT;
1171  MBT.col_z( M1.col_z() );
1172 
1173  assert( std::abs( dot( M1.col_x(), MBT.col_z() ) ) < 1e-3 );
1174  assert( std::abs( dot( M2.col_x(), MBT.col_z() ) ) < 1e-3 );
1175  assert( std::abs( dot( M1.col_y(), MBT.col_z() ) ) < 1e-3 );
1176  assert( std::abs( dot( M2.col_y(), MBT.col_z() ) ) < 1e-3 );
1177 
1178  // get
1179  MBT.col_y( ( 0.5f * ( M1.col_y() + M2.col_y() ) ).normalized() );
1180  MBT.col_x( ( 0.5f * ( M1.col_x() + M2.col_x() ) ).normalized() );
1181 
1182  assert( is_orthonormal( MBT, 1e-3 ) );
1183 
1184  // angular params
1185 
1186  // TWIST
1187  // x,y,z make rh coord system
1188  params[1] = atan2( dot( M1.col_x(), M2.col_y() ), dot( M1.col_x(), M2.col_x() ) );
1189 
1190  if ( local_debug ) {
1191  assert( abs( abs( params[1] ) - arccos( dot( M1.col_x(), M2.col_x() ) ) ) < 1e-2 );
1192  }
1193 
1194 
1195  // ROLL:
1196  params[2] = gamma * dot( rt, MBT.col_y() );
1197 
1198  // TILT
1199  params[3] = gamma * dot( rt, MBT.col_x() );
1200 
1201  // translational params
1202  Vector const displacement( stub1.v - stub2.v );
1203 
1204  params[4] = dot( displacement, MBT.col_x() ); // SHIFT
1205  params[5] = dot( displacement, MBT.col_y() ); // SLIDE
1206  params[6] = dot( displacement, MBT.col_z() ); // RISE
1207 
1208  /////////////
1209  // debugging:
1210  if ( local_debug ) {
1211  { // sin gamma version of params[2] (roll) is a simple dot product:
1212  //Real const tmp1 = sin( gamma ) * params[2] / gamma;
1213  //Real const tmp2 = dot( Vector( cross( stub2.M.col_z(), stub1.M.col_z() ) ), MBT.col_y() );
1214  assert( abs( sin( gamma ) * params[2] / gamma -
1215  dot( Vector( cross( stub2.M.col_z(), stub1.M.col_z() ) ), MBT.col_y() )) < 1e-2 );
1216  }
1217 
1218  { // sin gamma version of params[3] (tilt) is a simple dot product:
1219  //Real const tmp1( sin( gamma ) * params[3] / gamma );
1220  //Real const tmp2( dot( Vector( cross( stub2.M.col_z(), stub1.M.col_z() )), MBT.col_x() ) );
1221  assert( abs( sin( gamma ) * params[3] / gamma -
1222  dot( Vector( cross( stub2.M.col_z(), stub1.M.col_z() )), MBT.col_x() )) < 1e-2 );
1223  }
1224 
1225  // check sign conventions
1226  Real phi_prime( arccos( dot( rt, MBT.col_y() ) ) );
1227  if ( dot( cross( rt, MBT.col_y() ), MBT.col_z() ) < 0.0f ) {
1228  phi_prime *= -1.0f;
1229  }
1230 
1231  Vector tmp( cross( M2.col_x(), M1.col_x() ) );
1232  assert( cross( tmp, MBT.col_z() ).length() <1e-2 );
1233 
1234  //Real const p1x = std::asin( dot( MBT.col_z(), cross( M2.col_y(), M1.col_y() ) ) );
1235  //Real const p1z = std::asin( dot( MBT.col_z(), cross( M2.col_x(), M1.col_x() ) ) );
1236  //std::cout << "equal? p1: " << params[1] << ' ' << p1x << ' ' << p1z <<
1237  // std::endl;
1238  assert( abs( params[1] - asin( dot( MBT.col_z(), cross( M2.col_y(), M1.col_y() ) ) ) ) +
1239  abs( params[1] - asin( dot( MBT.col_z(), cross( M2.col_x(), M1.col_x() ) ) ) ) < 1e-2 );
1240 
1241  //Real const p2 = gamma * cos( phi_prime );
1242  //Real const p3 = gamma * sin( phi_prime );
1243  //Real const dev( std::abs( p2 - params[2] ) + std::abs( p3 - params[3] ) );
1244  //std::cout << "dev: " << dev << std::endl;
1245  assert( abs( gamma * cos( phi_prime ) - params[2] ) + abs( gamma * sin( phi_prime ) - params[3] ) < 1e-2 );
1246 
1247  // check sign conventions
1248  assert( params[1] * dot( MBT.col_z(), cross( M2.col_y(), M1.col_y() ) ) > 0);
1249  }
1250 
1251  // convert to degrees
1252  params[1] = degrees( params[1] );
1253  params[2] = degrees( params[2] );
1254  params[3] = degrees( params[3] );
1255 }
1256 
1257 
1258 ////////////////////////////////////////////////////////////////////////////
1259 void
1261  conformation::Residue const & rsd,
1262  std::pair< std::string, int > & pucker,
1263  Real & pseudorotation,
1264  Real & amplitude
1265 )
1266 {
1267  using numeric::conversions::radians;
1268  using numeric::conversions::degrees;
1269 
1271  names.push_back( "C1*" );
1272  names.push_back( "C2*" );
1273  names.push_back( "C3*" );
1274  names.push_back( "C4*" );
1275  names.push_back( "O4*" );
1276 
1278  for ( int i=1; i<= 5; ++i ) {
1279  atoms.push_back( rsd.xyz( names[i] ) );
1280  }
1281 
1282  Real mindot = 1000.0;
1283  bool exxo( false );
1284  utility::vector1< Real > torsions(5, 0.0);
1285  for ( int ii=1; ii<= 5; ++ii ) {
1286 
1287  torsions[ ii ] = dihedral_radians(
1288  atoms[ 4 ],
1289  atoms[ 5 ],
1290  atoms[ 1 ],
1291  atoms[ 2 ]
1292  );
1293 
1294  Vector n12 = (( atoms[2]-atoms[1] ).cross( atoms[3]-atoms[2] ) ).normalized();
1295  Real dot = std::abs( n12.dot( ( atoms[4]-atoms[3] ).normalized() ) );
1296  if ( dot < mindot ) {
1297  // get pucker
1298  //Real pucker_dot = n12.dot( ( atoms[5] - Real(0.5) * ( atoms[4] + atoms[1] ) ).normalized() );
1299 
1300  mindot = dot;
1301  pucker.first = names[5];
1302  exxo = ( n12.dot( ( atoms[5] - Real(0.5) * ( atoms[4] + atoms[1] ) ).normalized() ) > 0.0 );
1303  }
1304 
1305  atoms.push_back( atoms[1] );
1306  atoms.erase( atoms.begin() );
1307 
1308  names.push_back( names[1] );
1309  names.erase( names.begin() );
1310 
1311  }
1312 
1313  pseudorotation = atan(
1314  ( ( torsions[2] + torsions[5] ) - ( torsions[1] + torsions[4] ) ) /
1315  ( 2.0 * torsions[3] * ( sin( radians(36.0) ) + sin( radians(72.0)) ) )
1316  );
1317 
1318  pseudorotation = degrees( pseudorotation );
1319  if( torsions[3] < 0.0 ) pseudorotation += 180.0;
1320 
1321  pseudorotation = basic::periodic_range( pseudorotation, 360.0 );
1322 
1323  amplitude = degrees( torsions[3] / ( cos( radians( pseudorotation ) ) + 1.0e-20 ) );
1324 
1325  // additional integer for scannability
1326  {
1327  int const atom_index( std::find( names.begin(), names.end(), pucker.first ) - names.begin() );
1328  int const sign_index( exxo ? 0 : 1 );
1329  if ( atom_index%2 == sign_index ) pucker.second = atom_index+1;
1330  else pucker.second = atom_index-4;
1331  }
1332 
1333  if ( exxo ) pucker.first += " exxo";
1334  else pucker.first += " endo";
1335 }
1336 
1337 ///////////////////////////////////////////////////////////////////////////////
1340  kinematics::Stub const & in_stub1,
1341  kinematics::Stub const & in_stub2
1342 )
1343 {
1344  using numeric::conversions::degrees;
1345  using numeric::arccos;
1346 
1347  // Reordering as Phil did
1348  kinematics::Stub stub1( kinematics::Stub::Matrix::cols( in_stub2.M.col_y(), in_stub2.M.col_z(), in_stub2.M.col_x() ), in_stub2.v );
1349  kinematics::Stub stub2( kinematics::Stub::Matrix::cols( in_stub1.M.col_y(), in_stub1.M.col_z(), in_stub1.M.col_x() ), in_stub1.v );
1350 
1351  // copy matrices
1352  Matrix M1( stub1.M ), M2( stub2.M );
1353 
1354  assert( is_orthonormal( M1, 1e-3 ) );
1355  assert( is_orthonormal( M2, 1e-3 ) );
1356 
1357  bool base_flipped = false;
1358  if ( dot( M1.col_z(), M2.col_z() ) < 0.0 ) {
1359  base_flipped = true;
1360  basic::T("core.scoring.base_geometry") << "get_midstep_stub: base flip!!!\n";
1361  //utility::exit( EXIT_FAILURE, __FILE__, __LINE__);
1362  }
1363 
1364  // The nomenclature for the angles is the base pair convention (buckle, opening)
1365  // but the math is the same as for base steps, and the code in get_stub_stub_params works
1366  // for both.
1367  //
1368  // get angle between the y-axes
1369  Real const gamma( arccos( dot( M1.col_y(), M2.col_y() ) ) );
1370 
1371  Vector const bo( ( cross( M2.col_y(), M1.col_y() ) ).normalized() );
1372 
1373  Matrix R_gamma_2( rotation_matrix( bo, gamma/2.0f ) );
1374 
1375  M2 = R_gamma_2 * M2;
1376  M1 = R_gamma_2.transposed() * M1;
1377 
1378  assert( is_orthonormal( M1, 1e-3 ) );
1379  assert( is_orthonormal( M2, 1e-3 ) );
1380 
1381  // build mid-stub triad
1382  assert( M1.col_y().distance( M2.col_y() ) < 1e-3 );
1383  assert( std::abs( dot( bo, M1.col_y() ) ) < 1e-3 );
1384 
1385  Matrix MBT;
1386  MBT.col_y( M1.col_y() );
1387 
1388  assert( std::abs( dot( M1.col_z(), MBT.col_y() ) ) < 1e-3 );
1389  assert( std::abs( dot( M2.col_z(), MBT.col_y() ) ) < 1e-3 );
1390  assert( std::abs( dot( M1.col_x(), MBT.col_y() ) ) < 1e-3 );
1391  assert( std::abs( dot( M2.col_x(), MBT.col_y() ) ) < 1e-3 );
1392 
1393  // get
1394  MBT.col_x( ( 0.5f * ( M1.col_x() + M2.col_x() ) ).normalized() );
1395  MBT.col_z( ( 0.5f * ( M1.col_z() + M2.col_z() ) ).normalized() );
1396 
1397  assert( is_orthonormal( MBT, 1e-3 ) );
1398 
1399  return kinematics::Stub( MBT, 0.5f*( stub1.v + stub2.v ) );
1400 
1401 }
1402 
1403 
1404 
1405 } // namespace dna
1406 }} // scoring core