Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
CoarseRNA_LoopCloser.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 CoarseRNA_LoopCloser
11 /// @brief protocols that are specific to CoarseRNA_LoopCloser
12 /// @detailed
13 /// @author Rhiju Das
14 
15 // Unit headers
17 
18 // Package headers
20 //
21 #include <core/types.hh>
24 // AUTO-REMOVED #include <core/conformation/util.hh>
25 #include <core/id/AtomID.hh>
26 #include <core/id/NamedAtomID.hh>
27 #include <core/id/TorsionID.hh>
28 #include <core/id/DOF_ID.hh>
32 #include <core/pose/Pose.hh>
33 #include <core/pose/util.hh>
34 #include <basic/Tracer.hh>
36 #include <numeric/random/random.hh>
37 #include <numeric/angle.functions.hh>
38 #include <numeric/xyz.functions.hh>
39 #include <numeric/xyzVector.hh>
40 #include <numeric/conversions.hh>
41 #include <numeric/kinematic_closure/bridgeObjects.hh>
42 // AUTO-REMOVED #include <protocols/moves/kinematic_closure/kinematic_closure_helpers.hh>
43 #include <utility/exit.hh>
44 #include <utility/vector1.hh>
45 #include <ObjexxFCL/FArray1D.hh>
46 #include <ObjexxFCL/string.functions.hh>
47 #include <ObjexxFCL/format.hh>
48 
49 using namespace core;
50 
51 static basic::Tracer TR( "protocols.coarse_rna.coarse_rna_loop_closer" ) ;
52 static numeric::random::RandomGenerator RG(2289440); // <- Magic number, do not change it!
53 using ObjexxFCL::fmt::I;
54 using ObjexxFCL::fmt::F;
55 using core::id::AtomID;
57 using core::id::DOF_ID;
59 using numeric::conversions::radians;
60 using numeric::conversions::degrees;
61 using numeric::angle_radians;
62 using numeric::principal_angle;
63 using numeric::dihedral_radians;
64 
65 namespace protocols {
66 namespace coarse_rna {
67 
68 CoarseRNA_LoopCloser::CoarseRNA_LoopCloser():
69  a_little_verbose_( false ),
70  verbose_( false ),
71  cutpos_( 0 ),
72  nsol_( 0 ),
73  which_scratch_res_is_cut_( 0 ),
74  choose_least_perturb_solution_( true ),
75  choose_best_solution_( false ),
76  choose_random_solution_( false ),
77  save_all_solutions_( false )
78 {
79  Mover::type("CoarseRNA_LoopCloser");
80 }
81 
82 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
83 /// @details Apply the RNA Loop Closer -- currently specialized for coarse-grained RNA representation.
84 ///
85 void
87  std::cout << "Does nothing for now -- input the residue that you changed." << std::endl;
88  // Later make this loop over all cutpoints?
89 }
90 
91 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
92 bool
93 CoarseRNA_LoopCloser::apply( core::pose::Pose & pose, Size const & seqpos_moved )
94 {
95 
96  seqpos_moved_ = seqpos_moved;
97  if ( a_little_verbose_ || verbose_ ) TR << "Checking move at " << seqpos_moved << std::endl;
98 
99  // which cutpoint was affected?
100  partition_definition_.dimension( pose.total_residue(), false );
101  pose.fold_tree().partition_by_residue( seqpos_moved, partition_definition_ );
102 
104  // if ( cutpos_list_.size() > 1 ) {
105  // utility_exit_with_message( "Found more than one cutpoint affected by a frag insertion -- should not happen!" );
106  // }
107 
108  return close_at_all_cutpoints( pose );
109 }
110 
111 
112 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
113 bool
115 {
116 
117  seqpos_moved_ = 0;
118  if ( a_little_verbose_ || verbose_ ) TR << "Checking move at jump " << jumpno << std::endl;
119 
120  // which cutpoint was affected?
121  partition_definition_.dimension( pose.total_residue(), false );
123 
125 
126  return close_at_all_cutpoints( pose );
127 }
128 
129 
130 ///////////////////////////////////////////////////////////////////////////////////////////////////////
133  return "CoarseRNA_LoopCloser¯";
134 }
135 
136 
137 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
138 bool
140 
141  if ( cutpos_list_.size() == 0 ) return true; // no change to any cutpoints.
142 
143  bool success( true );
144  for ( Size i = 1; i <= cutpos_list_.size(); i++ ) {
145 
146  cutpos_ = cutpos_list_[ i ];
147 
148  if ( a_little_verbose_ || verbose_ ) TR << "Cutpoint affected: " << cutpos_ << std::endl;
149 
150  bool const success_in_finding_pivots = figure_out_pivots( pose );
151  if ( !success_in_finding_pivots ) {
152  success = false;
153  continue;
154  }
155 
156  close_the_loop( pose );
157  // std::cout << nsol_ << std::endl;
158 
159  if ( nsol_ == 0 ) success = false;
160  // if ( nsol_ > 0 ) exit( 0 );
161  }
162 
163  return success;
164 
165 }
166 
167 
168 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
169 void
171 
172  cutpos_list_.clear();
173 
174  if ( verbose_ ){
175  for ( Size n = 1; n <= pose.total_residue(); n++ ) std::cout << partition_definition_( n );
176  std::cout << std::endl;
177  }
178 
179  cutpos_ = 0;
180  for ( Size n = 1; n < pose.total_residue(); n++ ) {
181  if ( pose.fold_tree().is_cutpoint( n ) &&
185  cutpos_list_.push_back( n );
186  if ( verbose_ ) std::cout << "AFFECTED CUTPOINT: " << n << std::endl;
187  }
188  }
189 
190 
191 }
192 
193 void
195  std::cout << "BACKWARD_RES ";
196  for ( Size n = 1; n <= backward_res_.size(); n++ ) std::cout << ' ' << backward_res_[n];
197  std::cout << std::endl;
198 
199  std::cout << "FORWARD_RES ";
200  for ( Size n = 1; n <= forward_res_.size(); n++ ) std::cout << ' ' << forward_res_[n];
201  std::cout << std::endl << std::endl;
202  }
203 
204 ////////////////////////////////////////////////////////////////////////////////////////
205 bool
207 
209 
211 
212  // Filter out perturb residue -- if that leaves enough dofs!
213  Size const tot_pivot_res = forward_res_.size() + backward_res_.size();
214 
215  if ( tot_pivot_res < 2 ) return false;
216 
217  if ( tot_pivot_res > 2 && seqpos_moved_ > 0 ) {
218  remove_res( forward_res_, seqpos_moved_+1 /* +1 because pivot atom (phosphate) is on cutpos+1*/ );
220  }
221 
223 
225 
226  return true;
227 }
228 
229 ////////////////////////////////////////////////////////////////////////////////////////
230 void
232 
233  utility::vector1< core::Size > new_res_vector;
234 
235  for ( Size n = 1; n <= res_vector.size(); n++ ) {
236  if ( res_vector[ n ] != res ) new_res_vector.push_back( res_vector[ n ] );
237  }
238 
239  res_vector = new_res_vector;
240 }
241 
242 
243 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
244 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
245 // backtrack through atom_tree to figure out which torsions control each end of the cutpoint.
246 // Keep track of controlling phosphates (potential "pivots")
247 void
249  utility::vector1< core::Size > & upstream_res,
250  utility::vector1< bool > & is_upstream_res,
251  pose::Pose const & pose ){
252  while ( current_atom->parent() ){
253 
254  current_atom = ( current_atom->parent() );
255  AtomID const & atom_id( current_atom->id() );
256  if ( pose.residue_type( atom_id.rsd() ).atom_name( atom_id.atomno() ) == " P " ) {
257  upstream_res.push_back( current_atom->id().rsd() );
258  is_upstream_res[ current_atom->id().rsd() ] = true;
259  }
260  }
261 
262 }
263 
264 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
265 void
267 
268  is_backward_res_.clear();
269  is_forward_res_.clear();
270  for ( Size i = 1; i <= pose.total_residue(); i++ ){
271  is_backward_res_.push_back( false );
272  is_forward_res_.push_back( false );
273  }
274 
275  backward_res_.clear();
276  forward_res_.clear();
277 
278  //Backtrack from sugar before chainbreak -- could generalize this to be the atom immediately before chainbreak.
279  core::id::AtomID const ref_atom_id( 2, cutpos_ );
280  core::kinematics::tree::AtomCOP current_atom ( & pose.atom_tree().atom_dont_do_update( ref_atom_id ) );
281  backtrack( current_atom, backward_res_, is_backward_res_, pose );
282 
283  // Backtrack from phosphate after chainbreak -- again, could generalize.
284  AtomID atom_id( named_atom_id_to_atom_id( NamedAtomID( " P ", cutpos_ + 1 ), pose ) );
285  current_atom = & pose.atom_tree().atom_dont_do_update( atom_id );
286  backtrack( current_atom, forward_res_, is_forward_res_, pose );
287 
289 
290  // Trick to filter out just controlling pivots -- any upstream residues
291  // shared in the backtrack paths from either end of the chainbreak
292  // actually will have no effect on the relative positions of the chainbreak ends.
293  // Also, this is our opportunity to filter out atoms which are not allowed to move
294  // (takes advantage of the allow_insert_ object).
297 
299 
300 }
301 
302 /////////////////////////////////////////////////////////////////////////////////////////////////
303 void
305  utility::vector1< bool > const & is_filter_res,
306  pose::Pose const & pose ){
307 
308  utility::vector1< core::Size > new_upstream_res;
309 
310  for ( Size n = 1; n <= upstream_res.size(); n++ ) {
311 
312  Size const i( upstream_res[ n ] );
313  // AtomID atom_id = named_atom_id_to_atom_id( NamedAtomID( " P ", i ), pose ); // Unused variable causes warning.
314 
315  // if ( !is_filter_res[ i ] &&
316  // allow_insert_->get( atom_id ) ) new_upstream_res.push_back( i );
317 
318  if ( !is_filter_res[ i ] &&
319  allow_insert_->get( id::TorsionID( i, id::BB, 1 ), pose.conformation() ) ) new_upstream_res.push_back( i );
320 
321  }
322 
323  upstream_res = new_upstream_res;
324 
325 }
326 
327 /////////////////////////////////////////////////////////////////////////////////////////////////
328 // We need 3 pivots -- one better involves the cutpoint.
329 // For kinematic loop closure, need these three pivots -- and also
330 // the residue 5' of the cutpoint (this may already be one of the pivots).
331 void
333 
334  ////////////////////////////////////////////////////////////////////////////////////////////////////////////
335  ////////////////////////////////////////////////////////////////////////////////////////////////////////////
336  Size total_pivots = forward_res_.size() + backward_res_.size() + 1;
337 
338  if ( total_pivots < 3 ){
339  utility_exit_with_message( "Not enough pivots to close chainbreak!" );
340  }
341 
342  // line up the pivots in order.
343  utility::vector1< Size > pivots_in_order;
344  // first the "backward" residues, those upstream of the cutpoint. Their order needs to be reversed.
345  for ( Size n = backward_res_.size(); n >= 1; n-- ) pivots_in_order.push_back( backward_res_[ n ] );
346  // Cutpoint is one of the pivots.
347  pivots_in_order.push_back( cutpos_ + 1 );
348  // Then the "forward" residues (downstream).
349  for ( Size n = 1; n <= forward_res_.size() ; n++ ) pivots_in_order.push_back( forward_res_[ n ] );
350 
351  // Keep track of which pivots have been selected with an array.
352  utility::vector1< bool > pivots_selected( total_pivots, false );
353 
354  // Need to pick a random subset of these potential pivot points.
355  // well, one is the cutpoint pivot for sure.
356  Size const cutpoint_pivot = backward_res_.size() + 1;
357  pivots_selected[ cutpoint_pivot ] = true;
358  total_pivots--;
359 
360  // two more to go.
361  for ( Size n = 1; n <= 2; n++ ){
362 
363  Size const which_pivot = static_cast<int>( RG.uniform() * total_pivots ) + 1;
364  Size count( 0 );
365 
366  for ( Size i = 1; i <= pivots_selected.size(); i++ ) {
367  if ( !pivots_selected[ i ] ) count++;
368  if ( count == which_pivot ) {
369  pivots_selected[ i ] = true;
370  total_pivots--;
371  break;
372  }
373  }
374 
375  }
376 
377  ////////////////////
378  // manual override!
379  ////////////////////
380  // for( Size i=1; i<=pivots_selected.size();i++) pivots_selected[i]= false;
381  // pivots_selected[ 2 ] = true;
382  // pivots_selected[ 3 ] = true;
383  // pivots_selected[ 4 ] = true;
384  ////////////////////
385 
386  ////////////////////////////////////////////////////////////////////////////
387  // Okey doke, what are the three pivots?
388  // Also, will need to carry out kinematic loop closure on a little "scratch pose"
389  // that includes these pivots as well as ...
390  // the residues before/after the cutpoint (one or both of these is a pivot as well)
391  // [I think there may be a simpler way to write this ]
392  is_scratch_res_.clear();
393  is_pivot_res_.clear();
394  for ( Size i = 1; i <= is_backward_res_.size() /*pose.total_residue()*/ ; i++ ){
395  is_scratch_res_.push_back( false );
396  is_pivot_res_.push_back( false );
397  }
398 
399  if ( verbose_ ) {
400  std::cout << "PIVOTS_SELECTED: ";
401  for ( Size i = 1; i <= pivots_selected.size(); i++ ) std::cout << pivots_selected[ i ];
402  std::cout << std::endl;
403  }
404 
405  for ( Size i = 1; i <= pivots_selected.size(); i++ ) {
406  if( pivots_selected[ i ] ) {
407  is_pivot_res_[ pivots_in_order[ i ] ] = true;
408  is_scratch_res_[ pivots_in_order[ i ] ] = true;
409  }
410  }
411 
412  is_scratch_res_[ cutpos_ ] = true; /* cutpos+1 is already a pivot_res, this is the residue before.*/
413 
414  if ( verbose_ ) {
415  std::cout << "IS_PIVOT_RES: ";
416  for ( Size i = 1; i <= is_pivot_res_.size(); i++ ) std::cout << is_pivot_res_[ i ];
417  std::cout << std::endl;
418 
419  std::cout << "IS_SCRATCH_RES: ";
420  for ( Size i = 1; i <= is_scratch_res_.size(); i++ ) std::cout << is_scratch_res_[ i ];
421  std::cout << std::endl;
422  }
423 
424  scratch_res_.clear();
425  pivot_res_.clear();
426  pivot_to_scratch_res_.resize( 3, 0 ); /* vector of size 3*/
428 
429  for ( Size i = 1; i <= is_scratch_res_.size(); i++ ) {
430  if ( is_scratch_res_[ i ] ) {
431  scratch_res_.push_back( i );
432  if( i == cutpos_ ) which_scratch_res_is_cut_ = scratch_res_.size();
433  }
434  if ( is_pivot_res_[ i ] ) {
435  pivot_res_.push_back( i );
436  pivot_to_scratch_res_[ pivot_res_.size() ] = scratch_res_.size();
437  }
438  }
439 
440  assert( which_scratch_res_is_cut_ > 0 );
441  assert( scratch_res_.size() >= 3 );
442  assert( pivot_res_.size() == 3 );
443 
444  if (verbose_ ){
445  std::cout << "SCRATCH RES: ";
446  for ( Size n = 1; n <= scratch_res_.size(); n++ ) std::cout << ' ' << scratch_res_[ n ];
447  std::cout << std::endl;
448  }
449 
450  if ( a_little_verbose_ || verbose_ ){
451  TR << "PIVOT RES: ";
452  for ( Size n = 1; n <= pivot_res_.size(); n++ ) TR << ' ' << pivot_res_[ n ];
453  TR << std::endl;
454  }
455 
456  if (verbose_ ){
457  std::cout << "SCRATCH RES: ";
458  std::cout << "PIVOT_TO_SCRATCH_RES: ";
459  for ( Size n = 1; n <= pivot_to_scratch_res_.size(); n++ ) std::cout << ' ' << pivot_to_scratch_res_[ n ];
460  std::cout << std::endl;
461 
462  std::cout << "WHICH_SCRATCH_RES_IS_CUT: " << which_scratch_res_is_cut_ << std::endl;
463  }
464 
465 }
466 
467 //////////////////////////////////////////////////////////////////////////
468 void
470 
471  using namespace core::kinematics;
472  using namespace numeric::kinematic_closure;
473 
474  ///// kinematic loop close.
475  // Following copied from, e.g., KinematicMover.cc. Need to elaborate for terminal residues!
476  // inputs to loop closure
478  utility::vector1<Size> pivots (3), order (3);
479  utility::vector1<Real> dt_ang, db_len, db_ang;
480 
481  // doesn't matter.
482  order[1]=1;
483  order[2]=2;
484  order[3]=3;
485 
486  ///////////////////////////////////////////////////////////
487  ///////////////////////////////////////////////////////////
488  // This is a terrible hack to make S-P-S triplets look like
489  // N-CA-C for proteins.
490  ///////////////////////////////////////////////////////////
491  ///////////////////////////////////////////////////////////
492  atom_ids_.clear();
493  Size const nscratch = scratch_res_.size();
494  // first triplet --dummy for anchoring. Will be replaced by fixed coordinate system
495  atom_ids_.push_back( NamedAtomID( " S ", scratch_res_[ nscratch ] ) );
496  atom_ids_.push_back( NamedAtomID( " P ", scratch_res_[ nscratch ] ) );
497  atom_ids_.push_back( NamedAtomID( " S ", scratch_res_[ nscratch ] ) );
498  // scratch res.
499  for ( Size i = 1; i <= nscratch; i++ ){
500  atom_ids_.push_back( NamedAtomID( " S ", scratch_res_[ i ]-1 ) ); // wait won't this be a problem if scratch_res = 1?
501  atom_ids_.push_back( NamedAtomID( " P ", scratch_res_[ i ] ) );
502  atom_ids_.push_back( NamedAtomID( " S ", scratch_res_[ i ] ) );
503  }
504  // last triplet --dummy for anchoring. Will be replaced by fixed coordinate system
505  atom_ids_.push_back( NamedAtomID( " S ", scratch_res_[ 1 ]-1 ) );
506  atom_ids_.push_back( NamedAtomID( " P ", scratch_res_[ 1 ] ) );
507  atom_ids_.push_back( NamedAtomID( " S ", scratch_res_[ 1 ] ) );
508 
509  for ( Size i = 1; i <= 3; i++ ){
510  pivots[ i ] = 3 * ( pivot_to_scratch_res_[ i ] ) + 2;
511  }
512 
513  fill_chainTORS( pose, atom_ids_, atoms, dt_ang, db_ang, db_len );
514 
515  if ( verbose_ ) output_chainTORS( dt_ang, db_ang, db_len );
516 
517  // These atoms_xyz are the same as computed in fill_chainTORS, but I'm
518  // having some trouble sending them out (can't clear or copy vector1< Vector > ?)
519  utility::vector1< Vector > atoms_xyz;
520  for ( Size i = 1; i <= atoms.size(); i++ ) {
521  atoms_xyz.push_back( Vector(atoms[i][1],atoms[i][2],atoms[i][3]) );
522  }
523 
524  //////////////////////////////////////////////
525  // Parameter at chainbreak.
526  // This looks a bit weird, because of a hack.
527  // In fill_chainTORS, there's a check that one S-P-S triplet
528  // may overlap with the next S-P-S triplet. This definitely
529  // happens at the cutpoint. In that case the degeneracy is broken by
530  // nudging the first S of the second S-P-S triplet a little towards the
531  // centroid of the pre-cutpoint residue. So we can ask for a clean
532  // geometry of the P after the cutpoint with respect to the
533  // previous residue's P-S-CEN coordinate system.
534  static const Real idl_S_nextP_( 3.838 );
535  Real const d_S_nextP = ( pose.xyz( NamedAtomID(" S ", cutpos_) ) -
536  pose.xyz( NamedAtomID("OVL1", cutpos_) ) ).length();
537  if (verbose_) std::cout << " D_S_NEXT_P " << d_S_nextP << " " << idl_S_nextP_ << std::endl;
538  db_len[ 3 * which_scratch_res_is_cut_ + 4 ] = d_S_nextP;
539 
540  static const Real idl_S_Snudge_nextP_( 65.908 );
541  // The "180.0 - " is because Snudge is sort of in the opposite direction to CEN (the math works out).
542  // Real const theta_Snudge_S_nextP = 180.0 - degrees( angle_radians( pose.xyz( NamedAtomID(" CEN", cutpos_) ),
543  // pose.xyz( NamedAtomID(" S ", cutpos_) ),
544  // pose.xyz( NamedAtomID("OVL1", cutpos_) ) ) );
545  Real const theta_S_Snudge_nextP = degrees( angle_radians(atoms_xyz[ 3*which_scratch_res_is_cut_+3],
546  atoms_xyz[ 3*which_scratch_res_is_cut_+4],
547  pose.xyz( NamedAtomID("OVL1", cutpos_) ) ) );
548  if (verbose_) std::cout << " THETA_S_Snudge_NEXTP " << theta_S_Snudge_nextP << " " << idl_S_Snudge_nextP_ << std::endl;
549  db_ang[ 3 * which_scratch_res_is_cut_ + 4 ] = theta_S_Snudge_nextP;
550 
551 
552  static const Real idl_S_nextP_nextS_( 84.947 );
553  Real const theta_S_nextP_nextS = degrees( angle_radians(atoms_xyz[ 3*which_scratch_res_is_cut_+4],
554  pose.xyz( NamedAtomID("OVL1", cutpos_) ),
555  pose.xyz( NamedAtomID("OVL2", cutpos_) ) ) );
556  if (verbose_) std::cout << " THETA_S_NEXTP_NEXTS " << theta_S_nextP_nextS << " " << idl_S_nextP_nextS_ << std::endl;
557  db_ang[ 3 * which_scratch_res_is_cut_ + 5 ] = theta_S_nextP_nextS;
558 
559 
560  static const Real idl_P_S_CEN_nextP( 86.592 );
561  // Real const phi_P_S_Snudge_nextP = degrees( dihedral_radians( atoms_xyz[ 3*which_scratch_res_is_cut_+2],
562  // atoms_xyz[ 3*which_scratch_res_is_cut_+3],
563  // atoms_xyz[ 3*which_scratch_res_is_cut_+4],
564  // pose.xyz( NamedAtomID("OVL1", cutpos_) ) ) );
565  Real const phi_P_S_Snudge_nextP = degrees( dihedral_radians( atoms_xyz[ 3*which_scratch_res_is_cut_+2],
566  atoms_xyz[ 3*which_scratch_res_is_cut_+3],
567  atoms_xyz[ 3*which_scratch_res_is_cut_+4],
568  pose.xyz( NamedAtomID("OVL1", cutpos_) ) ) );
569  if (verbose_) std::cout << " PHI_P_S_Snudge_NEXTP " << phi_P_S_Snudge_nextP << " " << idl_P_S_CEN_nextP << std::endl;
570 
571  dt_ang[ 3 * which_scratch_res_is_cut_ + 3 ] = phi_P_S_Snudge_nextP;
572 
573 
574  //Following are not critical but will allow cutpoint virtual atoms (OVL1, OVL2, and OVU1)
575  // to swing to the right place.
576  Real const phi_cutpivot1 = degrees( dihedral_radians( atoms_xyz[ 3*which_scratch_res_is_cut_+3],
577  atoms_xyz[ 3*which_scratch_res_is_cut_+4],
578  pose.xyz( NamedAtomID("OVL1", cutpos_) ),
579  pose.xyz( NamedAtomID("OVL2", cutpos_) ) ) );
580  dt_ang[ 3 * which_scratch_res_is_cut_ + 4 ] = phi_cutpivot1;
581  if (verbose_) std::cout << " PHI_S_Snudge_nextP_nextS " << phi_cutpivot1 << std::endl;
582 
583  Real const phi_cutpivot2 = degrees( dihedral_radians( pose.xyz( NamedAtomID("OVU1", cutpos_+1) ),
584  atoms_xyz[ 3*which_scratch_res_is_cut_+5],
585  atoms_xyz[ 3*which_scratch_res_is_cut_+6],
586  atoms_xyz[ 3*which_scratch_res_is_cut_+7] ) );
587  dt_ang[ 3 * which_scratch_res_is_cut_ + 5 ] = phi_cutpivot2;
588 
589 
590  // Following *should* be unnecessary, but bridgeObjects reads all atom coordinates
591  // before first pivot and after last pivot to define boundary conditions for loop.
592  // (In principal bridgeObjects just needs the first three and last three atoms!)
593  if ( which_scratch_res_is_cut_ == 1 ) {
594  Vector ovl1 = pose.xyz( NamedAtomID( "OVL1", cutpos_ ) );
595  for ( Size i = 1; i <= 3; i++ ) {
596  atoms[ 3*which_scratch_res_is_cut_ + 5 ][i] = ovl1( i );
597  }
598  }
599 
600  if (verbose_){
601  std::cout << "after chainbreak geometry fix" << std::endl;
602  output_chainTORS( dt_ang, db_ang, db_len );
603  }
604 
605 
606  ///////////////////////////////////
607  // Perform loop closure
608  ///////////////////////////////////
609  t_ang_.clear();
610  b_ang_.clear();
611  b_len_.clear();
612  nsol_ = 0;
613  bridgeObjects(atoms, dt_ang, db_ang, db_len, pivots, order, t_ang_, b_ang_, b_len_, nsol_);
614 
615  // Let's look at the solutions.
616  if ( a_little_verbose_ || verbose_ ) TR << "Kinematic loop closure found this many solutions: " << nsol_ << std::endl;
617  if ( nsol_ == 0 ) return;
618 
619  figure_out_dof_ids_and_offsets( pose, dt_ang );
620 
621  apply_solutions( pose );
622 
623 }
624 
625 ///////////////////////////////////////////////////////////////////////////////////////
626 void
628  utility::vector1<Real> const & dt_ang ){
629  ////////////////////////////////////////////////////////////////////////////////////
630  // Note that the torsion angles that we solved for do not directly correspond to
631  // torsion angles in the atom-tree. But they are right up to an *offset*, which
632  // we pre-calculate now. Also this is a good time to figure out exactly which
633  // DOFs need to be changed in the atom-tree.
634  //
635  // I think this could be nicely generalized to the fullatom RNA case, or even a
636  // general polymer, but currently don't have the time.
637  //
638  ////////////////////////////////////////////////////////////////////////////////////
639 
640  offset_save1_.clear();
641  offset_save2_.clear();
642 
643  dof_ids1_.clear();
644  dof_ids2_.clear();
645 
646  DOF_ID dof_id1,dof_id2;
647 
648  assert( pivot_res_.size() == 3 );
649 
650  AtomID id1, id2, id3, id4;
651  for ( Size i = 1; i <= 3; i++ ){
652 
653  Size const pivot = pivot_res_[ i ]; // residue number of phosphate.
654 
655  /////////////////////////////////////////////////////////////////////////////////////////
656  id1 = named_atom_id_to_atom_id( NamedAtomID( " P ", pivot-1 ), pose );
657  id2 = named_atom_id_to_atom_id( NamedAtomID( " S ", pivot-1 ), pose );
658  if ( pose.fold_tree().is_cutpoint( pivot - 1 ) ){
659  assert( pose.residue_type( pivot-1 ).has_variant_type( chemical::CUTPOINT_LOWER ) ); //this better be the case!!!
660  id3 = named_atom_id_to_atom_id( NamedAtomID( "OVL1", pivot-1 ), pose );
661  id4 = named_atom_id_to_atom_id( NamedAtomID( "OVL2", pivot-1 ), pose );
662  } else {
663  id3 = named_atom_id_to_atom_id( NamedAtomID( " P ", pivot ), pose );
664  id4 = named_atom_id_to_atom_id( NamedAtomID( " S ", pivot ), pose );
665  }
666 
667  dof_id1 = pose.atom_tree().torsion_angle_dof_id( id1, id2, id3, id4 );
668  // std::cout << "PIVOT " << pivot << " DOF_ID1 " << dof_id1 << " ID1 " << id1<< " ID2 " << id2 << " ID3 " << id3 << " ID4 " << id4 << std::endl;
669  dof_ids1_.push_back( dof_id1 );
670  figure_out_offset( pose, pivot, dof_id1, dt_ang[ 3*pivot_to_scratch_res_[ i ] + 1 ], offset_save1_ );
671 
672  /////////////////////////////////////////////////////////////////////////////////////////
673  if ( pose.fold_tree().is_cutpoint( pivot - 1 ) ){
674  assert( pose.residue_type( pivot ).has_variant_type( chemical::CUTPOINT_UPPER ) ); //this better be the case!!!
675  id1 = named_atom_id_to_atom_id( NamedAtomID( "OVU1", pivot ), pose );
676  } else {
677  id1 = named_atom_id_to_atom_id( NamedAtomID( " S ", pivot-1 ), pose );
678  }
679  id2 = named_atom_id_to_atom_id( NamedAtomID( " P ", pivot ), pose );
680  id3 = named_atom_id_to_atom_id( NamedAtomID( " S ", pivot ), pose );
681  if ( pose.fold_tree().is_cutpoint( pivot ) ){
682  id4 = named_atom_id_to_atom_id( NamedAtomID( " CEN", pivot ), pose );
683  } else {
684  id4 = named_atom_id_to_atom_id( NamedAtomID( " P ", pivot+1 ), pose );
685  }
686 
687  dof_id2 = pose.atom_tree().torsion_angle_dof_id( id1, id2, id3, id4 );
688  // std::cout << "PIVOT " << pivot << " DOF_ID2 " << dof_id2 << " ID1 " << id1<< " ID2 " << id2 << " ID3 " << id3 << " ID4 " << id4 << std::endl;
689  dof_ids2_.push_back( dof_id2 );
690  figure_out_offset( pose, pivot, dof_id2, dt_ang[ 3*pivot_to_scratch_res_[ i ] + 2 ], offset_save2_ );
691 
692  }
693 
694 }
695 
696 ////////////////////////////////////////////////////////////////////////////////////
697 void
699  core::pose::Pose const & pose,
700  core::Size const & pivot,
701  core::id::DOF_ID const & dof_id,
702  core::Real const & original_torsion_value,
703  utility::vector1< core::Real > & offset_save ){
704 
705  if ( dof_id == BOGUS_DOF_ID ) { //expected at cutpoint!
706  // if ( pivot == cutpos_+1 ) {
707  // offset_save.push_back( 0.0 ); //placeholder
708  // if ( verbose_ ){
709  // std::cout << dof_id;
710  // std::cout << " offset --- " << std::endl;
711  // }
712  // } else {
713  std::cout << "Problem with DOF_ID "<< pivot << " " << dof_id << std::endl;
714  utility_exit_with_message( "Problem with DOF_ID" );
715  // }
716  } else {
717  offset_save.push_back( pose.dof( dof_id ) - radians( original_torsion_value ) );
718  if ( verbose_ ){
719  std::cout << dof_id;
720  std::cout << " offset " << pose.dof( dof_id ) << " " << radians( original_torsion_value )
721  << " " << pose.dof( dof_id ) - radians( original_torsion_value ) << std::endl;
722  }
723  }
724 }
725 
726 /////////////////////////////////////////////////////////////////////////////////////////////////////////
727 void
729 
730  assert( t_ang_.size() == Size( nsol_ ) );
731 
732  /////////////////////////////////////////////////////////////////////////////////////////////////////
733  // Finally, ready to check out the solutions
734  /////////////////////////////////////////////////////////////////////////////////////////////////////
735  if ( nsol_ == 0 ) return;
736 
738 
739 
740  if ( verbose_ ) {
741  std::cout << "---------------------------------- " << std::endl;
742  std::cout << " start pose " << std::endl;
743  std::cout << "---------------------------------- " << std::endl;
744  utility::vector1<Real> dt_ang, db_len, db_ang;
746  fill_chainTORS( pose, atom_ids_, atoms, dt_ang, db_ang, db_len );
747  output_chainTORS( dt_ang, db_ang, db_len );
748  pose.dump_pdb( "before_closed.pdb" );
749  }
750 
751  Real best_deviation2( 0.0 );
752  Size best_sol( 0 );
753  // could save time by just looking over a subset of residues. But I don't think this is rate limiting
754  utility::vector1< Vector > ref_vectors;
755  Size const ref_atom( 1 );
756  for ( Size i = 1; i <= pose.total_residue(); i++ ){
757  ref_vectors.push_back( pose.xyz( id::AtomID(ref_atom,i) ) );
758  }
759 
760  for (Size n = 1; n <= Size( nsol_ ); n++) {
761  fill_solution( pose, n );
762  Real deviation2( 0.0 );
763  for ( Size i = 1; i <= pose.total_residue(); i++ ){
764  deviation2 += ( pose.xyz( id::AtomID(ref_atom,i) ) - ref_vectors[i] ).length_squared();
765  }
766  if ( n==1 || deviation2 < best_deviation2){
767  best_deviation2 = deviation2;
768  best_sol = n;
769  }
770  }
771 
772  fill_solution( pose, best_sol );
773 
774  if ( verbose_ ){ //consistency check.
775 
776  std::cout << "---------------------------------- " << std::endl;
777  std::cout << " solution " << best_sol << std::endl;
778  std::cout << "---------------------------------- " << std::endl;
779  output_chainTORS( t_ang_[best_sol], b_ang_[best_sol], b_len_[best_sol] );
780 
781  }
782 
783  fill_solution( pose, best_sol );
784 
785  if ( verbose_ ) {
786  std::cout << "pose " << best_sol << ": " << std::endl;
787  utility::vector1<Real> dt_ang, db_len, db_ang;
789  fill_chainTORS( pose, atom_ids_, atoms, dt_ang, db_ang, db_len );
790  output_chainTORS( dt_ang, db_ang, db_len );
791  pose.dump_pdb( "closed.pdb" );
792  }
793 
794  } else if ( choose_best_solution_ ){
795 
796  assert( scorefxn_ != 0 );
797 
798  Real best_score( 0.0 );
799  Size best_sol( 0 );
800  for (Size n = 1; n <= Size( nsol_ ); n++) {
801  fill_solution( pose, n );
802  Real const score = (*scorefxn_)( pose );
803  if ( score < best_score || n == 1 ) {
804  best_score = score;
805  best_sol = n;
806  }
807 
808  if ( verbose_ && n == 2 ){ //consistency check.
809  std::cout << "solution " << n << ": " << std::endl;
810  output_chainTORS( t_ang_[n], b_ang_[n], b_len_[n] );
811 
812  std::cout << "pose " << n << ": " << std::endl;
813 
814  utility::vector1<Real> dt_ang, db_len, db_ang;
816  fill_chainTORS( pose, atom_ids_, atoms, dt_ang, db_ang, db_len );
817  output_chainTORS( dt_ang, db_ang, db_len );
818  }
819 
820  }
821  fill_solution( pose, best_sol );
822 
823  } else {
824 
825  assert( choose_random_solution_ );
826  Size const n = static_cast<int>( nsol_ * RG.uniform() ) + 1;
827  fill_solution( pose, n );
828 
829  }
830 
831 }
832 
833 //////////////////////////////////////////////////////////////////////////////////////////////
834 void
837 
838  pose_list.clear();
839 
840  for (Size n = 1; n <= Size( nsol_ ); n++) {
841 
842  fill_solution( pose, n );
843 
844  core::pose::PoseOP pose_save = new Pose;
845  *pose_save = pose;
846  pose_list.push_back( pose_save );
847 
848  if (verbose_ ) {
849  pose.dump_pdb( "KIC_"+ ObjexxFCL::string_of( n )+".pdb" );
850  }
851 
852  }
853 }
854 
855 
856 //////////////////////////////////////////////////////////////////////////////////////////////////////////
857 void
859  Size const n ) const
860 {
861 
862  for ( Size i = 1; i <= dof_ids1_.size(); i++ ){
863 
864  if ( dof_ids1_[ i ] != BOGUS_DOF_ID ) {
865  pose.set_dof( dof_ids1_[i], principal_angle( radians( t_ang_[ n ][ 3 * pivot_to_scratch_res_[ i ] + 1 ] ) + offset_save1_[i] ) );
866  }
867 
868  if ( dof_ids2_[ i ] != BOGUS_DOF_ID ) {
869  pose.set_dof( dof_ids2_[i], principal_angle( radians( t_ang_[ n ][ 3 * pivot_to_scratch_res_[ i ] + 2 ] ) + offset_save2_[i] ) );
870  }
871 
872  }
873 
874 }
875 
876 //////////////////////////////////////////////////////////////////////////////////////////////////////////
877 void
879  choose_best_solution_ = true;
881  scorefxn_ = scorefxn;
882 }
883 
884 //////////////////////////////////////////////////////////////////////////////////////////////////////////
885 void
887  choose_best_solution_ = false;
889 }
890 
891 ///////////////////////////////////////////////////////////////////////////
892 void
894  utility::vector1< core::Real > const & db_ang,
895  utility::vector1< core::Real > const & db_len ) const {
896 
897  std::cout << "------ chainTORS output ---- " << std::endl;
898  for (Size i = 1; i <= dt_ang.size(); i++) {
899  std::cout << I( 3, i ) << " ";
900  std::cout << "TORSIONS: ";
901  std::cout << F(8,3,dt_ang[ i ]) << " ";
902 
903  std::cout << " BOND_ANGLES: ";
904  std::cout << F(8,3,db_ang[ i ]) << " ";
905 
906  std::cout << " BOND_LENGTHS: ";
907  std::cout << F(8,3,db_len[ i ]) << " ";
908 
909  std::cout << std::endl;
910 
911  }
912 }
913 
914 ///////////////////////////////////////////////////////////
915 void
917  core::pose::Pose const & pose,
920  utility::vector1<Real> & dt_ang,
921  utility::vector1<Real> & db_ang,
922  utility::vector1<Real> & db_len) const {
923 
924  using namespace core::kinematics;
925  using namespace numeric::kinematic_closure;
926 
928  utility::vector1<Real> R0 (3);
929 
930  utility::vector1< Vector > atoms_xyz;
931  for (Size i = 1; i <= atom_ids_.size(); i++ ) {
932  // std::cout << "filling: " << atom_ids_[i].atomno() << " " << atom_ids_[i].rsd() << std::endl;
933  atoms_xyz.push_back( pose.xyz( atom_ids_[ i ] ) );
934  }
935 
936  //replace first and last with coordinate systems?
937  atoms_xyz[ 1 ] = Vector( 0.0, 0.0, 0.0 );
938  atoms_xyz[ 2 ] = Vector( 0.0, 0.0, 1.0 );
939  atoms_xyz[ 3 ] = Vector( 0.0, 1.0, 0.0 );
940 
941  atoms_xyz[ atom_ids_.size() - 2 ] = Vector( 1.0, 0.0, 0.0 );
942  atoms_xyz[ atom_ids_.size() - 1 ] = Vector( 1.0, 0.0, 1.0 );
943  atoms_xyz[ atom_ids_.size() ] = Vector( 1.0, 1.0, 0.0 );
944 
945  // Some of the pivot atoms may not be distinct -- nan.
946  // luckily there's a little hack we can do.
947  // where we nudge one atom the slightest bit.
948  static Real const nudge( 0.000001 );
949  for ( Size n = 1; n <= ( (atom_ids_.size()/3) - 3 ) ; n++ ){
950  Size const i = 3 + (n * 3); // Look at S at the end of one triplet that may overlap with starting S of next triplet
951  if ( atom_ids_[ i ] == atom_ids_[ i+1 ] ){
952  // This should be the S at the end of one triplet overlapping with
953  // the S beginning the next triplet.
954  Size const seqpos = atom_ids_[ i ].rsd();
955  atoms_xyz[ i+1 ] = atoms_xyz[ i ] +
956  nudge * ( pose.xyz( NamedAtomID( " CEN", seqpos ) ) - atoms_xyz[i] ).normalize();
957  }
958  }
959 
960  // formatting.
961  atoms.clear();
962  for ( Size i = 1; i <= atom_ids_.size(); i++ ){
963  utility::vector1< Real > atom_xyz_vals;
964  atom_xyz_vals.push_back( atoms_xyz[i].x() );
965  atom_xyz_vals.push_back( atoms_xyz[i].y() );
966  atom_xyz_vals.push_back( atoms_xyz[i].z() );
967  atoms.push_back( atom_xyz_vals );
968  }
969 
970  chainTORS(atoms.size(), atoms, dt_ang, db_ang, db_len, R0, Q0);
971 }
972 
973 
974 ///////////////////////////////////////////////////////////
975 void
978 }
979 
980 ///////////////////////////////////////////////////////////
983  return allow_insert_;
984 }
985 
986 
987 } // namespace coarse_rna
988 } // namespace protocols