Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ccd_closure.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 Phil Bradley
13 
14 
16 
17 // Rosetta Headers
18 #include <core/types.hh>
19 #include <core/pose/Pose.hh>
25 #include <core/kinematics/Stub.hh>
26 #include <basic/prof.hh>
27 #include <basic/basic.hh>
28 #include <basic/Tracer.hh>
29 
30 // ObjexxFCL Headers
31 #include <ObjexxFCL/format.hh>
32 #include <ObjexxFCL/string.functions.hh>
33 
34 // C++ Headers
35 
36 //Utility Headers
37 #include <numeric/xyz.functions.hh>
38 #include <numeric/numeric.functions.hh>
39 #include <numeric/random/random.fwd.hh>
40 #include <utility/assert.hh>
41 
42 #include <utility/vector1.hh>
43 
44 //Auto Headers
45 
46 
47 
48 using namespace ObjexxFCL;
49 using namespace ObjexxFCL::fmt;
50 
51 namespace protocols {
52 namespace loops {
53 namespace loop_closure {
54 namespace ccd {
55 
56 using namespace core;
57 using utility::vector1;
59 
60 basic::Tracer tccd( "protocols.loops.loop_closure.ccd.ccd_closure" );
61 
62 /////////////////////////////////////////////////////////////////////////////////
63 /// @brief copy mainchain atoms xyz and torsions from pose to coords and torsions
64 void
66  pose::Pose const & pose,
67  vector1< vector1< Vector > > & coords,
68  vector1< vector1< Real > > & torsions
69 )
70 {
71  Size const nres( pose.total_residue() );
72  coords.resize( nres );
73  torsions.resize( nres );
74 
75  for ( Size i=1; i<= nres; ++i ) {
76  conformation::Residue const & rsd( pose.residue(i) );
77  Size const nbb( rsd.mainchain_atoms().size() );
78  if ( nbb ) {
79  coords[i].resize( nbb );
80  torsions[i].resize( nbb );
81  for ( Size j=1; j <= nbb; ++j ) {
82  coords[i][j] = rsd.atom( rsd.mainchain_atoms()[j] ).xyz();
83  torsions[i][j] = rsd.mainchain_torsion(j);
84  }
85  }
86  }
87 
88 }
89 /////////////////////////////////////////////////////////////////////////////
90 ///@brief copy torsions into pose between residue loop_begin and loop_end
91 void
93  pose::Pose & pose,
94  int const loop_begin,
95  int const loop_end,
96  vector1< vector1< Real > > const & torsions
97 )
98 {
99  for ( int i=loop_begin; i<= loop_end; ++i ) {
100  for ( Size j=1; j<= torsions[i].size(); ++j ) {
101  //TorsionID id( i, id::BB, int(j) ), torsions[i][j] );
102  pose.set_torsion( id::TorsionID( i, id::BB, int(j) ), torsions[i][j] );
103  }
104  }
105 }
106 
107 ///////////////////////////////////////////////////////////////////////////
108 
109 void
111  vector1< vector1< Vector > > const & coords,
112  vector1< vector1< Real > > const & torsions,
113  int const cutpoint,
114  int const direction,
115  Real const bond_angle1,
116  Real const bond_length,
117  Real const bond_angle2,
118  Matrix & M
119 )
120 {
121  using numeric::conversions::radians;
122  using kinematics::Stub;
123 
124  bool const local_debug( false/*true*/ );
125 
126  Size const nbb( coords[cutpoint].size() );
127  assert( nbb >= 3 );
128 
129  // pack the coords, torsions, and angles
130  vector1< Vector > atoms( 6 );
131  vector1< Real > dihedrals( 3 );
132  vector1< Real > angles( 2 );
133 
134  if ( direction == 1 ) { // eg N->CA->C->N'->CA'->C'
135  for ( int i=1; i<= 3; ++i ) atoms[i ] = coords[ cutpoint ][ nbb-3+i ]; // 1,2,3: N, CA, C
136  for ( int i=1; i<= 3; ++i ) atoms[i+3] = coords[ cutpoint+1 ][ i ]; // 4,5,6: N',CA',C'
137  dihedrals[1] = radians( torsions[cutpoint ][ nbb-1 ] ); // N-CA-C-N'
138  dihedrals[2] = radians( torsions[cutpoint ][ nbb ] ); // CA-C-N'-CA'
139  dihedrals[3] = radians( torsions[cutpoint+1][ 1 ] ); // C-N'-CA'-C'
140  angles[1] = bond_angle1; // CA-C-N' already in radians
141  angles[2] = bond_angle2; // C-N'-CA' already in radian
142  } else { // eg N<-CA<-C<-N'<-CA'<-C'
143  for ( int i=1; i<= 3; ++i ) atoms[7-i ] = coords[ cutpoint ][ nbb-3+i ]; // 6,5,4: N, CA, C
144  for ( int i=1; i<= 3; ++i ) atoms[7-i-3] = coords[ cutpoint+1 ][ i ]; // 3,2,1: N',CA',C'
145  dihedrals[3] = radians( torsions[cutpoint ][ nbb-1 ] ); // N-CA-C-N'
146  dihedrals[2] = radians( torsions[cutpoint ][ nbb ] ); // CA-C-N'-CA'
147  dihedrals[1] = radians( torsions[cutpoint+1][ 1 ] ); // C-N'-CA'-C'
148  angles[2] = bond_angle1; // CA-C-N' already in radians
149  angles[1] = bond_angle2; // C-N'-CA' already in radians
150  }
151 
152  //build the two overlap atoms using bond_angle...
153  Vector atom3p, atom4p;
154  {
155  // atom4p is build forward, eg given N-CA-C, how to build N'
156  Stub const stub321( atoms[3], atoms[2], atoms[1] );
157  atom4p = stub321.spherical( dihedrals[1], angles[1], bond_length );
158 
159  // atom3p is built backward, eg given N'-CA'-C, how to build C
160  Stub const stub456( atoms[4], atoms[5], atoms[6] );
161  atom3p = stub456.spherical( dihedrals[3], angles[2], bond_length );
162  }
163 
164  Stub const stub1( atom4p, atoms[3], atoms[2] );
165  Stub const stub2( atoms[4], atom3p, atoms[5] );
166 
167  for ( int i=1; i<= 3; ++i ) {
168  M.col( i, stub1.local2global( stub2.global2local( atoms[3+i] ) ) );
169  }
170 
171  // M now corresponds to a torsion at the inter-residue bond of 0.0, need to adjust to proper torsion
172  Matrix const R( numeric::rotation_matrix_radians( ( atom4p - atoms[3] ).normalized(), dihedrals[2] ) );
173  M.col( 2, R * ( M.col(2) - atom4p ) + atom4p );
174  M.col( 3, R * ( M.col(3) - atom4p ) + atom4p );
175 
176  // confirm that the bond length, angle, and torsions are satisfied
177  if ( local_debug ) {
178  using basic::subtract_radian_angles;
179  ASSERT_ONLY( Real const dihedral1
180  ( dihedral_radians( atoms[1], atoms[2], atoms[3], M.col(1) ) );)
181  ASSERT_ONLY(Real const dihedral2
182  ( dihedral_radians( atoms[2], atoms[3], M.col(1), M.col(2) ) );)
183  ASSERT_ONLY(Real const dihedral3
184  ( dihedral_radians( atoms[3], M.col(1), M.col(2), M.col(3) ) );)
185 
186  ASSERT_ONLY(Real const angle1( std::acos( dot( ( atoms[3] - atoms[2] ).normalized(),
187  ( M.col(1) - atoms[3] ).normalized() ) ) );)
188  ASSERT_ONLY(Real const angle2( std::acos( dot( ( M.col(2) - M.col(1) ).normalized(),
189  ( M.col(1) - atoms[3] ).normalized() ) ) );)
190  ASSERT_ONLY(Real const length( atoms[3].distance( M.col(1) ) );)
191 
192  assert( std::abs( subtract_radian_angles( dihedral1, dihedrals[1] ) ) < 1e-3 );
193  assert( std::abs( subtract_radian_angles( dihedral2, dihedrals[2] ) ) < 1e-3 );
194  assert( std::abs( subtract_radian_angles( dihedral3, dihedrals[3] ) ) < 1e-3 );
195  assert( std::abs( subtract_radian_angles( angle1, angles[1] ) ) < 1e-3 );
196  assert( std::abs( subtract_radian_angles( angle2, angles[2] ) ) < 1e-3 );
197  assert( std::abs( length - bond_length ) < 1e-3 );
198  }
199 
200  // restore proper chain order for M if folding backward
201  if ( direction == -1 ) {
202  Matrix const tmp( M );
203  for ( int i=1; i<= 3; ++i ) M.col( i, tmp.col(4-i) );
204  }
205 }
206 
207 
208 ///////////////////////////////////////////////////////////////////////////
209 /// @brief check whether xyz coords of overlap position match internal coords
210 void
212  vector1< vector1< Vector > > const & coords,
213  vector1< vector1< Real > > const & torsions,
214  int const cutpoint,
215  int const direction,
216  Real const bond_angle1,
217  Real const ASSERT_ONLY(bond_length),
218  Real const bond_angle2,
219  Matrix const & M_in
220 )
221 {
222  using numeric::conversions::radians;
223  using kinematics::Stub;
224 
225  Size const nbb( coords[cutpoint].size() );
226  assert( nbb >= 3 );
227 
228  // pack the coords, torsions, and angles
229  vector1< Vector > atoms( 6 );
230  vector1< Real > dihedrals( 3 );
231  vector1< Real > angles( 3 );
232 
233  if ( direction == 1 ) {
234  for ( int i=1; i<= 3; ++i ) atoms[i ] = coords[ cutpoint ][ nbb-3+i ];
235  for ( int i=1; i<= 3; ++i ) atoms[i+3] = coords[ cutpoint+1 ][ i ];
236  dihedrals[1] = radians( torsions[cutpoint ][ nbb-1 ] );
237  dihedrals[2] = radians( torsions[cutpoint ][ nbb ] );
238  dihedrals[3] = radians( torsions[cutpoint+1][ 1 ] );
239  angles[1] = bond_angle1; // already in radians
240  angles[2] = bond_angle2;
241  } else {
242  for ( int i=1; i<= 3; ++i ) atoms[7-i ] = coords[ cutpoint ][ nbb-3+i ];
243  for ( int i=1; i<= 3; ++i ) atoms[7-i-3] = coords[ cutpoint+1 ][ i ];
244  dihedrals[3] = radians( torsions[cutpoint ][ nbb-1 ] );
245  dihedrals[2] = radians( torsions[cutpoint ][ nbb ] );
246  dihedrals[1] = radians( torsions[cutpoint+1][ 1 ] );
247  angles[2] = bond_angle1; // already in radians
248  angles[1] = bond_angle2;
249  }
250 
251  Matrix M( M_in );
252 
253  if ( direction == -1 ) {
254  for ( int i=1; i<= 3; ++i ) M.col( i, M_in.col(4-i) );
255  }
256 
257  {
258  using basic::subtract_radian_angles;
259  ASSERT_ONLY(Real const dihedral1
260  ( dihedral_radians( atoms[1], atoms[2], atoms[3], M.col(1) ) );)
261  ASSERT_ONLY(Real const dihedral2
262  ( dihedral_radians( atoms[2], atoms[3], M.col(1), M.col(2) ) );)
263  ASSERT_ONLY(Real const dihedral3
264  ( dihedral_radians( atoms[3], M.col(1), M.col(2), M.col(3) ) );)
265 
266  ASSERT_ONLY(Real const angle1( std::acos( dot( ( atoms[3] - atoms[2] ).normalized(),
267  ( M.col(1) - atoms[3] ).normalized() ) ) );)
268  ASSERT_ONLY(Real const angle2( std::acos( dot( ( M.col(2) - M.col(1) ).normalized(),
269  ( M.col(1) - atoms[3] ).normalized() ) ) );)
270  ASSERT_ONLY(Real const length( atoms[3].distance( M.col(1) ) );)
271 
272  assert( std::abs( subtract_radian_angles( dihedral1, dihedrals[1] ) ) < 1e-3 );
273  assert( std::abs( subtract_radian_angles( dihedral2, dihedrals[2] ) ) < 1e-3 );
274  assert( std::abs( subtract_radian_angles( dihedral3, dihedrals[3] ) ) < 1e-3 );
275  assert( std::abs( subtract_radian_angles( angle1, angles[1] ) ) < 1e-3 );
276  assert( std::abs( subtract_radian_angles( angle2, angles[2] ) ) < 1e-3 );
277  assert( std::abs( length - bond_length ) < 1e-3 );
278  }
279 
280 }
281 
282 
283 ///////////////////////////////////////////////////////////////////////////
284 void
285 index_pair_in_range( int & pos, int & atom, int const nbb ) {
286  while ( atom > nbb ) {
287  atom -= nbb;
288  pos += 1;
289  }
290  while ( atom < 1 ) {
291  atom += nbb;
292  pos -= 1;
293  }
294 }
295 
296 //////////////////////////////////////////////////////////////////////////
297 void
299  vector1< vector1< Vector > > const & coords,
300  int const seqpos,
301  int const torsion,
302  Vector & axis_atom, // output
303  Vector & axis_vector // output
304 )
305 {
306  int const nbb( coords[seqpos].size() );
307  int pos1( seqpos ), pos2( seqpos ),
308  atom1( torsion ), atom2( torsion+1 );
309  index_pair_in_range( pos2, atom2, nbb ); // in case torsion == nbb
310 
311  axis_atom = coords[pos2][atom2];
312  axis_vector = ( axis_atom - coords[pos1][atom1] ).normalized();
313 }
314 
315 
316 //------------------------------------------------------------------------------
317 //------------------------------------------------------------------------------
318 // this routine is used by ccd loop closure
319 
320 void
322  Real const alpha, // degrees
323  int const pos,
324  int const torsion,
325  int const dir,
326  int const cutpoint,
327  vector1< vector1< Vector > > & coords,
328  Matrix & M
329 )
330 {
331  using numeric::conversions::radians;
332  Size const nbb( coords[pos].size() );
333  int const fold_end( ( dir == 1 ) ? cutpoint : cutpoint + 1 );
334 
335  assert( ( fold_end - pos ) * dir >= 0 );
336 
337  // get the rotation matrix, offset
338  Vector axis_atom, axis_vector;
339  get_torsion_axis( coords, pos, torsion, axis_atom, axis_vector );
340 
341  Matrix const R( numeric::rotation_matrix_degrees( axis_vector, Real( dir * alpha) ) );
342 
343  Vector const v( axis_atom - R * axis_atom );
344  // get the rotation matrix about this axis_vector
345  // A is an atom on the torsion axis (axis_atom)
346  //
347  // transformation is x --> R * ( x - A ) + A = R * x - R*A + A = R * x + v where v = ( A - R * A )
348  //
349 
350  int fold_begin( pos );
351  int fold_begin_atom( ( dir == 1 ) ? torsion + 2 : torsion - 1 );
352  index_pair_in_range( fold_begin, fold_begin_atom, nbb );
353 
354  //
355  for ( int i = fold_begin; ( fold_end - i ) * dir >= 0; i += dir ) {
356  int j_begin( ( i == fold_begin ) ? fold_begin_atom : ( dir == 1 ? 1 : nbb ) );
357 
358  for ( Size j = j_begin; j >= 1 && j <= nbb; j += dir ) {
359  coords[i][j] = R * coords[i][j] + v;
360  }
361  }
362 
363  // move the overlap pos
364  for ( int i=1; i<= 3; ++i ) {
365  M.col(i, R*M.col(i) + v);
366  }
367 }
368 
369 /////////////////////////////////////////////////////////////////////////////
370 void
372  Matrix const & F,
373  Matrix const & M,
374  vector1< vector1< Vector > > const & coords,
375  int const pos,
376  int const torsion,
377  int const direction,
378  Real & angle,
379  Real & dev
380 )
381 {
382  using numeric::conversions::radians;
383  using numeric::conversions::degrees;
384 
385 
386 // !!!!!!!!!! REAL PRECISION !!!!!!!!!!!!!!!!!!!
387 // Reald letters are scalars: aa,bb,cc,dd
388  //Real r_length, f_length, alpha;
389 
390  int const n2c = { 1 };
391  int const c2n = { -1 };
392 
393  bool const local_debug = { false };//{ true };
394 
395  Vector A, axis_vector;
396  //Vector A, axis_vector, O, r, r_hat, s_hat, f_vector;
397  get_torsion_axis( coords, pos, torsion, A, axis_vector );
398 
399 // accumulate the components of the ccd equation
400  Real aa = 0.0;
401  Real bb = 0.0;
402  Real cc = 0.0;
403 
404  for ( int i = 1; i <= 3; ++i ) {
405  // project M onto the axis ==> O
406 
407  //AM = M.col(i) - A;
408  //dd = dot( AM, axis_vector );
409  //v = dd * axis_vector;
410  Vector const O( A + dot( M.col(i) - A, axis_vector ) * axis_vector );
411 
412  // calculate r
413  Vector const r = M.col(i) - O;
414  Real const r_length = r.length();
415  // calculate r_hat
416  Vector const r_hat = r / r_length;
417 
418  // calculate s_hat; orientation choice comes here!!
419  Vector const s_hat = cross( axis_vector, r_hat );
420 
421  // calculate f_vector
422  Vector const f_vector = F.col(i) - O;
423  Real const f_length = f_vector.length();
424 
425  aa += r_length * r_length + f_length * f_length;
426 
427  bb += 2 * r_length * dot( f_vector, r_hat );
428 
429  cc += 2 * r_length * dot( f_vector, s_hat );
430 
431  if ( local_debug ) {
432  // some checks on orthonormality
433  assert( std::abs( dot( axis_vector, r_hat ) ) < 1e-3 );
434  assert( std::abs( dot( axis_vector, s_hat ) ) < 1e-3 );
435  assert( std::abs( dot( s_hat, r_hat ) ) < 1e-3 );
436  assert( axis_vector.is_unit( 1e-3 ) );
437  assert( s_hat.is_unit( 1e-3 ) );
438  assert( r_hat.is_unit( 1e-3 ) );
439 
440  assert( std::abs( dot( M.col(i), axis_vector ) - dot( O, axis_vector ) ) < 1e-3 );
441  assert( std::abs( dot( r, axis_vector ) ) < 1e-3 );
442 
443  }
444  }
445 
446  Real const alpha = std::atan2( cc, bb );
447 
448  dev = aa - bb * std::cos( alpha ) - cc * std::sin( alpha );
449 
450  if ( local_debug ) {
451  Real const one_degree = radians( 1.0 ); // one degree expressed in radians
452  if ( ( dev > aa - bb * std::cos( alpha - one_degree ) - cc * std::sin( alpha - one_degree ) ) ||
453  ( dev > aa - bb * std::cos( alpha + one_degree ) - cc * std::sin( alpha + one_degree ) ) ) {
454  utility_exit_with_message( "ccd problemo!" );
455  }
456  }
457 
458  if ( direction == n2c ) {
459  angle = degrees(alpha);
460  } else if ( direction == c2n ) {
461  angle = -degrees(alpha);
462  } else {
463  utility_exit_with_message( "ccd_angle: unrecognized direction: "+string_of(direction) );
464  }
465 
466 }
467 
468 ///////////////////////////////////////////////////////////////////////////////////
469 void
471  int const loop_begin,
472  int const loop_end,
473  int const cutpoint,
474  vector1< vector1< Real > > const & torsions,
475  vector1< vector1< Vector > > const & coords
476  )
477 {
478  int const nbb( torsions[ loop_begin ].size() );
479  for ( int i=loop_begin; i<= loop_end; ++i ) {
480  for ( int torsion=1; torsion<= nbb; ++torsion ) {
482  for ( int k=1; k<= 4; ++k ) {
483  int seqpos(i), atomno(torsion+k-2);
484  index_pair_in_range( seqpos, atomno, nbb );
485  xyz.push_back( coords[seqpos][atomno] );
486  }
487  Real const xyz_dihedral( numeric::dihedral_degrees( xyz[1], xyz[2], xyz[3], xyz[4] ) );
488  if ( ( i == cutpoint && ( torsion == nbb -1 || torsion == nbb ) ) ||
489  ( i == cutpoint+1 && ( torsion == 1 ) ) ) continue;
490  assert( std::abs( basic::subtract_degree_angles( xyz_dihedral, torsions[i][torsion] ) ) < 1e-3 );
491  tccd.Debug << "torsion-check: " << i << ' ' << torsion << ' ' << torsions[i][torsion] << ' ' << xyz_dihedral << std::endl;
492  }
493 
494  }
495 }
496 
497 
498 //------------------------------------------------------------------------------
499 //
500 /// @details tolerance in Angstroms, forward and backward splice RMS over N,CA,C must
501 /// be less than tolerance for an early return. otherwise goes through the
502 /// loop ii_cycles, each time both forward and backward
503 /// returns the number of cycles actually taken
504 
505 int
507  pose::Pose & pose,
508  kinematics::MoveMap const & mm,
509  int const loop_begin,
510  int const loop_end,
511  int const cutpoint,
512  int const ii_cycles,
513  Real const tolerance,
514  bool const rama_check,
515  Real const max_rama_score_increase,
516  Real const max_total_delta_helix,
517  Real const max_total_delta_strand,
518  Real const max_total_delta_loop,
519  Real & forward_deviation, // output
520  Real & backward_deviation, // output
521  Real & torsion_delta,
522  Real & rama_delta
523 )
524 {
525  PROF_START( basic::CCD_CLOSE );
526  using namespace id;
527 
528  /////////
529  // params
530  /////////
531  bool const local_debug = { false }; //true };
532  bool const local_verbose = { false }; //true };
533  int const n2c = { 1 }; // must be 1 and -1 (below) for proper incrementing in loops
534  int const c2n = { -1 };
535  // per-cycle max move params
536  //Real const max_angle_delta_helix = { 100.0 };
537  //Real const max_angle_delta_strand = { 100.0 };
538  //Real const max_angle_delta_loop = { 100.0 };
539  Real const max_angle_delta_helix = { 1.0 };
540  Real const max_angle_delta_strand = { 5.0 };
541  Real const max_angle_delta_loop = { 10.0 };
542  // for rama-checking with Boltzman criterion (should be higher?)
543  Real const ccd_temperature = { 0.25 };
544  Size const nres( pose.total_residue() );
545 
546  Real const bond_angle1( pose.residue( cutpoint ).upper_connect().icoor().theta() );// CA-C=N bond angle
547  Real const bond_angle2( pose.residue( cutpoint+1 ).lower_connect().icoor().theta() ); // C=N-CA bond angle
548  Real const bond_length( pose.residue( cutpoint+1 ).lower_connect().icoor().d() ); // C=N distance
549 
550  // pack mainchain coordinates, torsions into local arrays
551  Size const nbb( pose.residue( loop_begin ).mainchain_atoms().size() );
553  vector1< vector1< Real > > torsions;
554 
555  load_coords_and_torsions( pose, coords, torsions );
556  assert( coords[loop_begin].size() == nbb && torsions[loop_begin].size() == nbb );
557 
558  // save the starting torsions for comparison, starting rama score if rama_check == true
559  vector1< vector1< Real > > start_torsions( torsions );
560  vector1< Real > start_rama_score( nres, 0.0 );
562  if ( rama_check ) {
563  rama = &(scoring::ScoringManager::get_instance()->get_Ramachandran());
564  for ( int i=loop_begin; i<= loop_end; ++i ) {
565  start_rama_score[i] = rama->eval_rama_score_residue( pose.aa(i), torsions[i][1], torsions[i][2] );
566  }
567  }
568 
569  // reuse this for saving coords in case of move-rejection to prevent unnecessary refolds
570  vector1< vector1< Vector > > save_coords( coords );
571 
572  // for reporting how many cycles we actually took
573  int actual_cycles = ii_cycles;
574 
575 
576  ////////////////////////////
577  // now start cycling through
578  ////////////////////////////
579  for ( int ii = 1; ii <= ii_cycles; ++ii ) {
580 
581  if ( ii%10 == 0 ) {
582  // avoid coordinate errors due to roundoff
583  copy_torsions_to_pose( pose, loop_begin, loop_end, torsions );
584  load_coords_and_torsions( pose, coords, torsions );
585  }
586 
587  // first forward, then backward
588  for ( int repeat = 1; repeat <= 2; ++repeat ) {
589  int direction,start_pos,stop_pos,increment;
590  if ( repeat == 1 ) {
591  direction = n2c;
592  start_pos = loop_begin;
593  stop_pos = std::min(loop_end,cutpoint);
594  increment = 1;
595  } else {
596  direction = c2n;
597  start_pos = loop_end;
598  stop_pos = std::max(loop_begin,cutpoint+1);
599  increment = -1;
600  }
601 
602  // get fixed and moving positions for this direction:
603  Matrix F,M;
604  // F is the fixed landing position,
605  // for n->c direction, that would be the first three backbone atom of the residue after cutpoint
606  // for c->n direction, that would be the last three backbone atom of the residue of cutpoint
607  for ( int i = 1; i <= 3; ++i ) {
608  if ( direction == n2c ) {
609  F.col( i, coords[ cutpoint + 1 ][ i ] );
610  } else {
611  F.col( i, coords[ cutpoint ][ nbb - 3 + i ] );
612  }
613  }
614  // M is the actual landing postion
615  get_overlap_pos( coords, torsions, cutpoint, direction, bond_angle1, bond_length, bond_angle2, M );
616 
617  if ( local_debug )
618  check_overlap_pos( coords, torsions, cutpoint, direction, bond_angle1, bond_length, bond_angle2, M );
619 
620 
621 
622  // as we change torsion angles through the loop the moving
623  // atoms in M will be transformed along with the downstream segment
624  // of the loop, by the routine refold_loop_torsions(...)
625 
626  for ( int pos = start_pos; pos*increment <= stop_pos*increment;
627  pos += increment ) {
628 
629  if ( !mm.get( TorsionID( pos, BB, phi_torsion ) ) && !mm.get( TorsionID( pos, BB, psi_torsion ) ) ) continue;
630 
631 
632  Real max_angle_delta, max_total_delta;
633  if ( pose.secstruct(pos) == 'H' ) {
634  max_angle_delta = max_angle_delta_helix;
635  max_total_delta = max_total_delta_helix;
636  } else if ( pose.secstruct(pos) == 'E' ) {
637  max_angle_delta = max_angle_delta_strand;
638  max_total_delta = max_total_delta_strand;
639  } else {
640  max_angle_delta = max_angle_delta_loop;
641  max_total_delta = max_total_delta_loop;
642  }
643 
644  if ( max_total_delta <= 0.01 ) {
645  tccd.Debug << "cant move this residue " << pos << std::endl;
646  continue;
647  }
648 
649  // save values for rama score eval, and in case we rama-reject
650  vector1< Real > const save_torsions( torsions[ pos ] );
651 
652  // save in case we rama-reject!
653  save_coords.resize( nres );
654  for ( int i=loop_begin; i<= loop_end; ++i ) {
655  save_coords[i].resize( nbb );
656  for ( Size j=1; j<= nbb; ++j ) {
657  save_coords[i][j] = coords[i][j];
658  }
659  }
660 
661  for ( Size torsion = 1; torsion <= nbb; ++torsion ) {
662 
663  if ( !mm.get( TorsionID( pos, BB, torsion ) ) ) continue;
664 
665  if ( pos == cutpoint && torsion == nbb ) continue;
666 
667  if ( local_debug )
668  check_overlap_pos( coords, torsions, cutpoint, direction, bond_angle1, bond_length, bond_angle2, M );
669 
670  Real alpha,dev;
671  calculate_ccd_angle( F, M, coords, pos, torsion, direction, alpha, dev );
672  Real const alpha_orig( alpha );
673 
674  // impose per-move deltas
675  if ( alpha > max_angle_delta ) alpha = max_angle_delta;
676  if ( alpha < -max_angle_delta ) alpha = -max_angle_delta;
677 
678  // check for total movement during closure run:
679  Real const total_delta
680  ( basic::subtract_degree_angles( start_torsions[pos][torsion], torsions[pos][torsion] + alpha ) );
681 
682  if ( total_delta > max_total_delta ) {
683  // this logic is a little tricky: if adding alpha to the previous
684  // delta pushes us past 180 from start, then it wont work, so check for
685  // that (note that if max_total_delta > 180 we wont even get here ):
686  assert( alpha + max_total_delta < 180 );
687  if ( alpha > 0 ) {
688  alpha -= ( total_delta - max_total_delta + 0.01 );
689  } else {
690  alpha += ( total_delta - max_total_delta + 0.01 );
691  }
692  }
693 
694  // update the coordinates to reflect the torsion angle change
695  refold_loop_torsion( alpha, pos, torsion, direction, cutpoint, coords, M );
696 
697  // update torsions
698  torsions[ pos ][ torsion ] = basic::periodic_range( torsions[pos][torsion] + alpha, 360.0 );
699 
700  if ( local_debug )
701  check_overlap_pos( coords, torsions, cutpoint, direction, bond_angle1, bond_length, bond_angle2, M );
702 
703  // debugging: ///////////////////////
704  if ( local_debug ) {
705  // this assumes that the tree is not rooted at cutpoint or
706  // cutpoint+1
707  check_torsions( loop_begin, loop_end, cutpoint, torsions, coords );
708 
709  copy_torsions_to_pose( pose, loop_begin, loop_end, torsions );
710 
711  vector1< vector1< Vector > > tmp_coords;
712  vector1< vector1< Real > > tmp_torsions;
713 
714  load_coords_and_torsions( pose, tmp_coords, tmp_torsions );
715 
716  // calculate coordinate dev
717  Real coord_dev = 0.0;
718  for ( int i = loop_begin; i <= loop_end; ++i ) {
719  for ( Size j = 1; j <= nbb; ++j ) {
720  coord_dev += coords[i][j].distance( tmp_coords[i][j] );
721  }
722  }
723 
724  if ( coord_dev > 0.1 ) {
725  utility_exit_with_message( "fold_loop_torsion dev:: " + string_of( coord_dev ) );
726  }
727 
728  Real tmp_dev = 0.0;
729  for ( int i = 1; i <= 3; ++i ) {
730  tmp_dev += M.col(i).distance_squared( F.col(i) );
731  }
732 
733  if ( alpha == alpha_orig && std::abs( dev - tmp_dev) > 0.1 ) {
734  tccd.Warning << "WARNING:: ccd-dev error: " << dev << ' ' <<
735  tmp_dev << ' ' << std::abs( dev-tmp_dev) << std::endl;
736  }
737 
738  if ( local_verbose )
739  tccd.Warning << "pos: " << I( 3, pos ) << I( 3, torsion) <<
740  " alpha-orig: " << fmt::F( 7, 3, alpha_orig ) <<
741  " alpha: " << fmt::F( 7, 3, alpha ) <<
742  " dev1: " << fmt::F( 13, 9, dev ) <<
743  " dev2: " << fmt::F( 13, 9, tmp_dev ) << std::endl;
744 
745  } // if ( local_debug ) ///////////////////////////////////
746  } // torsion = 1,nbb
747 
748 
749  if ( rama_check ) {
750  assert( nbb == 3 );
751  //////////////////////////////////////
752  // evaluate the rama score difference:
753  Real const old_rama_score( rama->eval_rama_score_residue( pose.aa(pos), torsions[pos][1], torsions[pos][2]));
754  Real const new_rama_score( rama->eval_rama_score_residue( pose.aa(pos), save_torsions[1], save_torsions[2]));
755 
756  if (local_verbose)
757  tccd.Warning << "rama_check: " << pos << ' ' << old_rama_score << ' ' << new_rama_score << std::endl;
758 
759  if ( new_rama_score > old_rama_score ) {
760  Real const boltz_factor ( (old_rama_score-new_rama_score)/ccd_temperature );
761  Real const negative_forty( -40.0f );
762  Real const probability ( std::exp(std::max(negative_forty,boltz_factor) ) );
763  if ( new_rama_score - start_rama_score[ pos ] > max_rama_score_increase ||
764  numeric::random::uniform() >= probability ) {
765  // undo the change:
766  torsions[pos] = save_torsions;
767 
768  // recover saved coords
769  for ( int i=loop_begin; i<= loop_end; ++i ) {
770  for ( Size j=1; j<= nbb; ++j ) {
771  coords[i][j] = save_coords[i][j];
772  }
773  }
774 
775  get_overlap_pos( coords, torsions, cutpoint, direction, bond_angle1, bond_length, bond_angle2, M );
776 
777  } // rama reject
778  } // rama-score got worse
779  } // if ( rama_check )
780  } // pos = start_pos,stop_pos
781  } // repeat = 1,2 1=n2c; 2=c2n
782 
783  if ( ii%5 == 0 || ii == ii_cycles ) {
784  // check overlap deviations to see if loop is closed
785  // every 5 cycles or on the last one.
786  //
787  // forward_deviation:
788  Matrix F,M;
789  int direction = n2c;
790  for ( int i = 1; i <= 3; ++i ) {
791  F.col( i, coords[ cutpoint + 1 ][ i ] );
792  }
793 
794  get_overlap_pos( coords, torsions, cutpoint, direction, bond_angle1, bond_length, bond_angle2, M );
795 
796  forward_deviation = 0.0;
797  for ( int i = 1; i <= 3; ++i ) {
798  for ( int j = 1; j <= 3; ++j ) {
799  forward_deviation += numeric::square( M(j,i) - F(j,i) );
800  }
801  }
802  forward_deviation = sqrt( forward_deviation / 3 );
803 
804  // backward_deviation:
805  direction = c2n;
806  for ( int i = 1; i <= 3; ++i ) {
807  F.col( i, coords[ cutpoint ][ nbb - 3 + i ] );
808  }
809  get_overlap_pos( coords, torsions, cutpoint, direction, bond_angle1, bond_length, bond_angle2, M );
810 
811  backward_deviation = 0.0;
812  for ( int i = 1; i <= 3; ++i ) {
813  for ( int j = 1; j <= 3; ++j ) {
814  backward_deviation += numeric::square( M(j,i) - F(j,i) );
815  }
816  }
817  backward_deviation = sqrt( backward_deviation / 3 );
818 
819  if (local_verbose) tccd.Debug << "cycle/forward_dev/backward_dev: " << ii << " " << forward_deviation << " "
820  << backward_deviation << std::endl;
821 
822  if ( forward_deviation < tolerance && backward_deviation < tolerance ) {
823  if ( local_verbose )
824  tccd.Debug << "closed early: ii= " << ii << ' ' << tolerance << std::endl;
825  actual_cycles = ii;
826  break;
827  }
828  } // check deviations
829  } // ii=1,ii_cycles
830 
831  // DONE!
832  copy_torsions_to_pose( pose, loop_begin, loop_end, torsions );
833 
834  // calculate torsion dev, rama delta
835  torsion_delta = 0.0;
836  rama_delta = 0.0;
837 
838  for ( int i=loop_begin; i<= loop_end; ++i ) {
839  for ( Size j=1; j<= nbb; ++j ) {
840  torsion_delta += std::abs( basic::subtract_degree_angles( start_torsions[i][j], torsions[i][j] ) );
841  }
842  if ( rama_check ) {
843  Real const final_rama_score( rama->eval_rama_score_residue( pose.aa(i), torsions[i][1], torsions[i][2] ) );
844  rama_delta += ( final_rama_score - start_rama_score[i] );
845  }
846  }
847  torsion_delta /= ( loop_end - loop_begin + 1);
848  rama_delta /= ( loop_end - loop_begin + 1);
849 
850  PROF_STOP( basic::CCD_CLOSE );
851  return actual_cycles;
852 }
853 
854 /////////////////////////////////////////////////////////
855 void
857  int const total_moves,
858  core::pose::Pose & pose,
859  core::kinematics::MoveMap const & mm,
860  int const loop_begin,
861  int const loop_end,
862  int const cutpoint
863 )
864 {
865 
866 
867  using namespace id;
868 
869  /////////
870  // params
871  /////////
872  bool const local_debug = { false }; //true };
873  bool const local_verbose = { false }; //true };
874  bool const rama_check = { true };
875 
876  int const n2c = { 1 }; // must be 1 and -1 (below) for proper incrementing in loops
877  int const c2n = { -1 };
878 
879  // per-cycle max move params
880  //Real const max_angle_delta_helix = { 100.0 };
881  //Real const max_angle_delta_strand = { 100.0 };
882  //Real const max_angle_delta_loop = { 100.0 };
883  Real const max_angle_delta_helix = { 1.0 };
884  Real const max_angle_delta_strand = { 5.0 };
885  Real const max_angle_delta_loop = { 10.0 };
886  // for rama-checking with Boltzman criterion (should be higher?)
887  Real const ccd_temperature = { 0.25 };
888  Size const nres( pose.total_residue() );
889 
890  Real const bond_angle1( pose.residue( cutpoint ).upper_connect().icoor().theta() );// CA-C=N bond angle
891  Real const bond_angle2( pose.residue( cutpoint+1 ).lower_connect().icoor().theta() ); // C=N-CA bond angle
892  Real const bond_length( pose.residue( cutpoint+1 ).lower_connect().icoor().d() ); // C=N distance
893 
894  // pack mainchain coordinates, torsions into local arrays
895  Size const nbb( pose.residue( loop_begin ).mainchain_atoms().size() );
897  vector1< vector1< Real > > torsions;
898 
899  load_coords_and_torsions( pose, coords, torsions );
900  assert( coords[loop_begin].size() == nbb && torsions[loop_begin].size() == nbb );
901 
902  // save the starting torsions for comparison,
903  vector1< vector1< Real > > start_torsions( torsions );
904 
905  // reuse this for saving coords in case of move-rejection to prevent unnecessary refolds
906  vector1< vector1< Vector > > save_coords( coords );
907 
908  Size total_insert( loop_end - loop_begin + 1 );
909  Real const H_weight ( 0.5 );
910  Real const E_weight ( 1.0 );
911  Real const L_weight ( 8.5 );
912  Real total_weight(0.0);
913  vector1< Real > weight_map( total_insert, 0.0 );
914 
915  for ( Size i = 1; i <= total_insert; ++i ) {
916 
917  char ss( pose.secstruct( loop_begin - 1 + i ) );
918 
919  if ( ss == 'H' ) {
920  total_weight += H_weight;
921  } else if ( ss == 'E' ) {
922  total_weight += E_weight;
923  } else {
924  assert( ss == 'L' );
925  total_weight += L_weight;
926  }
927  weight_map[ i ] = total_weight;
928 
929  }
930 
931 
932  Size nmoves( 0 );
933  Size ntries( 0 );
934 
935  while ( nmoves < Size ( total_moves ) ) {
936  ++ntries;
937  if ( ntries > Size ( 5*total_moves ) ) {
938  break;
939  }
940 
941  Real const weight( numeric::random::uniform()*total_weight );
942  Size ipos;
943  for( ipos = 1; ipos <= total_insert; ++ipos ) {
944  if( weight < weight_map[ ipos ] ) break;
945  }
946  if( ipos > total_insert ) {
947  tccd.Debug << "ccd_moves: bad_weight " << weight << ' ' <<
948  total_weight << ' ' << weight_map[ total_insert ] << std::endl;
949  ipos = total_insert;
950  }
951 
952  Size const pos = ipos + loop_begin - 1;
953  int const direction( pos <= Size( cutpoint ) ? n2c : c2n );
954 
955 
956  // get fixed and moving positions for this direction:
957  Matrix F,M;
958  // F is the fixed landing position,
959  // for n->c direction, that would be the first three backbone atom of the residue after cutpoint
960  // for c->n direction, that would be the last three backbone atom of the residue of cutpoint
961  for ( int i = 1; i <= 3; ++i ) {
962  if ( direction == n2c ) {
963  F.col( i, coords[ cutpoint + 1 ][ i ] );
964  } else {
965  F.col( i, coords[ cutpoint ][ nbb - 3 + i ] );
966  }
967  }
968  // M is the actual landing postion
969  get_overlap_pos( coords, torsions, cutpoint, direction, bond_angle1, bond_length, bond_angle2, M );
970 
971  if ( local_debug )
972  check_overlap_pos( coords, torsions, cutpoint, direction, bond_angle1, bond_length, bond_angle2, M );
973 
974 
975  Real max_angle_delta;
976  if ( pose.secstruct(pos) == 'H' ) {
977  max_angle_delta = max_angle_delta_helix;
978  } else if ( pose.secstruct(pos) == 'E' ) {
979  max_angle_delta = max_angle_delta_strand;
980  } else {
981  max_angle_delta = max_angle_delta_loop;
982  }
983 
984  // save values for rama score eval, and in case we rama-reject
985  vector1< Real > const save_torsions( torsions[ pos ] );
986 
987  // save in case we rama-reject!
988  save_coords.resize( nres );
989  for ( int i=loop_begin; i<= loop_end; ++i ) {
990  save_coords[i].resize( nbb );
991  for ( Size j=1; j<= nbb; ++j ) {
992  save_coords[i][j] = coords[i][j];
993  }
994  }
995 
996  for ( Size torsion = 1; torsion <= nbb; ++torsion ) {
997 
998  if ( !mm.get( TorsionID( pos, BB, torsion ) ) ) continue;
999 
1000  if ( pos == Size( cutpoint ) && torsion == nbb ) continue;
1001 
1002  if ( local_debug )
1003  check_overlap_pos( coords, torsions, cutpoint, direction, bond_angle1, bond_length, bond_angle2, M );
1004 
1005  Real alpha, dev;
1006  calculate_ccd_angle( F, M, coords, pos, torsion, direction, alpha, dev );
1007  //v Real const alpha_orig( alpha );
1008 
1009  // impose per-move deltas
1010  if ( alpha > max_angle_delta ) alpha = max_angle_delta;
1011  if ( alpha < -max_angle_delta ) alpha = -max_angle_delta;
1012 
1013  // update the coordinates to reflect the torsion angle change
1014  refold_loop_torsion( alpha, pos, torsion, direction, cutpoint, coords, M );
1015 
1016  // update torsions
1017  torsions[ pos ][ torsion ] = basic::periodic_range( torsions[pos][torsion] + alpha, 360.0 );
1018 
1019  if ( local_debug )
1020  check_overlap_pos( coords, torsions, cutpoint, direction, bond_angle1, bond_length, bond_angle2, M );
1021 
1022 
1023  } // loop over nbb
1024 
1025 
1027  if ( rama_check ) {
1028  rama = &(scoring::ScoringManager::get_instance()->get_Ramachandran());
1029  assert( nbb == 3 );
1030  //////////////////////////////////////
1031  // evaluate the rama score difference:
1032  Real const old_rama_score( rama->eval_rama_score_residue( pose.aa(pos), torsions[pos][1], torsions[pos][2]));
1033  Real const new_rama_score( rama->eval_rama_score_residue( pose.aa(pos), save_torsions[1], save_torsions[2]));
1034 
1035  if (local_verbose)
1036  tccd.Debug << "rama_check: " << pos << ' ' << old_rama_score << ' ' << new_rama_score << std::endl;
1037 
1038  if ( new_rama_score > old_rama_score ) {
1039  Real const boltz_factor ( (old_rama_score-new_rama_score)/ccd_temperature );
1040  Real const negative_forty( -40.0f );
1041  Real const probability ( std::exp(std::max(negative_forty,boltz_factor) ) );
1042  if ( numeric::random::uniform() >= probability ) {
1043  // undo the change:
1044  torsions[pos] = save_torsions;
1045 
1046  // recover saved coords
1047  for ( int i=loop_begin; i<= loop_end; ++i ) {
1048  for ( Size j=1; j<= nbb; ++j ) {
1049  coords[i][j] = save_coords[i][j];
1050  }
1051  }
1052 
1053  get_overlap_pos( coords, torsions, cutpoint, direction, bond_angle1, bond_length, bond_angle2, M );
1054 
1055  } // rama reject
1056  } // rama-score got worse
1057  } // if ( rama_check )
1058 
1059 
1060  ++nmoves;
1061  } //end while( nmoves < total_moves)
1062  // DONE!
1063  copy_torsions_to_pose( pose, loop_begin, loop_end, torsions );
1064 
1065 }
1066 
1067 } // namespace ccd
1068 } // namespace loop_closure
1069 } // namespace loops
1070 } // namespace protocols