Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
fold_tree_functions.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 protocols/forge/methods/fold_tree_functions.cc
11 /// @brief methods for manipulating FoldTrees
12 /// @author Yih-En Andrew Ban (yab@u.washington.edu)
13 
14 // unit headers
16 
17 // package headers
19 
20 // project headers
21 #include <core/types.hh>
25 
27 #include <core/kinematics/Edge.hh>
30 #include <core/pose/Pose.hh>
31 #include <basic/Tracer.hh>
32 
33 // numeric headers
34 #include <numeric/random/random.hh>
35 
36 // utility headers
37 #include <utility/exit.hh>
38 
39 // C++ headers
40 #include <algorithm>
41 #include <map>
42 #include <set>
43 #include <sstream>
44 #include <string>
45 #include <vector>
46 
47 #include <core/pose/util.hh>
48 #include <utility/vector1.hh>
49 
50 
51 
52 namespace protocols {
53 namespace forge {
54 namespace methods {
55 
56 
57 static numeric::random::RandomGenerator RG( 2557316 ); // magic number, don't change
58 
59 
60 // Tracer instance for this file
61 // Named after the original location of this code
62 static basic::Tracer TR( "protocols.forge.methods.fold_tree_functions" );
63 
64 
65 /// @brief enforce Edge has start <= stop (swap if necessary)
66 /// @return true if start and stop were swapped
68  if ( e.start() > e.stop() ) {
69  int const tmp = e.stop();
70  e.stop() = e.start();
71  e.start() = tmp;
72 
73  if ( !e.start_atom().empty() || !e.stop_atom().empty() ) {
74  std::string tmp_s = e.stop_atom();
75  e.stop_atom() = e.start_atom();
76  e.start_atom() = tmp_s;
77  }
78 
79  return true;
80  }
81 
82  return false;
83 }
84 
85 
86 /// @brief find the k'th closest larger peptide vertex of given vertex in fold tree
87 /// @param[in] v the given vertex
88 /// @param[in] ft fold tree to search
89 /// @param[in] k find the k'th closest, must be > 0
90 /// @return 0 if no such vertex
93  core::Size const v,
94  core::kinematics::FoldTree const & ft,
95  core::Size const k
96 )
97 {
98  using core::Size;
101 
102  assert( k > 0 );
103 
104  std::vector< Size > peptide_vertices;
105 
106  for ( FoldTree::const_iterator e = ft.begin(), ee = ft.end(); e != ee; ++e ) {
107  if ( e->label() == Edge::PEPTIDE ) {
108  peptide_vertices.push_back( e->start() );
109  peptide_vertices.push_back( e->stop() );
110  }
111  }
112 
113  // run through in sorted order
114  Size count = 0;
115  std::sort( peptide_vertices.begin(), peptide_vertices.end() );
116  std::unique( peptide_vertices.begin(), peptide_vertices.end() );
117  for ( std::vector< Size >::const_iterator i = peptide_vertices.begin(), ie = peptide_vertices.end(); i != ie; ++i ) {
118  if ( *i > v ) {
119  ++count;
120  if ( count == k ) {
121  return *i;
122  }
123  }
124  }
125 
126  return 0;
127 }
128 
129 
130 /// @brief find the k'th closest smaller peptide vertex of given vertex in fold tree
131 /// @param[in] v the given vertex
132 /// @param[in] ft fold tree to search
133 /// @param[in] k find the k'th closest, must be > 0
134 /// @return 0 if no such vertex
137  core::Size const v,
138  core::kinematics::FoldTree const & ft,
139  core::Size const k
140 )
141 {
142  using core::Size;
145 
146  assert( k > 0 );
147 
148  std::vector< Size > peptide_vertices;
149 
150  for ( FoldTree::const_iterator e = ft.begin(), ee = ft.end(); e != ee; ++e ) {
151  if ( e->label() == Edge::PEPTIDE ) {
152  peptide_vertices.push_back( e->start() );
153  peptide_vertices.push_back( e->stop() );
154  }
155  }
156 
157  // run through in backwards sorted order
158  Size count = 0;
159  std::sort( peptide_vertices.begin(), peptide_vertices.end() );
160  std::unique( peptide_vertices.begin(), peptide_vertices.end() );
161  for ( std::vector< Size >::const_reverse_iterator i = peptide_vertices.rbegin(), ie = peptide_vertices.rend(); i != ie; ++i ) {
162  if ( *i < v ) {
163  ++count;
164  if ( count == k ) {
165  return *i;
166  }
167  }
168  }
169 
170  return 0;
171 }
172 
173 
174 /// @brief query if vertex already exists in fold tree
175 bool
177  core::Size const v,
178  core::kinematics::FoldTree const & ft
179 )
180 {
181  using core::Size;
183 
184  for ( FoldTree::const_iterator e = ft.begin(), ee = ft.end(); e != ee; ++e ) {
185  if ( static_cast< Size >( e->start() ) == v || static_cast< Size >( e->stop() ) == v ) {
186  return true;
187  }
188  }
189 
190  return false;
191 }
192 
193 
194 /// @brief find all jump edges whose start or stop lands on the given position
195 /// @param[in] pos The position.
196 /// @param[in] ft The fold tree.
197 /// @return a list of jump edges
199  core::Size const pos,
200  core::kinematics::FoldTree const & ft
201 )
202 {
203  using core::Size;
206 
207  typedef utility::vector1< Edge > Edges;
208 
209  Edges jump_edges;
210 
211  for ( FoldTree::const_iterator e = ft.begin(), ee = ft.end(); e != ee; ++e ) {
212  if ( e->label() > 0 && ( static_cast< Size >( e->start() ) == pos || static_cast< Size >( e->stop() ) == pos ) ) {
213  jump_edges.push_back( *e );
214  }
215  }
216 
217  return jump_edges;
218 }
219 
220 
221 /// @brief find the jump connecting two continuous segments of a fold tree
222 /// @param[in] u Any vertex on the first segment.
223 /// @param[in] v Any vertex on the second segment.
224 /// @param[in] ft The fold tree to query.
225 /// @return the jump number connecting the two segments, 0 if no such jump
227  core::Size const u,
228  core::Size const v,
229  core::kinematics::FoldTree const & ft
230 )
231 {
232  using core::Size;
236 
237  // add all regular edges sans jumps to union-find to construct continuous segments
238  DisjointSets uf( ft.nres() );
239  for ( FoldTree::const_iterator e = ft.begin(), ee = ft.end(); e != ee; ++e ) {
240  Edge edge( *e );
241  order( edge );
242 
243  if ( e->label() < 0 ) {
244  union_interval( edge.start(), edge.start(), edge.stop(), uf );
245  }
246  }
247 
248  // representatives of the segments of u and v
249  Size const root_u = uf.ds_find( u );
250  Size const root_v = uf.ds_find( v );
251 
252  for ( Size i = 1, ie = ft.num_jump(); i <= ie; ++i ) {
253  Edge const & e = ft.jump_edge( i );
254 
255  Size const root_start = uf.ds_find( e.start() );
256  Size const root_stop = uf.ds_find( e.stop() );
257  if ( ( root_start == root_u && root_stop == root_v ) || ( root_start == root_v && root_stop == root_u ) ) {
258  return i;
259  }
260  }
261 
262  return 0; // couldn't find a jump edge
263 }
264 
265 
266 /// @brief remove a cutpoint, merging the two sections that are adjacent to the cut
267 /// @return true if cutpoint removed, false if not a cutpoint
269  core::Size const v,
271 )
272 {
273  using core::Size;
277 
279 
280  if ( !ft.is_cutpoint( v ) ) {
281  return false;
282  }
283 
284  // first:
285  // - add all regular edges sans jumps to union-find to construct continuous
286  // segments
287  // - collect all jump edges
288  DisjointSets uf( ft.nres() );
289  EdgeList jump_edges;
290 
291  for ( FoldTree::const_iterator e = static_cast< FoldTree const & >( ft ).begin(), ee = static_cast< FoldTree const & >( ft ).end(); e != ee; ++e ) {
292  Edge edge( *e );
293  order( edge );
294 
295  if ( e->label() > 0 ) {
296  jump_edges.push_back( edge );
297  } else {
298  union_interval( edge.start(), edge.start(), edge.stop(), uf );
299  }
300  }
301 
302  // find the representatives of section containing cutpoint and cutpoint+1
303  Size const left_root = uf.ds_find( v );
304  Size const right_root = uf.ds_find( v + 1 );
305 
306  // Run through jump edges to find the jump connecting the left & right sets.
307  // Jump edges were ordered when collecting them, so the start() must correspond
308  // to the left set and the stop() must correspond to the right set.
309  EdgeList::const_iterator j = jump_edges.begin(), je = jump_edges.end();
310  while(
311  j != je &&
312  uf.ds_find( j->start() ) != left_root &&
313  uf.ds_find( j->stop() ) != right_root
314  )
315  {
316  ++j;
317  }
318 
319  // remove the jump and subsequently the cutpoint; this call should
320  // automatically reorder the tree
321  ft.delete_jump_and_intervening_cutpoint( j->start(), j->stop() );
322 
323  return true;
324 }
325 
326 
327 /// @brief seal a fold tree by removing all specified cutpoints
328 /// @param[in] cutpoints Cutpoints to remove.
329 /// @param[in,out] ft The input tree.
330 /// @return A new tree with cutpoints removed and all other topology kept
331 /// constant.
333  utility::vector1< core::Size > const & cutpoints,
335 )
336 {
337  using core::Size;
341 
343 
344  // first:
345  // - add all regular edges sans jumps to union-find to construct continuous
346  // segments
347  // - collect all jump edges
348  DisjointSets uf( ft.nres() );
349  EdgeList jump_edges;
350 
351  for ( FoldTree::const_iterator e = static_cast< FoldTree const & >( ft ).begin(), ee = static_cast< FoldTree const & >( ft ).end(); e != ee; ++e ) {
352  Edge edge( *e );
353  order( edge );
354 
355  if ( e->label() > 0 ) {
356  jump_edges.push_back( edge );
357  } else {
358  union_interval( edge.start(), edge.start(), edge.stop(), uf );
359  }
360  }
361 
362  // run through all cutpoints
363  for ( utility::vector1< Size >::const_iterator i = cutpoints.begin(), ie = cutpoints.end(); i != ie; ++i ) {
364  // find the representatives of section containing cutpoint and cutpoint+1
365  Size const v = *i;
366  Size const left_root = uf.ds_find( v );
367  Size const right_root = uf.ds_find( v + 1 );
368 
369  // Run through jump edges to find the jump connecting the left & right sets.
370  // Jump edges were ordered when collecting them, so the start() must correspond
371  // to the left set and the stop() must correspond to the right set.
372  EdgeList::const_iterator j = jump_edges.begin(), je = jump_edges.end();
373  while(
374  j != je &&
375  uf.ds_find( j->start() ) != left_root &&
376  uf.ds_find( j->stop() ) != right_root
377  )
378  {
379  ++j;
380  }
381 
382  // remove the jump and subsequently the cutpoint; this call should
383  // automatically reorder the tree
384  ft.delete_jump_and_intervening_cutpoint( j->start(), j->stop() );
385 
386  // track the merge between the two segments
387  uf.ds_union( left_root, right_root );
388  }
389 }
390 
391 
392 /// @brief attempt to shift jumps in a fold tree based on fixed positions in a MoveMap
393 /// @param[in] ft FoldTree to alter
394 /// @param[in] movemap MoveMap to try and honor
395 /// @return FoldTree with jumps shifted, if possible
396 /// @remarks Procedure will shift a jump position on a continuous segment to a
397 /// randomly selected fixed position on that segment specified by the MoveMap.
398 /// No changes will be made to a jump point if it is contained within a segment
399 /// lacking valid fixed positions. This procedure has the side effect of
400 /// collapsing all jump points to a single point within segments that have
401 /// fixed positions.
404  core::kinematics::FoldTree const & ft,
405  core::kinematics::MoveMap const & mm
406 )
407 {
408  using core::Size;
412 
414  typedef utility::vector1< Size > NodeList;
415  typedef std::map< Size, Size > Root2Jump;
416  typedef std::map< Size, NodeList > Root2Nodes;
417 
418  FoldTree aft; // altered FoldTree, return this
419  DisjointSets uf( ft.nres() );
420  EdgeList regular_edges; // non-jump edges
421  EdgeList jump_edges;
422 
423  // separate edges into categories; construct continuous segments using union-find
424  for ( FoldTree::const_iterator e = ft.begin(), ee = ft.end(); e != ee; ++e ) {
425  if ( e->label() > 0 ) { // jump edge
426 
427  jump_edges.push_back( *e );
428  order( jump_edges.back() );
429 
430  } else { // regular edge
431 
432  regular_edges.push_back( *e );
433  order( regular_edges.back() );
434  union_interval( regular_edges.back().start(), regular_edges.back().start(), regular_edges.back().stop(), uf );
435 
436  }
437  }
438 
439  // pick a single jump point per segment
440  Root2Jump r2j;
441  Root2Nodes r2n = uf.sets();
442  for ( Root2Nodes::iterator i = r2n.begin(), ie = r2n.end(); i != ie; ++i ) {
443  NodeList & nodes = i->second;
444  NodeList fixed;
445 
446  // find all useable fixed positions for jump
447  for ( NodeList::const_iterator j = nodes.begin(), je = nodes.end(); j != je; ++j ) {
448  if ( !mm.get_bb( *j ) ) {
449  fixed.push_back( *j );
450  }
451  }
452 
453  // pick fixed position for jump
454  if ( !fixed.empty() ) {
455  r2j[ i->first ] = fixed[ RG.random_range( 1, fixed.size() ) ];
456  }
457  }
458 
459  // swap all jump points, split any necessary regular edges
460  for ( EdgeList::iterator e = jump_edges.begin(), ee = jump_edges.end(); e != ee; ++e ) {
461  Root2Jump::const_iterator new_start = r2j.find( uf.ds_find( e->start() ) );
462  Root2Jump::const_iterator new_stop = r2j.find( uf.ds_find( e->stop() ) );
463 
464  // swap start
465  if ( new_start != r2j.end() ) {
466  e->start() = new_start->second;
467  }
468 
469  // swap stop
470  if ( new_stop != r2j.end() ) {
471  e->stop() = new_stop->second;
472  }
473 
474  // split facets if necessary
475  add_vertex( e->start(), regular_edges );
476  add_vertex( e->stop(), regular_edges );
477  }
478 
479  // add all regular edges
480  for ( EdgeList::const_iterator e = regular_edges.begin(), ee = regular_edges.end(); e != ee; ++e ) {
481  aft.add_edge( *e );
482  }
483 
484  // add all jump edges
485  for ( EdgeList::const_iterator e = jump_edges.begin(), ee = jump_edges.end(); e != ee; ++e ) {
486  aft.add_edge( *e );
487  }
488 
489  // finalize
490  aft.reorder( ft.root() );
491 
492  return aft;
493 }
494 
495 
496 /// @brief construct a fold tree from Pose wrt chain endings and residue types
497 /// @remarks Determines edge types from residues (polymer vs non-polymer).
498 /// Each chain will end up as one edge in the fold tree. Jumps will be made
499 /// from the new root to a random fixed backbone residue as specified by the
500 /// movemap. If all residues in a chain are moveable, will choose any random
501 /// residue.
502 /// @param[in] pose Pose.
503 /// @param[in] ft_root Root of the new fold tree.
504 /// @param[in] mm MoveMap used to select jump positions.
505 /// @return fold tree wrt chain endings and residue types
508  core::pose::Pose const & pose,
509  core::Size const ft_root,
510  core::kinematics::MoveMap const & mm
511 )
512 {
513  using core::Size;
518 
519  typedef utility::vector1< Edge > Edges;
520  typedef utility::vector1< Size > Nodes;
521  typedef std::map< Size, Nodes > Root2Nodes;
522 
523  FoldTree ft;
524 
525  // NOTE: This procedure could be significantly simpler but the current fold
526  // tree implementation does not allow it; hence what is essentially a series
527  // of workarounds below.
528 
529  // use union-find to track connected components
530  DisjointSets uf( pose.n_residue() );
531 
532  // first connect sequential polymer vertices and do connections
533  // between chemical vertices
534  for ( Size i = 1, ie = pose.conformation().num_chains(); i <= ie; ++i ) {
535  Size const chain_begin = pose.conformation().chain_begin( i );
536  Size const chain_end = pose.conformation().chain_end( i );
537 
538  Size prior_polymer_r = pose.residue( chain_begin ).is_polymer() ? chain_begin : 0;
539  for ( Size r = chain_begin; r <= chain_end; ++r ) {
540  Residue const & res = pose.residue( r );
541 
542  if ( res.is_polymer() ) {
543 
544  // if polymer and sequential, union with prior residue;
545  // cannot add polymer edge yet (also, some FoldTree internal
546  // topology checks barf when too many [i,i+1] vertices)
547  if ( prior_polymer_r > 0 && r == prior_polymer_r + 1 ) { // safe for r == 1
548  uf.ds_union( r, prior_polymer_r );
549  }
550 
551  prior_polymer_r = r;
552 
553  } else { // chemical connection
554 
555  for ( Size c = 1, ce = res.n_residue_connections(); c <= ce; ++c ) {
556  Size const cr = res.connected_residue_at_resconn( c );
557  Residue const & cres = pose.residue( cr );
558 
559  assert( static_cast< Size >( res.chain() ) == i );
560 
561  if ( r < cr && res.chain() == cres.chain() ) {
562 
563  // go ahead and add the edge to fold tree;
564  // uses implicit chemical edge constructor
565  ft.add_edge(
566  Edge(
567  r, cr,
568  res.atom_name( res.connect_atom( cres ) ),
569  cres.atom_name( cres.connect_atom( res ) ) )
570  );
571 
572  uf.ds_union( cr, r );
573  }
574  } // foreach residue connection
575 
576  }
577  } // foreach chain
578  }
579 
580  // grab components up to this point
581  Root2Nodes r2n = uf.sets();
582 
583  // run through each component, adding polymer edges and assigning jumps
584  Size jump_count = 0;
585  for ( Root2Nodes::iterator i = r2n.begin(), ie = r2n.end(); i != ie; ++i ) {
586  Nodes & nodes = i->second;
587  std::sort( nodes.begin(), nodes.end() );
588  bool const component_contains_ft_root = std::find( nodes.begin(), nodes.end(), ft_root ) != nodes.end();
589 
590  if ( nodes.size() > 1 ) {
591 
592  // Grab only polymer vertices. Need to do this to separate any
593  // mixed vertex scenarios.
594  Nodes polymer_vertices;
595  for ( Nodes::const_iterator v = nodes.begin(), ve = nodes.end(); v != ve; ++v ) {
596  if ( pose.residue( *v ).is_polymer() ) {
597  polymer_vertices.push_back( *v );
598  }
599  }
600 
601  if ( polymer_vertices.empty() ) {
602 
603  // everything is chemical, pick a jump point and be done
604  if ( !component_contains_ft_root ) {
605  Size const jump_point = RG.random_range( *nodes.begin(), *nodes.rbegin() );
606  ft.add_edge( Edge( ft_root, jump_point, ++jump_count ) );
607  uf.ds_union( jump_point, ft_root );
608  }
609 
610  } else if ( polymer_vertices.size() == 1 ) {
611 
612  // single vertex, jump point is the single polymer vertex
613  if ( !component_contains_ft_root ) {
614  ft.add_edge( Edge( ft_root, *polymer_vertices.begin(), ++jump_count ) );
615  uf.ds_union( *polymer_vertices.begin(), ft_root );
616  }
617 
618  } else {
619 
620  // construct re-indexed uf to track connected polymer subsections
621  DisjointSets indexed_uf( polymer_vertices.size() );
622  for ( Size j = 1, je = polymer_vertices.size(); j < je; ++j ) {
623  if ( polymer_vertices[ j ] + 1 == polymer_vertices[ j+1 ] ) {
624  // for simplicity do the union here instead of when the
625  // polymer edge is added
626  indexed_uf.ds_union( j+1, j );
627  }
628  }
629 
630  Root2Nodes indexed_r2n = indexed_uf.sets();
631  for ( Root2Nodes::iterator j = indexed_r2n.begin(), je = indexed_r2n.end(); j != je; ++j ) {
632  Nodes subsection = j->second;
633  std::sort( subsection.begin(), subsection.end() );
634  Size const ss_begin = polymer_vertices[ *subsection.begin() ];
635  Size const ss_end = polymer_vertices[ *subsection.rbegin() ];
636  bool const subsection_contains_ft_root = ss_begin <= ft_root && ft_root <= ss_end;
637 
638  // find appropriate fixed bb positions for jump
640  for ( Size k = ss_begin; k <= ss_end; ++k ) {
641  if ( !mm.get_bb( k ) ) {
642  fixed.push_back( k );
643  }
644  }
645 
646  // pick a jump point
647  Size jump_point = ft_root;
648  if ( !subsection_contains_ft_root ) {
649  if ( fixed.empty() ) {
650  jump_point = RG.random_range( ss_begin, ss_end );
651  } else {
652  jump_point = fixed[ RG.random_range( 1, fixed.size() ) ];
653  }
654  }
655 
656  // order necessary vertices, remove duplicates
657  std::set< Size > vertices;
658  vertices.insert( ss_begin );
659  vertices.insert( ss_end );
660  vertices.insert( jump_point );
661 
662  // add polymer edges, there are only three cases
663  switch ( vertices.size() ) {
664  case 3:
665  ft.add_edge( Edge( *vertices.begin(), *( ++vertices.begin() ), Edge::PEPTIDE ) );
666  ft.add_edge( Edge( *( ++vertices.begin() ), *( ++( ++vertices.begin() ) ), Edge::PEPTIDE ) );
667  break;
668  case 2:
669  ft.add_edge( Edge( *vertices.begin(), *( ++vertices.begin() ), Edge::PEPTIDE ) );
670  break;
671  case 1:
672  // do nothing
673  break;
674  default:
675  TR.Fatal << "FATAL: fold_tree_from_pose() : vertices.size() not in [1, 3]" << std::endl;
676  utility_exit_with_message( "should not be here" );
677  break;
678  }
679 
680  // add jump edge
681  if ( !subsection_contains_ft_root ) {
682  ft.add_edge( Edge( ft_root, jump_point, ++jump_count ) );
683  uf.ds_union( jump_point, ft_root );
684  }
685 
686  }
687 
688  }
689 
690  } else { // nodes.size() == 1
691  // with one vertex we only need to connect a jump
692  if ( !component_contains_ft_root ) {
693  ft.add_edge( Edge( ft_root, *nodes.begin(), ++jump_count ) );
694  uf.ds_union( *nodes.begin(), ft_root );
695  }
696  }
697  }
698 
699  assert( uf.n_disjoint_sets() == 1 ); // everything should now be connected
700 
701  // finalize
702  bool const success = ft.reorder( ft_root );
703  if ( !success ) {
704  TR.Fatal << "FATAL: fold_tree_from_pose(): " << ft << std::endl;
705  utility_exit_with_message( "bad fold tree topology" );
706  }
707 
708  return ft;
709 }
710 
711 
712 /// @brief merge two fold trees by jump between their roots
713 /// @param[in] left_tree
714 /// @param[in] right_tree
715 /// @return Merged FoldTree with all vertices of right_tree placed to the
716 /// right of vertices in left_tree. Jump labels in right_tree will be
717 /// renumbered += left_tree.num_jump(). New tree is rooted in the same
718 /// place as left_tree.
721  core::kinematics::FoldTree const & left_tree,
722  core::kinematics::FoldTree const & right_tree
723 )
724 {
725  return merge(
726  left_tree, left_tree.root(), std::string(),
727  right_tree, right_tree.root(), std::string(),
728  false
729  );
730 }
731 
732 
733 /// @brief merge two fold trees connecting by jump via specified positions
734 /// @param[in] left_tree
735 /// @param[in] left_position position on left_tree to connect
736 /// @param[in] right_tree
737 /// @param[in] right_position position on right_tree to connect
738 /// @return Merged FoldTree with all vertices of right_tree placed to the
739 /// right of vertices in left_tree. Jump labels in right_tree will be
740 /// renumbered += left_tree.num_jump(). New tree is rooted in the same
741 /// place as left_tree.
744  core::kinematics::FoldTree const & left_tree,
745  core::Size const left_position,
746  core::kinematics::FoldTree const & right_tree,
747  core::Size const right_position
748 )
749 {
750  return merge(
751  left_tree, left_position, std::string(),
752  right_tree, right_position, std::string(),
753  false
754  );
755 }
756 
757 
758 /// @brief merge two fold trees connecting by jump via specified positions
759 /// @param[in] left_tree
760 /// @param[in] left_position position on left_tree to connect
761 /// @param[in] left_jump_atom Use this atom for the left side of the jump.
762 /// Use empty string to indicate default setting.
763 /// @param[in] right_tree
764 /// @param[in] right_position position on right_tree to connect
765 /// @param[in] right_jump_atom Use this atom for the right set of the jump.
766 /// Use empty string to indicate default setting.
767 /// @param[in] keep_stub_in_residue Attempt to keep generated stubs of the
768 /// jump within their respective residues. default False
769 /// @return Merged FoldTree with all vertices of right_tree placed to the
770 /// right of vertices in left_tree. Jump labels in right_tree will be
771 /// renumbered += left_tree.num_jump(). New tree is rooted in the same
772 /// place as left_tree.
775  core::kinematics::FoldTree const & left_tree,
776  core::Size const left_position,
777  std::string const & left_jump_atom,
778  core::kinematics::FoldTree const & right_tree,
779  core::Size const right_position,
780  std::string const & right_jump_atom,
781  bool const keep_stub_in_residue
782 )
783 {
784  using core::Size;
787 
788  assert( left_position <= left_tree.nres() );
789  assert( right_position <= right_tree.nres() );
790 
791  FoldTree new_ft = left_tree;
792 
793  // add all shifted edges from right_tree
794  for ( FoldTree::const_iterator r = right_tree.begin(), re = right_tree.end(); r != re; ++r ) {
795  Edge new_edge = *r;
796  new_edge.start() += left_tree.nres();
797  new_edge.stop() += left_tree.nres();
798  if ( new_edge.label() > 0 ) {
799  new_edge.label() += left_tree.num_jump();
800  }
801  new_ft.add_edge( new_edge );
802  }
803 
804  // compute jump positions
805  Size const jleft = left_position;
806  Size const jright = right_position + left_tree.nres();
807 
808  // split edge originating from left tree
809  if ( !vertex_exists( jleft, new_ft ) ) {
810  FoldTree::const_iterator f = facet_containing_position(
811  jleft,
812  static_cast< FoldTree const & >( new_ft ).begin(),
813  static_cast< FoldTree const & >( new_ft ).end(),
814  Edge::PEPTIDE
815  );
816  assert( f != static_cast< FoldTree const & >( new_ft ).end() ); // paranoia
817 
818  Edge const base = *f;
819  new_ft.delete_edge( base );
820  new_ft.add_edge( base.start(), jleft, base.label() );
821  new_ft.add_edge( jleft, base.stop(), base.label() );
822  }
823 
824  // split edge originating from right tree
825  if ( !vertex_exists( jright, new_ft ) ) {
826  FoldTree::const_iterator f = facet_containing_position(
827  jright,
828  static_cast< FoldTree const & >( new_ft ).begin(),
829  static_cast< FoldTree const & >( new_ft ).end(),
830  Edge::PEPTIDE
831  );
832  assert( f != static_cast< FoldTree const & >( new_ft ).end() ); // paranoia
833 
834  Edge const base = *f;
835  new_ft.delete_edge( base );
836  new_ft.add_edge( base.start(), jright, base.label() );
837  new_ft.add_edge( jright, base.stop(), base.label() );
838  }
839 
840  // add new jump
841  new_ft.add_edge(
842  Edge(
843  jleft, jright,
844  left_tree.num_jump() + right_tree.num_jump() + 1,
845  left_jump_atom, right_jump_atom,
846  keep_stub_in_residue
847  )
848  );
849 
850  // re-root
851  new_ft.reorder( left_tree.root() );
852 
853  return new_ft;
854 }
855 
856 
857 /// @brief replace a section of one fold tree with another fold tree, connecting by
858 /// jump between their roots
859 /// @param[in] original_tree
860 /// @param[in] replace_begin residue starting the section of original_tree to replace
861 /// @param[in] replace_end residue ending the section of original_tree to replace
862 /// @param[in] movemap MoveMap whose fixed backbone positions dictates where new jumps
863 /// may be placed.
864 /// @param[in] replacement_tree
865 /// @return FoldTree with section replaced.
866 /// @remarks The procedure will attempt to honor the MoveMap as much as it can. The caveat
867 /// is that sequences of calls to some FoldTree routines may shift the jumps internally in
868 /// a way that is not easily predictable. If the procedure cannot find an allowed
869 /// residue for a jump, it will make a jump to the median residue in the disconnected
870 /// fold tree interval.
873  core::kinematics::FoldTree const & original_tree,
874  int const replace_begin,
875  int const replace_end,
876  core::kinematics::MoveMap const & movemap,
877  core::kinematics::FoldTree const & replacement_tree
878 )
879 {
880  using core::Size;
885 
887  typedef utility::vector1< Size > NodeList;
888  typedef std::map< Size, NodeList > Root2Nodes;
889 
890  assert( replace_begin <= replace_end );
891  assert( original_tree.root() < replace_begin || original_tree.root() > replace_end );
892 
893  Size const replace_length = replace_end - replace_begin + 1;
894  Size const final_nres = original_tree.nres() - replace_length + replacement_tree.nres();
895  Size const final_ft_root = original_tree.root() < replace_begin ?
896  original_tree.root() :
897  original_tree.root() - replace_length + replacement_tree.nres();
898 
899  // create altered fold tree and delete the section to be replaced
900  FoldTree aft = original_tree;
901  for ( int r = replace_begin; r <= replace_end; ++r ) {
902  aft.delete_seqpos( replace_begin );
903  }
904 
905  TR.Debug << "original_tree: " << original_tree << std::endl;
906  TR.Debug << "aft: " << aft << std::endl;
907 
908  DisjointSets uf( final_nres ); // union-find
909  FoldTree tracking_ft = aft;
910  FoldTree new_ft;
911 
912  // left section
913  for ( FoldTree::const_iterator e = static_cast< FoldTree const & >( aft ).begin(),
914  ee = static_cast< FoldTree const & >( aft ).end(); e != ee; ++e )
915  {
916  if ( e->label() < 0 && e->start() < replace_begin && e->stop() < replace_begin ) {
917  Edge new_edge = *e;
918  order( new_edge ); // for union_interval
919 
920  new_ft.add_edge( new_edge );
921  tracking_ft.delete_edge( *e );
922 
923  union_interval( new_edge.start(), new_edge.start(), new_edge.stop(), uf );
924  }
925  }
926 
927  TR.Debug << "new_ft after left: " << new_ft << std::endl;
928 
929  // right section, shifted to take into account replacement tree
930  for ( FoldTree::const_iterator e = static_cast< FoldTree const & >( aft ).begin(),
931  ee = static_cast< FoldTree const & >( aft ).end(); e != ee; ++e )
932  {
933  if ( e->label() < 0 && e->start() >= replace_begin && e->stop() >= replace_begin ) {
934  Edge new_edge = *e;
935  order( new_edge ); // for union_interval
936  new_edge.start() += replacement_tree.nres();
937  new_edge.stop() += replacement_tree.nres();
938 
939  new_ft.add_edge( new_edge );
940  tracking_ft.delete_edge( *e );
941 
942  union_interval( new_edge.start(), new_edge.start(), new_edge.stop(), uf );
943  }
944  }
945 
946  TR.Debug << "new_ft after right: " << new_ft << std::endl;
947 
948  // jumps
949  for ( FoldTree::const_iterator e = static_cast< FoldTree const & >( aft ).begin(),
950  ee = static_cast< FoldTree const & >( aft ).end(); e != ee; ++e )
951  {
952  if ( e->label() > 0 ) {
953  Edge new_edge = *e;
954 
955  if ( new_edge.start() >= replace_begin ) {
956  new_edge.start() += replacement_tree.nres();
957  }
958 
959  if ( new_edge.stop() >= replace_begin ) {
960  new_edge.stop() += replacement_tree.nres();
961  }
962 
963  new_ft.add_edge( new_edge );
964  tracking_ft.delete_edge( *e );
965 
966  uf.ds_union( new_edge.start(), new_edge.stop() );
967  }
968  }
969 
970  assert( tracking_ft.size() <= 2 );
971 
972  TR.Debug << "new_ft after jump: " << new_ft << std::endl;
973 
974  // run through remaining edges, splitting if necessary
975  for ( FoldTree::const_iterator e = static_cast< FoldTree const & >( tracking_ft ).begin(),
976  ee = static_cast< FoldTree const & >( tracking_ft ).end(); e != ee; ++e )
977  {
978  Edge edge = *e;
979  order( edge ); // for union_interval
980 
981  if ( edge.stop() == replace_begin ) { // on right vertex
982  Edge new_edge = edge;
983  --new_edge.stop();
984 
985  new_ft.add_edge( new_edge );
986 
987  union_interval( new_edge.start(), new_edge.start(), new_edge.stop(), uf );
988 
989  } else if ( edge.start() == replace_begin ) { // on left vertex
990  Edge new_edge = edge;
991  new_edge.start() += replacement_tree.nres();
992  new_edge.stop() += replacement_tree.nres();
993 
994  new_ft.add_edge( new_edge );
995 
996  union_interval( new_edge.start(), new_edge.start(), new_edge.stop(), uf );
997 
998  } else if ( edge.start() < replace_begin ) { // split
999  Edge left_edge = edge;
1000  left_edge.stop() = replace_begin - 1;
1001 
1002  Edge right_edge = edge;
1003  right_edge.start() = replace_begin + replacement_tree.nres();
1004  right_edge.stop() += replacement_tree.nres();
1005 
1006  new_ft.add_edge( left_edge );
1007  new_ft.add_edge( right_edge );
1008 
1009  union_interval( left_edge.start(), left_edge.start(), left_edge.stop(), uf );
1010  union_interval( right_edge.start(), right_edge.start(), right_edge.stop(), uf );
1011  }
1012  }
1013 
1014  // remove any single residue edges that might exist after splitting
1015  new_ft.delete_self_edges();
1016 
1017  TR.Debug << "new_ft after remaining: " << new_ft << std::endl;
1018 
1019  // replacement tree indexing shift
1020  Size const rshift = replace_begin - 1;
1021  Size const jshift = new_ft.num_jump();
1022 
1023  // add edges from replacement tree
1024  for ( FoldTree::const_iterator e = replacement_tree.begin(), ee = replacement_tree.end(); e != ee; ++e ) {
1025  Edge new_edge = *e;
1026  new_edge.start() += rshift;
1027  new_edge.stop() += rshift;
1028  if ( new_edge.label() > 0 ) {
1029  new_edge.label() += jshift;
1030  }
1031 
1032  new_ft.add_edge( new_edge );
1033 
1034  if ( new_edge.label() > 0 ) {
1035  uf.ds_union( new_edge.start(), new_edge.stop() );
1036  } else {
1037  order( new_edge ); // for union_interval
1038  union_interval( new_edge.start(), new_edge.start(), new_edge.stop(), uf );
1039  }
1040  }
1041 
1042  // make new jump from final_ft_root to root of replacement tree
1043  new_ft.add_edge( final_ft_root, replacement_tree.root() + rshift, new_ft.num_jump() + 1 );
1044  uf.ds_union( final_ft_root, replacement_tree.root() + rshift );
1045 
1046  TR.Debug << "new_ft after replacement: " << new_ft << std::endl;
1047 
1048  // construct re-indexed movemap
1049  MoveMap mm;
1050  mm.set_bb_true_range( 1, final_nres );
1051  for ( Size i = 1, ie = original_tree.nres(); i <= ie; ++i ) {
1052  if ( i < static_cast< Size >( replace_begin ) ) {
1053  mm.set_bb( i, movemap.get_bb( i ) );
1054  } else if ( static_cast< Size >( replace_end ) < i ) {
1055  mm.set_bb( i - replace_length + replacement_tree.nres(), movemap.get_bb( i ) );
1056  }
1057  }
1058 
1059  // find disconnected components and make jumps from final_root to an
1060  // allowed residue governed by the MoveMap
1061  Root2Nodes r2n = uf.sets();
1062  for ( Root2Nodes::iterator i = r2n.begin(), ie = r2n.end(); i != ie; ++i ) {
1063  if ( i->first != uf.ds_find( final_ft_root ) ) {
1064  NodeList & nodes = i->second;
1065  NodeList fixed;
1066 
1067  // find all useable fixed positions for jump
1068  for ( NodeList::const_iterator j = nodes.begin(), je = nodes.end(); j != je; ++j ) {
1069  if ( !mm.get_bb( *j ) ) {
1070  fixed.push_back( *j );
1071  }
1072  }
1073 
1074  // new edge
1075  Edge new_edge;
1076  new_edge.start() = final_ft_root;
1077  new_edge.label() = new_ft.num_jump() + 1;
1078 
1079  // add jump
1080  if ( fixed.empty() ) { // problematic case
1081 
1082  // we have no fixed positions, so just add the jump to the
1083  // (lower) median node
1084  std::sort( nodes.begin(), nodes.end() );
1085  if ( nodes.size() % 2 == 1 ) { // median
1086  new_edge.stop() = nodes[ ( nodes.size() + 1 ) / 2 ];
1087  } else { // lower median
1088  new_edge.stop() = nodes[ nodes.size() / 2 ];
1089  }
1090 
1091  } else { // normal case
1092  new_edge.stop() = fixed[ RG.random_range( 1, fixed.size() ) ];
1093  }
1094 
1095  // split existing edge if necessary
1096  FoldTree::const_iterator f_connecting = facet_containing_position(
1097  new_edge.stop(),
1098  static_cast< FoldTree const & >( new_ft ).begin(),
1099  static_cast< FoldTree const & >( new_ft ).end(),
1100  Edge::PEPTIDE
1101  );
1102  if ( f_connecting != static_cast< FoldTree const & >( new_ft ).end() ) {
1103  Edge const connecting_edge = *f_connecting;
1104  new_ft.delete_edge( connecting_edge );
1105  new_ft.add_edge( connecting_edge.start(), new_edge.stop(), connecting_edge.label() );
1106  new_ft.add_edge( connecting_edge.stop(), new_edge.stop(), connecting_edge.label() );
1107  }
1108 
1109  // add to fold tree
1110  new_ft.add_edge( new_edge );
1111 
1112  // add to uf
1113  uf.ds_union( new_edge.start(), new_edge.stop() );
1114 
1115  }
1116  }
1117 
1118  assert( uf.n_disjoint_sets() == 1 );
1119 
1120  TR.Debug << "new_ft after disconnected: " << new_ft << std::endl;
1121 
1122  // finalize
1123  bool const success = new_ft.reorder( final_ft_root );
1124  runtime_assert( success );
1125 
1126  return new_ft;
1127 }
1128 
1129 // set up star foldtree for special manipulation
1131  core::pose::Pose & pose,
1132  //core::kinematics::MoveMap & mm,
1133  protocols::loops::Loops loops ) {
1134  using namespace core::chemical;
1135  using namespace core::kinematics;
1136 
1137  core::Size nres = pose.total_residue()-1;
1139 
1140  core::Size prev_cut = 0, this_cut, out_midpt;
1141  int njump =1 ;
1142  for ( core::Size i=1; i <= loops.size(); ++i ) {
1143  core::Size loop_start = loops[i].start() ;
1144  core::Size loop_end = loops[i].stop() -1 ; // special case to treat loop objects as definition of a cut and not a real range. only use this for two chain tree!
1145 
1146  bool start_is_cut = pose.fold_tree().is_cutpoint( loop_start-1 );
1147  bool end_is_cut = pose.fold_tree().is_cutpoint( loop_end );
1148 
1149  if ( loop_start == 1) continue;
1150  if ( loop_end == nres) continue;
1151 
1152  /// some really weird cases
1153  if ( start_is_cut && !end_is_cut && prev_cut == loop_start-1 )
1154  continue;
1155  if ( start_is_cut && end_is_cut && prev_cut != loop_start-1 ) {
1156  // need to add two cuts for this loop
1157  this_cut = loop_start-1;
1158  //out_midpt = (prev_cut + this_cut+1)/4;
1159  out_midpt = prev_cut +1; // try to root the jump at beginning
1160  newF.add_edge( nres+1, out_midpt, njump );
1161  if (out_midpt != prev_cut+1)
1162  newF.add_edge( out_midpt, prev_cut+1, Edge::PEPTIDE );
1163  if (out_midpt != this_cut)
1164  newF.add_edge( out_midpt, this_cut , Edge::PEPTIDE );
1165  prev_cut = this_cut;
1166 
1167  njump++;
1168  }
1169 
1170  if ( start_is_cut && !end_is_cut && prev_cut != loop_start-1 )
1171  this_cut = loop_start-1;
1172  else if ( end_is_cut )
1173  this_cut = loop_end;
1174  else
1175  this_cut = loops[i].cut();
1176 
1177  //out_midpt = (prev_cut + this_cut+1)/2;
1178  out_midpt = prev_cut + 1; //try to root the jump at beginning.
1179 
1180  if ( !start_is_cut && !end_is_cut ) {
1183  }
1184  newF.add_edge( nres+1, out_midpt, njump );
1185  if (out_midpt != prev_cut+1)
1186  newF.add_edge( out_midpt, prev_cut+1, Edge::PEPTIDE );
1187  if (out_midpt != this_cut)
1188  newF.add_edge( out_midpt, this_cut , Edge::PEPTIDE );
1189  TR << "add edge " << njump << " : " << prev_cut+1 << "..." << out_midpt << "..." << this_cut << std::endl;
1190 
1191  njump++;
1192  prev_cut = this_cut;
1193  }
1194 
1195  // c term
1196  if (prev_cut != nres) {
1197  out_midpt = (prev_cut + nres+1)/2;
1198  newF.add_edge( prev_cut+1, nres+1, njump );
1199  newF.add_edge( prev_cut+1, nres , Edge::PEPTIDE );
1200  TR << "add edge " << njump << " : " << prev_cut+1 << "..." << out_midpt << "..." << nres << std::endl;
1201  }
1202 
1203  newF.reorder( nres+1 ); // root the tree on the VRT res
1204  TR << newF << std::endl;
1205  pose.fold_tree( newF );
1206 }
1207 
1208 void jumps_and_cuts_from_pose( core::pose::Pose & pose, utility::vector1< std::pair<core::Size, core::Size > > & jumps, utility::vector1< core::Size > & cuts){
1209 
1210  core::kinematics::FoldTree f_orig = pose.fold_tree();
1211 
1212  for ( core::Size i = 1; i<= f_orig.num_jump(); ++i ) {
1213  core::Size down ( f_orig.downstream_jump_residue(i) );
1214  core::Size up ( f_orig.upstream_jump_residue(i) );
1215  jumps.push_back( std::pair<int,int>( down, up ) );
1216  }
1217  cuts = f_orig.cutpoints();
1218 }
1219 
1220 
1221 } // methods
1222 } // forge
1223 } // protocols