Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
FoldTree.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 core/kinematics/FoldTree.cc
11 /// @brief Fold tree class
12 /// @author Phil Bradley
13 
14 // Unit headers
16 
17 // Rosetta Headers
18 #include <core/kinematics/util.hh>
20 #include <basic/Tracer.hh>
21 
22 // Utility Headers
23 #include <utility/exit.hh>
24 #include <utility/PyAssert.hh>
25 
26 // Third-party Headers
27 #include <boost/functional/hash.hpp>
28 
29 // ObjexxFCL formating
30 #include <ObjexxFCL/format.hh>
31 #include <ObjexxFCL/string.functions.hh>
32 
33 // C++ Headers
34 #include <algorithm>
35 // AUTO-REMOVED #include <iostream>
36 #include <list>
37 #include <sstream>
38 #include <string>
39 #include <iostream>
40 
41 using namespace ObjexxFCL;
42 using namespace ObjexxFCL::fmt;
43 
44 static basic::Tracer TR("core.kinematics.FoldTree");
45 
46 namespace core {
47 namespace kinematics {
48 
49 // @brief Auto-generated virtual destructor
50 FoldTree::~FoldTree() {}
51 
52 
53 ///////////////////////////////////////////////////////////////////////
54 // ensure that stored data depending on the topology are up-to-date
55 // modifications by add_edge, delete_edge, reorder, etcetc
56 // are indicated by setting new_topology and/or new_order to true
57 
58 ///////////////////////////////////////////////////////////////////////////////
59 /// @details Checks that edges are in the same order and are equal
60 bool
62  FoldTree const & a,
63  FoldTree const & b
64 )
65 {
66  if ( a.edge_list_.size() != b.edge_list_.size() ) return false;
68  edge_a( a.edge_list_.begin() ), a_end( a.edge_list_.end() ),
69  edge_b( b.edge_list_.begin() );
70  edge_a != a_end; ++edge_a, ++edge_b ) {
71  if ( *edge_a != *edge_b ) return false;
72  }
73  return true;
74 }
75 
76 bool operator!=(const FoldTree& a, const FoldTree& b) {
77  return !(a == b);
78 }
79 
80 // @details Computes a fixed-length, hash-based identifier for this FoldTree,
81 // permitting efficient comparison of a pair of FoldTrees. The need for this
82 // functionality arose from a desire to reuse an object that was unaware of
83 // changes to the FoldTree. Rather than perform a costly deep comparison by
84 // evaluating edge lists, we wanted a simple method for quickly testing
85 // whether the naive object should be reinstantiated. This method is most
86 // useful in situations where there are many edges in the FoldTree.
87 size_t FoldTree::hash_value() const {
88  using std::string;
89  using std::stringstream;
90 
91  // obtain a string representation of the FoldTree
92  string repr;
93  stringstream ss;
94  ss << this;
95  repr = ss.str();
96 
97  // compute hash(repr)
98  return hasher(repr);
99 }
100 
101 /// @details Delete self-edges in the foldtree, allowing the edge 1->1 for a single residue tree
102 
103 void
104 FoldTree::delete_self_edges()
105 {
106  if ( edge_list_.size() <= 1 ) return;
107 
108  utility::vector1< Edge > delete_me;
109 
110  for ( iterator it = edge_list_.begin(), ite = edge_list_.end(); it != ite; ++it ) {
111  if ( it->start() == it->stop() ) delete_me.push_back( *it );
112  }
113 
114  if ( !delete_me.empty() ) {
115  for ( Size i=1; i<= delete_me.size(); ++i ) {
116  delete_edge( delete_me[i] );
117  }
118  new_topology = true;
119  }
120 }
121 
122 
123 /// @details Delete a sequence position from a foldtree. If the residue is a jump point or the root of the tree,
124 /// we will have to rearrange the topology.
125 
126 
127 void
128 FoldTree::delete_seqpos( int const seqpos )
129 {
130  PyAssert( (seqpos>0) && (seqpos<=nres()), "FoldTree::delete_seqpos( int const seqpos ): input variable seqpos has a meaningless value");
131  if ( is_jump_point( seqpos ) || is_root( seqpos ) ) {
132  delete_jump_seqpos( seqpos );
133  } else {
134  delete_seqpos_simple( seqpos );
135  }
136 }
137 
138 /// @details Useful for removing a loop modeling jump+cut
139 /// @note This will trigger a renumbering of the jumps if jump_number < num_jump()
140 void
141 FoldTree::delete_jump_and_intervening_cutpoint( int const jump_number )
142 {
143  delete_jump_and_intervening_cutpoint( jump_point(1,jump_number), jump_point(2,jump_number) );
144 }
145 
146 /// @details Useful for removing a loop modeling jump+cut
147 /// @note This will trigger a renumbering of the jumps if jump number < num_jump()
148 void
149 FoldTree::delete_jump_and_intervening_cutpoint( int jump_begin, int jump_end )
150 {
151  PyAssert( (jump_begin>0) && (jump_begin<=num_jump()), "FoldTree::delete_jump_and_intervening_cutpoint( int jump_begin , int jump_end ): input variable jump_begin has a meaningless value");
152  PyAssert( (jump_end>0) && (jump_end<=num_jump()), "FoldTree::delete_jump_and_intervening_cutpoint( int jump_begin , int jump_end ): input variable jump_end has a meaningless value");
153 // PyAssert( is_jump_point( jump_begin ) && is_jump_point( jump_end ), 'FoldTree::delete_jump_and_intervening_cutpoint( int jump_begin , int jump_end ): input variables are not jump points');
154  assert( is_jump_point( jump_begin ) && is_jump_point( jump_end ) );
155 
156  if ( jump_begin > jump_end ) {
157  int tmp( jump_begin );
158  jump_begin = jump_end;
159  jump_end = tmp;
160  }
161 
162  Size const old_num_jump( num_jump() );
163  Size const old_root( root() );
164  Size jump_number(0);
165 
166  for ( Size i=1; i<= old_num_jump; ++i ) {
167  if ( jump_point(1,i) == jump_begin && jump_point(2,i) == jump_end ) jump_number = i;
168  }
169  assert( jump_number ); // will fail if there's no jump between jump_begin and jump_end
170 
171  // look for a cutpoint between
172  Size cut(0);
173  for ( int i=jump_begin; i<= jump_end-1; ++i ) {
174  if ( is_cutpoint( i ) ) {
175  if ( cut ) utility_exit_with_message( "multiple cutpoints between jump positions!" );
176  cut = i;
177  }
178  }
179  assert( cut );
180 
181  add_edge( cut, cut+1, Edge::PEPTIDE );
182  delete_unordered_edge( jump_begin, jump_end, jump_number );
183 
184  if ( jump_number < old_num_jump ) {
185  TR << "delete_jump_and_intervening_cutpoint: renumbering the remaining jumps!" << std::endl;
186  for ( iterator it=begin(); it!= end(); ++it ) {
187  if ( it->is_jump() && (Size)(it->label()) > jump_number ) it->label() = it->label() - 1;
188  }
189  }
190 
191  delete_extra_vertices();
192  reorder( old_root );
193  assert( check_fold_tree() );
194 
195 }
196 
197 
198 /// @details Slide a cutpoint from one position to another.
199 void
200 FoldTree::slide_cutpoint( Size const current_cut, Size const target_cut )
201 {
202  assert( is_cutpoint( current_cut ) && !is_cutpoint( target_cut ) );
203  PyAssert( (is_cutpoint( current_cut )) && (!is_cutpoint( target_cut )), "FoldTree::slide_cutpoint( Size const current_cut , Size const target_cut ): input variable current_cut or target_cut has a meaningless value");
204  Size const current_root( root() );
205 
206  TR.Trace << "slide_cutpoint: current= "<< current_cut << " target= " << target_cut << ' ' << *this;
207  add_vertex( target_cut );
208  add_vertex( target_cut+1 );
209  add_edge( current_cut, current_cut+1, Edge::PEPTIDE );
210  delete_unordered_edge( target_cut, target_cut+1, Edge::PEPTIDE );
211  reorder( current_root );
212  delete_extra_vertices();
213  delete_self_edges();
214  assert( check_fold_tree() );
215  TR.Trace << "slide_cutpoint: final tree= " << *this;
216 }
217 
218 /// @details Switches a given jump to connect two different residues.
219 void
220 FoldTree::slide_jump( Size const jump_number, Size const new_res1, Size const new_res2 )
221 {
222  TR.Debug << "slide_jump: starting tree= " << *this;
223  Edge const old_jump_edge( jump_edge( jump_number ) );
224 
225  Size const pos1( std::min( new_res1, new_res2 ) );
226  Size const pos2( std::max( new_res1, new_res2 ) );
227  utility::vector1< Edge > new_edges, remove_edges;
228  for( iterator it=begin(); it!=end(); ++it ){
229  core::Size const start( (core::Size)it->start() );
230  core::Size const stop( (core::Size)it->stop() );
231  if( it->label() != Edge::PEPTIDE ) continue;
232  if( (start <= pos1 && stop >= pos1) || (stop <= pos1 && start >= pos1) ) { // edges not always in sequential order (eg - jump in middle of chain)
233  //TR.Debug << "start-pos1-stop " << start <<" " << pos1 << " " << stop << std::endl;
234  new_edges.push_back( Edge( start, pos1, Edge::PEPTIDE ) );
235  new_edges.push_back( Edge( pos1, stop, Edge::PEPTIDE ) );
236  remove_edges.push_back( *it );
237  }
238  if( (start <= pos2 && stop >= pos2) || (stop <= pos2 && start >= pos2) ) {
239  //TR.Debug << "start-pos2-stop " << start <<" " << pos2 << " " << stop << std::endl;
240  new_edges.push_back( Edge( start, pos2, Edge::PEPTIDE ) );
241  new_edges.push_back( Edge( pos2, stop, Edge::PEPTIDE ) );
242  remove_edges.push_back( *it );
243  }
244  }
245  for( utility::vector1< Edge >::iterator it=remove_edges.begin(); it!=remove_edges.end(); ++it ) {
246  delete_edge( *it );
247  }
248  for( utility::vector1< Edge >::iterator it=new_edges.begin(); it!=new_edges.end(); ++it ) {
249  add_edge( *it );
250  }
251 
252  Edge const new_jump_edge( pos1, pos2, jump_number );
253  delete_edge( old_jump_edge );
254  add_edge( new_jump_edge );
255  delete_extra_vertices();
256  delete_self_edges();
257  TR.Debug << "slide_jump: final tree= " << *this;
258 }
259 
260 /// @details Delete a position from the foldtree that is either a jump_point or the root. Will require some
261 /// rearranging of the topology.
262 /// LOGIC: note that there are 0 or 1 incoming edges to this vertex
263 /// need a replacement vertex for edges involving this guy: (note that this number will have to be adjusted)
264 /// I. if seqpos is polymer residue (ie contained in a polymer edge)
265 /// 1. if there's an incoming polymer segment, choose the previous rsd in this segment
266 /// 2. choose the next residue in the first outgoing polymer edge
267 /// II. if there's an incoming edge, choose the start of this edge
268 /// III. (non-polymer root residue) choose stop of first edge in foldtree
269 ///
270 
271 void
272 FoldTree::delete_jump_seqpos( int const seqpos )
273 {
274 
275  TR.Trace << "delete_jump_seqpos: " << seqpos << ' ' << *this << std::endl;
276 
277  Size const old_nres( nres() );
278  assert( is_jump_point( seqpos ) || is_root( seqpos ) );
279  PyAssert( ( is_jump_point( seqpos )) || ( is_root( seqpos ) ), "FoldTree::delete_jump_seqpos( int const seqpos): input variable seqpos has a meaningless value");
280 
281  /// this could confuse us
282  delete_self_edges();
283 
284  /// 1st order of business: determine the replacement vertex for this guy
285  Edge incoming_edge;
286  utility::vector1< Edge > outgoing_edges, outgoing_polymer_edges;
287 
288  for ( const_iterator it = begin(), ite = end(); it != ite; ++it ) {
289  if ( it->stop() == seqpos ) incoming_edge = *it;
290  else if ( it->start() == seqpos ) {
291  outgoing_edges.push_back( *it );
292  if ( it->is_polymer() ) {
293  outgoing_polymer_edges.push_back( *it );
294  }
295  }
296  }
297 
298  bool const is_root_rsd( is_root( seqpos ) );
299  assert( is_root_rsd == !incoming_edge.valid() );
300  bool const is_polymer_rsd( ( !is_root_rsd && incoming_edge.is_polymer() ) || !outgoing_polymer_edges.empty());
301 
302  Size new_seqpos( 0 ), deleted_jump_number( 0 );
303  if ( is_polymer_rsd ) {
304  if ( !is_root_rsd && incoming_edge.is_polymer() ) {
305  // case I.1 (see comments at start)
306  assert( incoming_edge.stop() == seqpos );
307  new_seqpos = seqpos - incoming_edge.polymer_direction();
308  } else {
309  // case I.2
310  Edge const & e( outgoing_polymer_edges.front() );
311  new_seqpos = seqpos + e.polymer_direction();
312  }
313  } else {
314  if ( is_root_rsd ) {
315  // case III
316  new_seqpos = begin()->stop();
317  if ( begin()->is_jump() ) deleted_jump_number = begin()->label();
318  } else {
319  // case II
320  new_seqpos = incoming_edge.start();
321  if ( incoming_edge.is_jump() ) deleted_jump_number = incoming_edge.label();
322  }
323  }
324  assert( new_seqpos );
325 
326  /// NO MODIFICATIONS TO THE TOPOLOGY OR ORDER OF THE TREE UP TO THIS POINT (except for delete_self_edges at start) ///
327  Size const old_num_jump( num_jump() );
328  if ( deleted_jump_number && deleted_jump_number != old_num_jump ) {
329  // have to relabel
330  TR.Info << "delete_jump_seqpos: deleting jump " << deleted_jump_number << std::endl;
331  TR.Info << "delete_jump_seqpos: renumbering jump " << old_num_jump << " to " << deleted_jump_number << std::endl;
332  jump_edge( old_num_jump ).label() = deleted_jump_number;
333  jump_edge( deleted_jump_number ).label() = old_num_jump;
334  new_topology = true;
335  }
336 
337  /// now remap the edges that contain seqpos
338  for ( iterator it = begin(), ite = end(); it != ite; ++it ) {
339  if ( it->stop() == seqpos ) it->stop() = new_seqpos;
340  else if ( it->start() == seqpos ) it->start() = new_seqpos;
341  }
342  new_topology = true;
343 
344  /// delete the edges with start == stop after removing seqpos
345  delete_self_edges();
346 
347  /// now adjust the sequence numbering of all edges to reflect deletion of seqpos
348  id::SequenceMapping old2new( id::SequenceMapping::identity( old_nres ) );
349  old2new.delete_target_residue( seqpos );
350 
351  apply_sequence_mapping( old2new );
352 
353  // special case
354  if ( edge_list_.size() == 1 && begin()->is_jump() &&
355  begin()->start() == begin()->stop() ) {
356  edge_list_.clear();
357  edge_list_.push_back( Edge( 1, 1, Edge::PEPTIDE ) );
358  new_topology = true;
359  }
360 
361  assert( check_fold_tree() );
362 
363  TR.Trace << "delete_jump_seqpos: after " << seqpos << ' ' << new_seqpos << *this << std::endl;
364 }
365 
366 /// @details Get the number of the jump that builds (connects to) a given residue
367 int
368 FoldTree::get_jump_that_builds_residue( int const seqpos ) const
369 {
370  check_topology();
371  Edge const & edge( get_residue_edge( seqpos ) );
372  if ( !edge.is_jump() ) utility_exit_with_message( "get_jump_that_builds_residue: not build by a jump!" );
373  return edge.label();
374 }
375 
376 /// @details Delete a sequence position from a foldtree. This will not work
377 /// at positions that are jump points, ie start or stop vertices for jump edges. (or the root of the tree!)
378 /// So basically only works for polymer residues.
379 
380 void
381 FoldTree::delete_seqpos_simple( int const seqpos )
382 {
383  TR.Trace << "delete_seqpos_simple: before " << seqpos << ' ' << *this << std::endl;
384  assert( !is_jump_point( seqpos ) && !is_root( seqpos ) );
385 
386  Size const old_nres( nres() );
387 
388  /// always a good idea for safety
389  delete_self_edges();
390 
391  /// first remap the edge (if it exists) that contains seqpos as a vertex
392  /// do this before renumbering everything
393  for ( iterator it = begin(), ite = end(); it != ite; ++it ) {
394  assert( it->start() != seqpos );
395  if ( it->stop() == seqpos ) {
396  assert( it->is_polymer() );
397  it->stop() = it->stop() - it->polymer_direction();
398  new_topology = true;
399  break; // there should be only one incoming edge
400  }
401  }
402 
403  /// now adjust the sequence numbering of all edges to reflect deletion of seqpos
404  id::SequenceMapping old2new( id::SequenceMapping::identity( old_nres ) );
405  old2new.delete_target_residue( seqpos ); assert( !old2new[ seqpos ] );
406 
407  apply_sequence_mapping( old2new );
408 
409  /// they may have been introduced
410  delete_self_edges();
411 
412  /// sanity
413  assert( check_fold_tree() );
414 
415  TR.Trace << "delete_seqpos_simple: after " << seqpos << ' ' << *this << std::endl;
416 }
417 
418 
419 /// @details Renumber all vertices according to an input sequence mapping
420 void
422 {
423 
424  for ( iterator it = begin(); it != end(); ++it ) {
425  it->start() = old2new[ it->start() ];
426  it->stop () = old2new[ it->stop () ];
427  }
428 
429  new_topology = true;
430 }
431 
432 
433 
434 /////////////////////////////////////////////////////////////////////////////
435 //
436 // the residue at position seqpos moves to position seqpos+1
437 //
438 // vertices remapped, only question is cutpoint at seqpos-1, should it move to seqpos?
439 //
440 /// @details (ie between current rsds seqpos-1 and seqpos, so that the sequence position of the new residue is seqpos)
441 /// if seqpos-1 is a cutpoint in the current fold_tree -- we have a choice about how to connect the new
442 /// residue: it could be joined to the preceding peptide segment (join to seqpos-1) or to the following
443 /// segment (joined to the residue currently at seqpos). join_upper and join_lower control the behavior in
444 /// this case.
445 ///
446 /// @note seqpos may be greater than current nres, ie we may be "inserting" at end
447 ///
448 void
449 FoldTree::insert_polymer_residue(
450  int const seqpos,
451  bool const join_lower,
452  bool const join_upper
453 )
454 {
455  int const old_size( nres() );
456  utility::vector1< int > old2new( old_size, 0 );
457  for ( int i=1; i<= old_size; ++i ) {
458  if ( i<seqpos ) old2new[i] = i;
459  else old2new[i] = i+1;
460  }
461 
462  // this is the only case where we actually need to know join_lower and join_upper,
463  // since in this case we have a choice of how to attach the new residue
464  bool const special_case( is_cutpoint( seqpos -1 ) );
465 
466  // in either of these cases we actually need to add a new edge to the tree, since we are gluing
467  // to a jump_point at a cutpoint, which means that there's no polymer edge extending in our
468  // direction yet
469  bool const seqpos_minus_1_is_vertex( seqpos > 1 && (is_jump_point( seqpos-1 ) || is_root(seqpos-1)));
470  bool const seqpos_is_vertex ( seqpos <= old_size && (is_jump_point( seqpos ) || is_root(seqpos)));
471  bool add_edge_lower( special_case && join_lower && seqpos_minus_1_is_vertex );
472  bool add_edge_upper( special_case && join_upper && seqpos_is_vertex );
473 
474  for ( iterator it = edge_list_.begin(), ite = edge_list_.end(); it != ite; ++it ) {
475  it->start() = old2new[ it->start() ];
476 
477  if ( special_case ) {
478  if ( join_lower && it->is_polymer() && it->stop() == seqpos - 1 && !seqpos_minus_1_is_vertex ) {
479  it->stop() = seqpos; // extend this segment to include seqpos
480  assert( !add_edge_lower );
481  continue;
482  }
483  if ( join_upper && it->is_polymer() && it->stop() == seqpos && !seqpos_is_vertex ) {
484  // dont remap seqpos to seqpos+1 as we would otherwise do, thereby extending this peptide edge to include seqpos
485  assert( !add_edge_upper );
486  continue;
487  }
488  }
489 
490  it->stop () = old2new[ it->stop () ];
491  }
492 
493  new_topology = true;
494 
495  if ( add_edge_lower ) {
496  add_edge( seqpos-1, seqpos, Edge::PEPTIDE );
497  } else if ( add_edge_upper ) {
498  add_edge( seqpos+1, seqpos, Edge::PEPTIDE );
499  }
500 
501  assert( join_lower == !is_cutpoint( seqpos-1 ) && join_upper == !is_cutpoint( seqpos ) );
502 }
503 
504 
505 /////////////////////////////////////////////////////////////////////////////
506 /// @details Insert a new residue into the tree at position seqpos, anchoring it
507 /// to the rest of the tree by a jump
508 ///
509 /// the residue at position seqpos moves to position seqpos+1
510 ///
511 /// vertices remapped, only question is cutpoint at seqpos-1, should it move to seqpos?
512 ///
513 
514 void
515 FoldTree::insert_residue_by_jump(
516  int const seqpos,
517  int anchor_pos, // in the current numbering system
518  std::string const& anchor_atom, // = 0
519  std::string const& root_atom // = 0
520 )
521 {
522  assert( is_cutpoint( seqpos - 1 ) );
523  int const old_size( nres() );
524  int const new_jump_number( num_jump() + 1 );
525 
526  utility::vector1< int > old2new( old_size, 0 );
527  for ( int i=1; i<= old_size; ++i ) {
528  if ( i<seqpos ) old2new[i] = i;
529  else old2new[i] = i+1;
530  }
531  anchor_pos = old2new[ anchor_pos ];
532 
533  for ( iterator it = edge_list_.begin(), ite = edge_list_.end(); it != ite; ++it ) {
534  it->start() = old2new[ it->start() ];
535  it->stop () = old2new[ it->stop () ];
536  }
537 
538  add_edge( anchor_pos, seqpos, new_jump_number );
539  assert( check_fold_tree() );
540  new_topology = true;
541  if ( anchor_atom.size() ) {
542  assert( root_atom.size() );
543  set_jump_atoms( new_jump_number, anchor_atom, root_atom );
544  }
545 }
546 
547 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
548 /// @details Insert another fold_tree as a subtree. Residues are inserted as a contiguous block beginning at
549 /// insert_seqpos. Jumps are inserted as a contiguous block beginning at insert_jumppos.
550 /// Note that insert_seqpos could be equal to nres()+1, ie subtree is being appended at the end.
551 /// The jump anchoring subtree runs from the residue currently numbered "anchor_pos" to the residue
552 /// insert_seqpos + subtree.root() - 1, and has label/number anchor_jump_number
553 ///
554 void
555 FoldTree::insert_fold_tree_by_jump(
556  FoldTree const & subtree,
557  int const insert_seqpos, // rsd 1 in subtree goes here
558  int const insert_jumppos, // jump 1 in subtree goes here
559  int const anchor_pos, // in the old numbering system
560  int anchor_jump_number, // in the new jump numbering system, default=0
561  std::string const & anchor_atom, // could be ""
562  std::string const & root_atom // ditto
563 )
564 {
565 
566  if ( !is_cutpoint( anchor_pos -1 ) && !is_cutpoint( anchor_pos ) ) {
567  TR.Warning << "insert_fold_tree_by_jump: anchor_pos is not a vertex of the tree!! anchor_pos= " << anchor_pos <<
568  std::endl;
569  TR.Warning << "*this= " << *this << "Adding anchor_pos as a new vertex!" << std::endl;
570  add_vertex( anchor_pos );
571  }
572 
573  int const old_nres( nres() );
574  int const old_njump( num_jump() );
575  int const insert_nres( subtree.nres() );
576  int const insert_njump( subtree.num_jump() );
577  int const new_njump( old_njump + insert_njump + 1 );
578  if ( !anchor_jump_number ) anchor_jump_number = new_njump; // put the anchor_jump at the end
579 
580  TR.Trace << "insert_fold_tree_by_jump: insert_seqpos= " << insert_seqpos << " insert_jumppos= " << insert_jumppos <<
581  " anchor_pos= " << anchor_pos << " anchor_jump_number= " << anchor_jump_number <<
582  " old_nres= " << old_nres << " old_njump= " << old_njump <<
583  " insert_nres= " << insert_nres << " insert_njump= " << insert_njump << std::endl;
584 
585  TR.Trace << "insert_fold_tree_by_jump: old_fold_tree: " << *this;
586  TR.Trace << "insert_fold_tree_by_jump: subtree: " << subtree;
587 
588  utility::vector1< int > old2new_res ( old_nres , 0 );
589  utility::vector1< int > old2new_jump( old_njump, 0 );
590  for ( int i=1; i<= old_nres; ++i ) {
591  if ( i < insert_seqpos ) old2new_res[ i ] = i;
592  else old2new_res[ i ] = i+insert_nres;
593  }
594  if ( anchor_jump_number >= insert_jumppos && anchor_jump_number < insert_jumppos + insert_njump ) {
595  utility_exit_with_message("anchor_jump_number cant fall within the range of inserted jumps!");
596  }
597  /// for debugging
598  utility::vector1< bool > labeled( new_njump, false );
599  labeled[ anchor_jump_number ] = true;
600  for ( int i= insert_jumppos; i< insert_jumppos+insert_njump; ++i ) labeled[i] = true;
601  for ( int i=1; i<= old_njump; ++i ) {
602  int o2n( i < insert_jumppos ? i : i+insert_njump );
603  if ( o2n >= anchor_jump_number ) ++o2n;
604  if ( o2n >= insert_jumppos && o2n < insert_jumppos+insert_njump ) o2n = insert_jumppos + insert_njump;
605  assert( !labeled[ o2n ] );
606  labeled[ o2n ] = true;
607  old2new_jump[ i ] = o2n;
608  }
609 
610  // remap the numbers of our edges
611  for ( iterator it = edge_list_.begin(), ite = edge_list_.end(); it != ite; ++it ) {
612  it->start() = old2new_res[ it->start() ];
613  it->stop () = old2new_res[ it->stop () ];
614  if ( it->is_jump() ) {
615  it->label() = old2new_jump[ it->label() ];
616  }
617  }
618 
619  // add the anchoring jump
620  int const root_pos( subtree.root() + insert_seqpos - 1 );
621  edge_list_.push_back( Edge( old2new_res[ anchor_pos ], root_pos, anchor_jump_number ) );
622 
623  // now append the edges from subtree
624  for ( const_iterator it= subtree.begin(); it != subtree.end(); ++it ) {
625  Edge new_edge( *it );
626  new_edge.start() = new_edge.start() + insert_seqpos-1;
627  new_edge.stop () = new_edge.stop () + insert_seqpos-1;
628  if ( new_edge.is_jump() ) new_edge.label() = new_edge.label() + insert_jumppos-1;
629 
630  edge_list_.push_back( new_edge );
631  }
632 
633  new_topology = true;
634 
635  if ( anchor_atom.size() ) {
636  assert( root_atom.size() );
637  set_jump_atoms( anchor_jump_number, anchor_atom, root_atom );
638  }
639 
640  TR.Trace << "insert_fold_tree_by_jump: new fold_tree: " << *this;
641  assert( check_fold_tree() );
642 
643 }
644 
645 
646 /////////////////////////////////////////////////////////////////////////////
647 /// @details Add a new residue -- either polymer or jump -- to the end of the tree
648 /// if the new residue is appended by polymer connection, add it at the end of polymer.
649 /// if the new residue is appended by jump connection, the cutpoint is the original polymer end
650 void
651 FoldTree::append_residue(
652  bool const attach_by_jump, // = false,
653  int const jump_anchor_residue, // = 0,
654  std::string const& jump_upstream_atom, // = "",
655  std::string const& jump_downstream_atom // = ""
656 )
657 {
658 
659  // NOTE -- all public method calls, no worries about data being
660  // up to date
661 
662  int const old_nres( nres() );
663 
664  // add a new edge (maybe temporary)
665  add_edge( old_nres, old_nres+1, Edge::PEPTIDE );
666 
667  if ( old_nres == 1 ) delete_self_edges();
668 
669  if ( attach_by_jump ) {
670  new_jump( jump_anchor_residue, old_nres + 1, old_nres );
671  if ( jump_upstream_atom.size() ) {
672  set_jump_atoms( num_jump(), jump_upstream_atom, jump_downstream_atom );
673  }
674  } else {
675  delete_extra_vertices();
676  }
677 }
678 
679 //////////////////////////////////////////////////////////////////////
680 void
681 FoldTree::append_residue_by_chemical_bond(
682  int const anchor_residue,
683  std::string const& anchor_atom,
684  std::string const& root_atom
685 )
686 {
687  int const old_nres( nres() );
688 
689  // chemical edge constructor
690  add_edge( Edge( anchor_residue, old_nres+1, anchor_atom, root_atom ) );
691 
692  new_topology = true;
693 
694  assert( is_cutpoint( old_nres ) );
695 }
696 
697 
698 /////////////////////////////////////////////////////////////////////////////
699 /// @details
700 /// do not allow self edge and do not order the edge list here
701 void
702 FoldTree::add_edge(
703  int const start,
704  int const stop,
705  int const label
706 )
707 {
708  // jump out if self-edge, exception: a one residue pose (happens at setup of pdb-read)
709  if ( start == stop && !( start == 1 && edge_list_.empty() ) ) return;
710 
711  new_topology = true; // book-keeping
712  edge_list_.push_back( Edge( start, stop, label ) );
713 }
714 //@details This 'add_edge' calls the edge constructor with the same args and is
715 //used to form chemical edges.
716 void
717 FoldTree::add_edge(
718  int const start,
719  int const stop,
720  std::string const & start_atom,
721  std::string const & stop_atom
722 )
723 {
724  // jump out if self-edge, exception: a one residue pose (happens at setup of pdb-read)
725  if ( start == stop && !( start == 1 && edge_list_.empty() ) ) return;
726  new_topology = true; // book-keeping
727  edge_list_.push_back( Edge( start, stop, start_atom, stop_atom ) );
728 }
729 
730 
731 /////////////////////////////////////////////////////////////////////////////
732 /// @details Does not ensure proper folding order
733 void
734 FoldTree::add_edge(
735  Edge const & new_edge
736 )
737 {
738  new_topology = true; // book-keeping
739  edge_list_.push_back( new_edge );
740 }
741 
742 
743 /////////////////////////////////////////////////////////////////////////////
744 /// @details
745 /// die if the iterator is out of range
746 void
747 FoldTree::delete_edge( FoldTree::iterator edge )
748 {
749  new_topology = true; // book-keeping
750  if ( edge < edge_list_.begin() || edge >= edge_list_.end() ) {
751  TR.Fatal << "FoldTree::delete_edge(...) edge not contained in edge_list_." << std::endl;
752  utility_exit();
753  }
754  edge_list_.erase( edge );
755 }
756 
757 /////////////////////////////////////////////////////////////////////////////
758 /// @details
759 void
760 FoldTree::delete_edge( Edge const & edge )
761 {
762  delete_unordered_edge( edge.start(), edge.stop(), edge.label() );
763 }
764 
765 /////////////////////////////////////////////////////////////////////////////
766 /// @details
767 /// needs to match start residue number, end residue number and label index.
768 /// abort if the edge is not found.
769 void
770 FoldTree::delete_unordered_edge(
771  int const start,
772  int const stop,
773  int const label
774 )
775 {
776  new_topology = true;
777  bool found(false);
778  for ( FoldTree::iterator it=edge_list_.begin(), it_end=edge_list_.end();
779  it != it_end; ++it ) {
780  if ( it->label() == label &&
781  ( ( it->start() == start && it->stop() == stop ) ||
782  ( it->start() == stop && it->stop() == start ) ) ) {
783  edge_list_.erase( it );
784  found = true;
785  break;
786  }
787  }
788  if ( !found ) {
789  TR.Fatal << "FoldTree::delete_unordered_edge(...) edge not in tree: " <<
790  ' ' << start << ' ' << stop << ' ' << label << std::endl;
791  TR.Fatal << *this;
792  utility_exit();
793  }
794 }
795 
796 
797 //////////////////////////////////////////////////////////////////
798 /// @details
799 /// it assumes that the segment is completely contained in a single edge
800 /// of the tree. Only edge_list is updated and new topology is set true.
801 /// No derived data is updated.
802 void
803 FoldTree::delete_segment(
804  int const seg_begin,
805  int const seg_end
806 )
807 {
808  int const n2c(1), c2n(-1);
809 
810  TR.Info << "FoldTree::delete_segment: " << seg_begin << ' ' <<
811  seg_end << std::endl;
812 
813  int const size( seg_end - seg_begin + 1 );
814 
815  FArray1D_int mapping( nres_, -1 );
816  for ( int i=1; i<= nres_; ++i ) {
817  if ( i < seg_begin ) {
818  mapping(i) = i;
819  } else if ( i > seg_end ) {
820  mapping(i) = i - size;
821  }
822  }
823 
824  std::vector< Edge > new_edge_list_;
825 
826  for ( iterator it = edge_list_.begin(), it_end = edge_list_.end();
827  it != it_end; ++it ) {
828  int pos1( mapping( it->start() ) );
829  int pos2( mapping( it->stop() ) );
830  int const dir( it->start() < it->stop() ? n2c :c2n );
831  if ( pos1 == -1 || pos2 == -1 ) assert( it->is_polymer() );
832 
833  if ( pos1 == -1 ) {
834  assert( (dir == n2c && it->start() == seg_begin && it->stop() > seg_end) ||
835  (dir == c2n && it->start() == seg_end && it->stop() < seg_begin) );
836  if ( dir == n2c ) {
837  pos1 = seg_begin; // n2c
838  } else {
839  pos1 = seg_begin - 1; // c2n
840  }
841  } else if ( pos2 == -1 ) {
842  assert( (dir == c2n && it->stop() == seg_begin && it->start() > seg_end) ||
843  (dir == n2c && it->stop() == seg_end && it->start() < seg_begin) );
844  if ( dir == c2n ) {
845  pos2 = seg_begin; // c2n
846  } else {
847  pos2 = seg_begin - 1; // n2c
848  }
849  }
850  if ( pos1 != pos2 ) {
851  new_edge_list_.push_back( Edge( pos1, pos2, it->label() ) );
852  //std::cout << "remap edge: " << *it << ' ' << pos1 << ' ' << pos2 <<
853  //std::endl;
854  }
855  }
856 
857  new_topology = true;
858  edge_list_ = new_edge_list_;
859 }
860 
861 
862 //////////////////////////////////////////////////////////////////
863 /// @details this is an internal function, used for testing if an edge is separating
864 ///
865 // should this set new_topology TRUE???
866 //
867 void
868 FoldTree::update_edge_label(
869  int const start,
870  int const stop,
871  int const old_label,
872  int const new_label
873 )
874 {
875  bool found(false);
876  for ( FoldTree::iterator it=edge_list_.begin(), it_end=edge_list_.end();
877  it != it_end; ++it ) {
878  if ( it->label() == old_label &&
879  ( ( it->start() == start && it->stop() == stop ) ||
880  ( it->start() == stop && it->stop() == start ) ) ) {
881  it->label() = new_label;
882  found = true;
883  break;
884  }
885  }
886  if ( !found ) {
887  TR.Fatal << "FoldTree::update_edge_label(...) edge not in tree: " <<
888  ' ' << start << ' ' << stop << ' ' << old_label << std::endl;
889  TR.Fatal << *this;
890  utility_exit();
891  }
892 }
893 
894 
895 
896 //////////////////////////////////////////////////////////////////
897 /// @details this is an internal function, used for testing if an edge is separating
898 ///
899 // should this set new_topology TRUE???
900 //
901 int
902 FoldTree::edge_label(
903  int const start,
904  int const stop
905 )
906 {
907  bool found(false);
908  int label(-1000);
909  for ( FoldTree::iterator it=edge_list_.begin(), it_end=edge_list_.end();
910  it != it_end; ++it ) {
911  if ( ( it->start() == start && it->stop() == stop ) ||
912  ( it->start() == stop && it->stop() == start ) ) {
913  label = it->label();
914  found = true;
915  break;
916  }
917  }
918  if ( !found ) {
919  TR.Fatal << "FoldTree::edge_label(...) edge not in tree: " <<
920  ' ' << start << ' ' << stop << ' ' << std::endl;
921  TR.Fatal << *this;
922  utility_exit();
923  }
924  return label;
925 }
926 
927 ///////////////////////////////////////////////////////
928 /// @details
929 /// after deleting a jump, there may be vertices of the
930 /// tree which are neither jumps nor cutpoints. So delete them!
931 /// this will combine two adjacent short edges into a long one
932 void
933 FoldTree::delete_extra_vertices()
934 {
935  // first get rid of any self-edges, eg left over from the tree when it was a single-residue tree
936  delete_self_edges();
937 
938  // want to use is_jump_point_, is_cutpoint_
939  // so ensure that this data is up-to-date
940  check_topology();
941 
942  int const _root( root() ); //need to keep that locally, since after killing the first edge the root() might have changed
943  //
944  while ( true ) {
945  int kill_vertex( 0 );
946  for ( iterator it=edge_list_.begin(),it_end = edge_list_.end();
947  it != it_end && !kill_vertex; ++it ) {
948  // are either of these vertices extraneous ( neither jump-point nor cutpoint)
949 // TR.Trace << "superfluous? check Edge " << *it << std::endl;
950 // TR.Trace << "isjump: " << is_jump_point_( it->start() ) << " " << is_jump_point_( it->stop() ) << std::endl;
951 // TR.Trace << "iscut: "
952 // << is_cutpoint_( it->start() ) << " " << is_cutpoint_( it->start()-1 ) << " "
953 // << is_cutpoint_( it->stop() ) << " " << is_cutpoint_( it->stop()-1 ) << std::endl;
954 // TR.Trace << "isroot: " << ( _root == it->start() ) << " " << ( _root == it->stop() ) << std::endl;
955  if ( it->start() != _root &&
956  !is_jump_point_[ it->start() ] &&
957  !is_cutpoint_ ( it->start() ) &&
958  !is_cutpoint_ ( it->start()-1 ) ) kill_vertex = it->start();
959  if ( !is_jump_point_[ it->stop() ] &&
960  !is_cutpoint_ ( it->stop() ) &&
961  !is_cutpoint_ ( it->stop()-1 ) ) kill_vertex = it->stop();
962  if ( kill_vertex ) break;
963  }
964  if ( !kill_vertex ) break;
965  // TR.Trace << "delete vertex: " << kill_vertex << std::endl;
966  int nbounds(0);
967  FArray1D_int bounds(2,0);
968  for ( iterator it=edge_list_.begin(),it_end = edge_list_.end();
969  it != it_end && nbounds<2; ++it ) {
970  if ( it->start() == kill_vertex ) {
971  nbounds++;
972  bounds( nbounds ) = it->stop();
973  } else if ( it->stop() == kill_vertex ) {
974  nbounds++;
975  bounds( nbounds ) = it->start();
976  }
977  }
978  //std::cout << "bounds: " << bounds(1) << ' ' << bounds(2) << std::endl << *this;
979  delete_unordered_edge( bounds(1), kill_vertex, Edge::PEPTIDE );
980  delete_unordered_edge( bounds(2), kill_vertex, Edge::PEPTIDE );
981  add_edge( bounds(1), bounds(2), Edge::PEPTIDE );
982  }
983 
984  // need to call reorder since directionality of new edges may be incorrect
985  reorder( _root );
986 }
987 
988 
989 /////////////////////////////////////////////////////////////////////////////
990 /// @details Get the sequence position of the downstream vertex of the jump indicated by
991 /// the jump_number argument. Downstream means that if we traverse the tree starting at the root
992 /// then we hit that vertex second.
993 ///
994 /// return 0 if failed
995 int
996 FoldTree::downstream_jump_residue( int const jump_number ) const
997 {
998  check_order();
999  assert( jump_number >= 1 && jump_number <= num_jump_ );
1000  for ( const_iterator it = edge_list_.begin(),
1001  it_end = edge_list_.end(); it != it_end; ++it ) {
1002  if ( it->label() == jump_number ) return it->stop();
1003  }
1004  return 0;
1005 }
1006 /////////////////////////////////////////////////////////////////////////////
1007 /// @details Get the sequence position of the upstream vertex of the jump indicated by
1008 /// the jump_number argument. Upstream means that if we traverse the tree starting at the root
1009 /// then we hit that vertex first.
1010 ///
1011 /// return 0 if failed
1012 int
1013 FoldTree::upstream_jump_residue( int const jump_number ) const
1014 {
1015  check_order();
1016  assert( jump_number >= 1 && jump_number <= num_jump_ );
1017  for ( const_iterator it = edge_list_.begin(),
1018  it_end = edge_list_.end(); it != it_end; ++it ) {
1019  if ( it->label() == jump_number ) return it->start();
1020  }
1021  return 0;
1022 }
1023 
1024 
1025 ///////////////////////////////////////////////////////
1026 /// @details Reorder the tree so that start_residue is the new root.
1027 /// returns false if no re-ordering allowed! To reorder
1028 /// successfully, start_residue needs to be a vertex in the
1029 /// original fold tree.
1030 
1031 // will this be too slow? creates a new edge_list_ object,
1032 // then at the end copies it into edge_list_; To
1033 bool
1034 FoldTree::reorder( int const start_residue )
1035 {
1036  if ( new_topology ) update_nres(); // need nres
1037 
1038  // static FArray ==> only re-allocate upon changes of nres
1039  static FArray1D_bool linked;
1040  if ( nres_ != int( linked.size1() ) ) {
1041  linked.dimension( nres_ );
1042  }
1043 
1044  EdgeList new_edge_list_;
1045 
1046  // keep track of which residues have been added to the new list
1047  linked = false;
1048 
1049  linked( start_residue) = true;
1050 
1051  bool new_member (true);
1052 
1053  while ( new_member ) {
1054  new_member = false;
1055  for ( const_iterator it = edge_list_.begin(),
1056  it_end = edge_list_.end(); it != it_end; ++it) {
1057  Edge const& old_edge( *it );
1058  Edge edge( old_edge ); //makes sure everything in Edge gets copied !!!
1059  if ( linked( edge.start() ) && !linked( edge.stop() ) ) {
1060  new_edge_list_.push_back( edge );
1061  linked( edge.stop() ) = true;
1062  new_member = true;
1063  } else if ( linked( edge.stop() ) && !linked( edge.start() ) ) {
1064  //switch start / stop information
1065  edge.start() = old_edge.stop();
1066  edge.stop() = old_edge.start();
1067  edge.start_atom() = old_edge.stop_atom();
1068  edge.stop_atom() = old_edge.start_atom();
1069  new_edge_list_.push_back( edge );
1070  linked( edge.stop() ) = true;
1071  new_member = true;
1072  }
1073  }
1074  }// while ( new_member )
1075 
1076  if ( new_edge_list_.size() != edge_list_.size() ) {
1077  TR.Error << "FoldTree::reorder( " << start_residue << " ) failed, new/old edge_list_ size mismatch" << std::endl;
1078  TR.Error << edge_list_.size() << ' ' << new_edge_list_.size() << std::endl;
1079  TR.Error << *this;
1080 
1081  // TR.Error << "show old edge list " << std::endl;
1082  // for( FoldTree::const_iterator it(edge_list_.begin()), end(edge_list_.end()); it!=end; ++it){
1083  // TR.Error << *it << std::endl;
1084  // }
1085 
1086  // TR.Error << "show new edge list " << std::endl;
1087  // for( FoldTree::const_iterator it(new_edge_list_.begin()), end(new_edge_list_.end()); it!=end; ++it){
1088  // TR.Error << *it << std::endl;
1089  // }
1090 
1091  return false;
1092  }
1093 
1094  // slow: clear edge_list_ then copy from new_edge_list_...
1095  edge_list_ = new_edge_list_;
1096  reassign_atoms_for_intra_residue_stubs();
1097  new_order = true;
1098  return true; // success
1099 } // FoldTree::reorder(...)
1100 
1101 
1102 
1103 
1104 ///////////////////////////////////////////////////////////////////////////////
1105 /// @brief Make a simple, 1->total_residue tree.
1106 void
1107 FoldTree::simple_tree( int const nres_in )
1108 {
1109  PyAssert( (nres_in>0), "FoldTree::simple_tree( int const nres_in ): input variable nres_in has a meaningless value");
1110  new_topology = true; // ensure that derived data are re-calculated
1111  edge_list_.clear();
1112  add_edge(1, nres_in, Edge::PEPTIDE); // from 1->total_residue
1113 }
1114 
1115 //////////////////////////////////////////////////////////////////////////////
1116 /// @brief Returns true if this tree is a simple 1->total_residue FoldTree,
1117 /// returns false otherwise.
1118 bool
1119 FoldTree::is_simple_tree() const {
1120  bool is_simple( false );
1121  if ( edge_list_.size() == 1 ) {
1122  EdgeList::const_iterator e = begin();
1123  if ( e->start() == 1 && (Size) e->stop() == nres() && e->is_polymer() )
1124  is_simple = true;
1125  }
1126 
1127  return is_simple;
1128 }
1129 
1130 
1131 //////////////////////////////////////////////////////////////////////////////
1132 /// @details After this call you're guaranteed that v is a vertex of the tree, ie not contained in the
1133 /// interior of a peptide edge
1134 ///
1135 
1136 void
1137 FoldTree::add_vertex( int const v )
1138 {
1139 
1140  // find the edge that contains new_cutpoint and cut it
1141  for ( iterator it= edge_list_.begin(), ite= edge_list_.end(); it != ite; ++it ) {
1142  if ( it->is_polymer() &&
1143  ( ( it->start() < v && it->stop () > v ) ||
1144  ( it->stop () < v && it->start() > v ) ) ) {
1145  int const start( std::min( it->start(), it->stop()) );
1146  int const stop ( std::max( it->start(), it->stop()) );
1147  delete_edge( it );
1148  if ( start < v ) add_edge( start, v, Edge::PEPTIDE );
1149  if ( stop > v ) add_edge( v, stop, Edge::PEPTIDE );
1150  break;
1151  }
1152  }
1153  new_topology = true;
1154 }
1155 
1156 
1157 /////////////////////////////////////////////////////////////////////////////
1158 /// @details Add a new jump to an existing fold tree, returns the jump_number of the new jump.
1159 
1160 int
1161 FoldTree::new_jump(
1162  int const jump_pos1,
1163  int const jump_pos2,
1164  int const new_cutpoint
1165 )
1166 {
1167  assert( !is_cutpoint( new_cutpoint ) );
1168  // otherwise causes an error with delete_unordered_edge
1169  PyAssert( !is_cutpoint( new_cutpoint ), "FoldTree::new_jump( int const new_cutpoint ): new_cutpoint is already a cutpoint!" );
1170  // Commenting out because it get in the way when building symmetry Pose
1171  //PyAssert( (jump_pos1-new_cutpoint)*(jump_pos2-new_cutpoint)<0, "FoldTree::new_jump( int const new_cutpoint ): new_cutpoint is not between the jump points!" );
1172  PyAssert( (jump_pos1>0) && (jump_pos1<=nres_), "FoldTree::new_jump( int const jump_pos1 ): jump_pos1 is out of range!" );
1173  PyAssert( (jump_pos2>0) && (jump_pos2<=nres_), "FoldTree::new_jump( int const jump_pos2 ): jump_pos2 is out of range!" );
1174 
1175  int const root( edge_list_.begin()->start() );
1176  int const new_jump_number( num_jump() + 1 );
1177 
1178  add_vertex( jump_pos1 );
1179  add_vertex( jump_pos2 );
1180  add_vertex( new_cutpoint );
1181  add_vertex( new_cutpoint+1 );
1182 
1183  add_edge( jump_pos1, jump_pos2, new_jump_number );
1184  delete_unordered_edge( new_cutpoint, new_cutpoint+1, Edge::PEPTIDE );
1185 
1186  reorder( root );
1187  new_topology = true;
1188 
1189  assert( is_cutpoint( new_cutpoint ) && is_jump_point( jump_pos1 ) && is_jump_point( jump_pos2 ) );
1190 // PyAssert( is_cutpoint( new_cutpoint ) && is_jump_point( jump_pos1 ) && is_jump_point( jump_pos2 ), "FoldTree::new_jump( int const jump_pos1, int const jump_pos2, int const new_cutpoint ): FAIL!" );
1191 
1192  return new_jump_number;
1193 }
1194 
1195 /// @details Add a new jump to an existing fold tree, returns the jump_number of the new jump.
1196 
1197 void
1198 FoldTree::new_chemical_bond(
1199  int const anchor_pos,
1200  int const root_pos,
1201  std::string const & anchor_atom,
1202  std::string const & root_atom,
1203  int const new_cutpoint
1204 )
1205 {
1206  assert( !is_cutpoint( new_cutpoint ) );
1207 
1208  int const root( edge_list_.begin()->start() );
1209 
1210  add_vertex( anchor_pos );
1211  add_vertex( root_pos );
1212  add_vertex( new_cutpoint );
1213  add_vertex( new_cutpoint+1 );
1214 
1215  Edge new_edge( anchor_pos, root_pos, anchor_atom, root_atom ); // not obvious that this is a chemical bond c-tor
1216  assert( new_edge.is_chemical_bond() );
1217  add_edge( new_edge );
1218  delete_unordered_edge( new_cutpoint, new_cutpoint+1, Edge::PEPTIDE );
1219 
1220  reorder( root );
1221  new_topology = true;
1222 
1223  assert( is_cutpoint( new_cutpoint ) && is_jump_point( anchor_pos ) && is_jump_point( root_pos ) );
1224 }
1225 
1226 /////////////////////////////////////////////////////////////////////////////
1227 /// @details Construct a new tree (self) from a set of jump points and cutpoints
1228 /// this assumes that we can make a tree, ie that the number of cuts
1229 /// is equal to the number of jumps.
1230 ///
1231 /// @note The root vertex of new tree is 1.
1232 bool
1233 FoldTree::tree_from_jumps_and_cuts(
1234  int const nres_in,
1235  int const num_jump_in,
1236  FArray2D_int const & jump_point_in, /* 2 x njump */
1237  FArray1D_int const & cuts,
1238  int const root_in,
1239  bool const verbose /* = true */
1240 )
1241 {
1242  // tells routines that need derived data to re-update,eg connected() needs
1243  // nres
1244  new_topology = true;
1245 
1246  if ( num_jump_in == 0 ) {
1247  // make a simple tree. this could also have been done by simple_tree()
1248  edge_list_.clear();
1249  add_edge( 1, nres_in, Edge::PEPTIDE );
1250  return true; // success
1251  }
1252 
1253  //jjh Report jumps for reporting purposes
1254  if ( verbose ) {
1255  for ( int i = 1, iend = num_jump_in ; i <= iend ; ++i ) {
1256  TR.Debug << "Jump #" << i << " from " << jump_point_in( 1, i ) <<
1257  " to " << jump_point_in( 2, i ) << std::endl;
1258  }
1259  }
1260 
1261  // make a list of the unique jump_points in increasing order:
1262  // so we can construct the peptide edges
1263  typedef std::list< int > Int_list;
1264  Int_list vertex_list;
1265  // vertex_list.push_back( 1 );
1266  FArray1D_bool is_cut( nres_in, false ); // keep track of cuts
1267  for ( int i = 1; i <= num_jump_in; ++i ) {
1268  for ( int j = 1; j <= 2; ++j ) {
1269  int const pos ( jump_point_in(j,i) );
1270  // assert( pos >= 1 && pos <= nres_in );
1271  // if ( jump_point_in( j, i ) == 1 || jump_point_in( j, i ) == nres_in ) {
1272  // if ( verbose ) TR.Warning << "attempt to create jump with residue 1 or NRES: not supported.. returning invalid tree" << std::endl;
1273  // return false;
1274  // }
1275  vertex_list.push_back( pos );
1276  }
1277  assert( jump_point_in(1,i) < jump_point_in(2,i) );
1278  int const cut( cuts(i) );
1279  assert( cut >= 1 && cut < nres_in );
1280  is_cut( cut ) = true;
1281  vertex_list.push_back( cut );
1282  vertex_list.push_back( cut+1 );
1283  }
1284  // vertex_list.push_back( nres_in );
1285 
1286  vertex_list.sort();
1287  vertex_list.unique(); // something like that...
1288 
1289  // start building the tree, add peptide edges
1290  edge_list_.clear();
1291 
1292  int const jump_stop( *( vertex_list.begin() ) );
1293  if ( jump_stop > 1 ) add_edge( 1, jump_stop, Edge::PEPTIDE );
1294 
1295  for ( Int_list::iterator it = vertex_list.begin(),
1296  it_end = vertex_list.end(); it != it_end; ++it ) {
1297  Int_list::iterator it_next (it);
1298  ++it_next;
1299  if ( it_next == it_end ) break;
1300 
1301  int const start ( *it );
1302  int const stop ( *it_next );
1303  assert( start >= 1 && start < stop && stop <= nres_in );
1304  if ( !is_cut(start) ) {
1305  add_edge( start, stop, Edge::PEPTIDE );
1306  } else {
1307  assert( stop == start + 1 );
1308  }
1309  }
1310 
1311  // Add final edge.
1312  Int_list::iterator last_jump_it = vertex_list.end();
1313  int const jump_start( *(--last_jump_it) );
1314  if ( jump_start < nres_in ) add_edge( jump_start, nres_in, Edge::PEPTIDE );
1315 
1316 
1317 // assert( edge_list_[0].start() == 1 &&
1318 // edge_list_[ edge_list_.size() -1 ].stop() == nres_in );
1319 
1320  // now add the edges corresponding to jumps
1321  for ( int i=1; i<= num_jump_in; ++i ) {
1322  add_edge( jump_point_in(1,i), jump_point_in(2,i), i );
1323  }
1324 
1325  reorder(root_in);
1326  // This assertion is out of place:
1327  // assert( check_fold_tree() ); // tree should be valid now
1328  // return true;
1329  // the interface description says that the function returns false if it fails...
1330  return check_fold_tree();
1331 }
1332 
1333 //////////////////////////////////////////////////////////////////////////////
1334 /// @details
1335 /// random_tree_from_jumps builds a tree from a list of jump_points and a
1336 /// bias array telling us where we should prefer to cut:
1337 /// P(cut at i ) ~ cut_bias(i).
1338 /// It returns false if choosing fails (incompatible jumps? cycles?....).
1339 /// as noted in update_edge_labels(), without corresponding cutpoint for each
1340 /// jump added, the fold tree will be cyclic ( e.g., some of the edges are non-
1341 /// separating with label==-2). This function keeps finding those edges and choose
1342 /// cutpoints based on the biased probability.
1343 /// note that during the process of building out tree, we cant use
1344 /// any of the derived data, since conceptually the derived data comes
1345 /// after the tree.
1346 ///
1347 /// Note (from rhiju): updated routine to allow jumps at 1 or NRES, but for now
1348 /// keep this behavior inactive by default -- other routines used by
1349 /// protein jumpers (get_residue_edge?) appear to stumble if jumps start
1350 /// at the root residue.
1351 ///
1352 bool FoldTree::random_tree_from_jump_points(
1353  int const nres_in,
1354  int const num_jump_in,
1355  FArray2D_int const & jump_point_in, /* 2 x njump */
1356  FArray1D_float const & cut_bias,
1357  int const root_in /* = 1 */,
1358  bool const allow_jump_at_1_or_NRES /* = false */)
1359 {
1360  std::vector< int > obligate_cut_points; //empty.
1361  return random_tree_from_jump_points( nres_in, num_jump_in, jump_point_in, obligate_cut_points, cut_bias, root_in, allow_jump_at_1_or_NRES );
1362 }
1363 
1364 
1365 bool
1366 FoldTree::random_tree_from_jump_points(
1367  int const nres_in,
1368  int const num_jump_in,
1369  FArray2D_int const & jump_point_in,
1370  std::vector< int > const & obligate_cut_points,
1371  FArray1D_float const & cut_bias,
1372  int const root_in /* = 1 */,
1373  bool const allow_jump_at_1_or_NRES /* = false */)
1374 {
1375  // tells routines that need derived data to re-update,eg connected() needs
1376  // nres
1377  new_topology = true;
1378 
1379  if ( num_jump_in == 0 ) {
1380  // make a simple tree. this could also have been done by simple_tree()
1381  edge_list_.clear();
1382  add_edge( 1, nres_in, Edge::PEPTIDE );
1383  return true; // success
1384  }
1385 
1386  // this array is passed in to the edge-cutting routines
1387  FArray1D_float cut_bias_sum( DRange(0,nres_in) );
1388  cut_bias_sum(0) = 0.0;
1389  for ( int i=1; i<= nres_in; ++i ) {
1390  cut_bias_sum(i) = cut_bias_sum( i-1 ) + cut_bias(i);
1391  }
1392 
1393 
1394  // make a list of the unique jump_points in increasing order:
1395  // so we can construct the peptide edges
1396  typedef std::list< int > Int_list;
1397  Int_list jump_list;
1398  // jump_list.push_back( 1 );
1399  for ( int i = 1; i <= num_jump_in; ++i ) {
1400  for ( int j = 1; j <= 2; ++j ) {
1401  if ( !allow_jump_at_1_or_NRES && (jump_point_in( j, i ) == 1 || jump_point_in( j, i ) == nres_in ) ) {
1402  TR.Warning << "attempt to create jump with residue 1 or NRES: not supported.. returning invalid tree" << std::endl;
1403  return false;
1404  }
1405  jump_list.push_back( jump_point_in(j,i) );
1406 
1407  }
1408  }
1409  // jump_list.push_back( nres_in );
1410 
1411  jump_list.sort();
1412  jump_list.unique(); // something like that...
1413 
1414  // start building the tree, add peptide edges
1415  edge_list_.clear();
1416 
1417  //Add beginning edge.
1418  int const jump_stop( *jump_list.begin() );
1419  if (jump_stop > 1) add_edge( 1, jump_stop, Edge::PEPTIDE );
1420 
1421  // Add intervening segments.
1422  for ( Int_list::iterator it = jump_list.begin(),
1423  it_end = jump_list.end(); it != it_end; ++it ) {
1424  Int_list::iterator it_next (it);
1425  ++it_next;
1426  if ( it_next == it_end ) break;
1427 
1428  int const start ( *it );
1429  int const stop ( *it_next );
1430  int const label ( -2 );//(start == 1 || stop == nres_in) ? Edge::PEPTIDE : -2 );
1431  assert( start >= 1 && start < stop && stop <= nres_in );
1432  add_edge( start, stop, label );
1433  }
1434 
1435  //Add final edge.
1436  Int_list::iterator last_jump_it = jump_list.end();
1437  int const jump_start( *(--last_jump_it) );
1438  if (jump_start < nres_in) add_edge( jump_start, nres_in, Edge::PEPTIDE );
1439 
1440  assert( edge_list_[0].start() == 1 &&
1441  edge_list_[ edge_list_.size()-1 ].stop() == nres_in );
1442 
1443  // now add the edges corresponding to jumps
1444  for ( int i=1; i<= num_jump_in; ++i ) {
1445  add_edge( jump_point_in(1,i), jump_point_in(2,i), i );
1446  }
1447 
1448  //Add cuts that the user has given ... there could be none.
1449  int const num_user_cut_points = obligate_cut_points.size();
1450  for ( int i = 0; i < num_user_cut_points; i++ ) {
1451  int const cut_point = obligate_cut_points[i];
1452  bool const success = cut_edge( cut_point );
1453 
1454  if (!success) {
1455  return false;
1456  // this is a problem!
1457  // TR.Fatal << "Problem with user-defined cutpoint: " << cut_point << " " << (*this) << std::endl;
1458  // utility_exit();
1459  }
1460 
1461  }
1462 
1463  // keep cutting edges until we get a tree
1464  bool is_a_tree ( false );
1465  while ( ! is_a_tree ) {
1466  update_edge_labels();
1467  is_a_tree = true;
1468  for ( iterator it = edge_list_.begin(), it_end = edge_list_.end();
1469  it != it_end; ++it ) {
1470  if ( it->label() == -2 ) {
1471  is_a_tree = false;
1472  break;
1473  }
1474  }
1475 
1476  if ( ! is_a_tree ) {
1477  if ( ! cut_random_edge( cut_bias_sum, nres_in ) ) {
1478  // failed to cut
1479  TR.Error << "failure in FoldTree::choose_random_cuts(...)." << std::endl;
1480  return false; // signal failure
1481  }
1482  }
1483  } // while ( ! is_a_tree )
1484 
1485  reorder(root_in);
1486 
1487  /// wrong behaviour:
1488  // assert( check_fold_tree() ); // tree should be valid now
1489  // return true;
1490  //This assertion is out of place:
1491  // the interface details that function returns false if it fails...
1492  return check_fold_tree();
1493 } // random_tree_from_jump_points(...)
1494 
1495 
1496 ///////////////////////////////////////////////////////////
1497 bool FoldTree::cut_edge( int const cut_point ) {
1498 
1499  for ( iterator it = edge_list_.begin(), it_end = edge_list_.end();
1500  it != it_end; ++it ) {
1501  if ( it ->label() < 0 &&
1502  ( ( it->start() <= cut_point && it->stop() >= cut_point+1 ) ||
1503  ( it->stop() <= cut_point && it->start() >= cut_point+1 ) ) ) {
1504  if ( it->label() == Edge::PEPTIDE ) {
1505  // you cant cut at this cutpoint
1506  break;
1507  } else {
1508  assert( it->label() == -2 );
1509  TR.Debug << "cutting at " << cut_point << std::endl;
1510 
1511  int const start( std::min( it->start(), it->stop()) );
1512  int const stop ( std::max( it->start(), it->stop()) );
1513  delete_edge( it );
1514  if ( start < cut_point ) add_edge( start, cut_point, Edge::PEPTIDE); // separating
1515  if ( cut_point+1 < stop ) add_edge( cut_point+1, stop, Edge::PEPTIDE); // separating
1516  return true; // successfully cut the tree
1517  }
1518  }
1519  } // loop over edge_list
1520  return false;
1521 }
1522 
1523 /////////////////////////////////////////////////////////////////////////////
1524 /// @details Fill a vector of cutpoints.
1525 /// @note Slow: just for convenience routines...
1527 FoldTree::cutpoints() const
1528 {
1529  check_topology();
1531  for( int i=1; i<= num_cutpoint_; ++i ) {
1532  cuts.push_back( cutpoint_[i] );
1533  }
1534  return cuts;
1535 }
1536 
1537 ///////////////////////////////////////////////////////////////////////////////
1538 // private:
1539 /// @details
1540 ///
1541 /// this routine assigns labels to the edges of a graph based
1542 /// on whether or not those edges are separating -- ie whether
1543 /// they can be cut without disconnecting the graph.
1544 /// we know we have a tree when all the edges are separating
1545 ///
1546 /// edge labels:
1547 /// - +N means that the edge corresponds to jump #N (=> uncuttable)
1548 /// - -2 means cuttable
1549 /// - -1 means separating == PEPTIDE
1550 /// - 0 means cut
1551 ///
1552 /// we assume that the only possible change in edge labelling that we
1553 /// need to make is from a -2 to a -1
1554 /// ie, the -1's are still correct
1555 /// also, there shouldn't be any 0's before this is called
1556 /// 0's are for communicating between this function and
1557 /// the logical function connected_graph(g)
1558 
1559 void
1560 FoldTree::update_edge_labels()
1561 {
1562  assert( Edge::PEPTIDE != -2 );
1563  for ( iterator it = edge_list_.begin(), it_end = edge_list_.end();
1564  it != it_end; ++it ) {
1565  if ( it->label() == -2 ) { // labelled as not separating
1566  it->label() = 0;
1567  if ( ! connected() ) {
1568  it->label() = Edge::PEPTIDE; // now it's separating
1569  } else {
1570  it->label() = -2; // still not separating
1571  }
1572  } else if ( it->label() == 0 ) { // debug
1573  TR.Fatal << "zero edge label in graph:" << std::endl;
1574  utility_exit();
1575  }
1576  }
1577 }
1578 
1579 /////////////////////////////////////////////////////////////////////////////
1580 /// @details Cuts a random edge chosen with per-rsd frequency given by cut_bias_sum.
1581 /// private: returns true if success, false if failure.
1582 /// operates on the edge_list_.
1583 /// doesnt assume any derived data is up-to-date.
1584 /// only an non-separating edge (label==-2) can be cut, otherwise fold tree will
1585 /// not be valid.
1586 bool
1587 FoldTree::cut_random_edge(
1588  FArray1D_float const & cut_bias_sum,
1589  int const nres_in
1590 )
1591 {
1592  int tries(0);
1593 
1594  while ( tries < 100000 ) {
1595  ++tries;
1596 
1597  int const cut_point ( pick_loopy_cutpoint( nres_in, cut_bias_sum ) );
1598  bool success = cut_edge( cut_point );
1599  TR.Debug << "Trying cut_point: " << cut_point << " " << success << std::endl;
1600  if (success ) return true;
1601  } // keep trying
1602 
1603  return false; // too many tries
1604 }
1605 
1606 /////////////////////////////////////////////////////////////////////////////
1607 /// @details Assign new numbers to the jumps.
1608 /// after we delete a jump, we may want to re-number the others.
1609 /// note of course this will invalidate the jump_transform array of
1610 /// any pose with this fold_tree, so be sure to call jumps_from_positions
1611 /// or something
1612 void
1613 FoldTree::renumber_jumps()
1614 {
1615  int counter(0);
1616  new_topology = true;
1617  for ( iterator it = edge_list_.begin(), it_end = edge_list_.end();
1618  it != it_end; ++it ) {
1619  if ( it->is_jump() ) {
1620  ++counter;
1621  TR.Debug << "renumber jumps:: from,to " << it->label() << ' ' <<
1622  counter << std::endl;
1623  it->label() = counter;
1624  }
1625  }
1626 }
1627 
1628 /////////////////////////////////////////////////////////////////////////////
1629 /// @details Is the tree connected?
1630 /// returns true if fold_tree is connected
1631 /// doesnt assume that the fold_tree is in valid folding order, or even a tree
1632 bool
1633 FoldTree::connected() const
1634 {
1635  static FArray1D_bool linked;
1636  if ( new_topology ) update_nres();
1637  if ( int( linked.size1() ) != nres_ ) linked.dimension( nres_ );
1638 
1639  if ( edge_list_.size() <1 ) return true;
1640 
1641  linked = false;
1642 
1643  // grow out a single connected component from the start vertex:
1644  const_iterator const it_begin ( edge_list_.begin() );
1645  const_iterator const it_end ( edge_list_.end() );
1646 
1647  // mark start vertex as linked:
1648  linked( it_begin->start() ) = true;
1649 
1650  bool new_member ( true );
1651 
1652  while ( new_member ) { // keep adding new members
1653  new_member = false;
1654  for ( const_iterator it = it_begin; it != it_end; ++it ) {
1655  if ( it->label() == 0 ) continue;
1656  if ( linked( it->start() ) && ! linked( it->stop()) ) {
1657  linked(it->stop()) = true;
1658  new_member = true;
1659  } else if ( linked( it->stop() ) && ! linked( it->start() ) ) {
1660  linked( it->start() ) = true;
1661  new_member = true;
1662  }
1663  }
1664  }
1665 
1666  for ( const_iterator it = it_begin; it != it_end; ++it ) {
1667  if ( ! linked( it->start() ) || ! linked( it->stop() ) ) {
1668  // it's disconnected!
1669  return false;
1670  }
1671  }
1672  return true;
1673 } // FoldTree::connected()
1674 
1675 
1676 /////////////////////////////////////////////////////////////////////////////
1677 /// @details Create two new foldtrees f1 and f2 by splitting myself at jump jump_number
1678 /// Uses the following routine to figure out which vertices should be in each tree.
1679 ///
1680 /// @note The N-terminal vertex of jump "jump_number" goes to tree f1
1681 ///
1682 void
1683 FoldTree::partition_by_jump(
1684  int const jump_number,
1685  FoldTree & f1, //contains N-terminal vertex in jump, like partner1 in partition_by_jump below
1686  FoldTree & f2
1687 ) const
1688 {
1689  check_topology(); // update derived data if necessary
1690 
1691  // partition the residues
1692  FArray1D_bool partner1( nres_, false );
1693  partition_by_jump( jump_number, partner1 );
1694  f1.clear();
1695  f2.clear();
1696 
1697  utility::vector1< int > seqpos1( nres_, 0 );
1698  utility::vector1< int > seqpos2( nres_, 0 );
1699  Size nres1(0), nres2(0);
1700 
1701  for ( Size i=1; i<= Size(nres_); ++i ) {
1702  if ( partner1(i) ) {
1703  ++nres1;
1704  seqpos1[i] = nres1;
1705  } else {
1706  ++nres2;
1707  seqpos2[i] = nres2;
1708  }
1709  }
1710 
1711  int jump1(0);
1712  int jump2(0);
1713  for ( const_iterator it=edge_list_.begin(), ite=edge_list_.end(); it != ite; ++it ) {
1714  Edge edge( *it );
1715  if ( edge.is_jump() && edge.label() == jump_number ) continue; // the split jump itself
1716 
1717  if ( partner1( edge.start() ) ) {
1718  assert( partner1( edge.stop() ) );
1719 
1720  edge.start() = seqpos1[ edge.start() ];
1721  edge.stop () = seqpos1[ edge.stop () ];
1722  assert( edge.start() && edge.stop() );
1723  if ( edge.is_jump() ) {
1724  ++jump1;
1725  edge.label() = jump1;
1726  }
1727  f1.add_edge( edge );
1728 
1729  } else {
1730  assert( !partner1( edge.stop() ) );
1731 
1732  edge.start() = seqpos2[ edge.start() ];
1733  edge.stop () = seqpos2[ edge.stop () ];
1734  assert( edge.start() && edge.stop() );
1735  if ( edge.is_jump() ) {
1736  ++jump2;
1737  edge.label() = jump2;
1738  }
1739  f2.add_edge( edge );
1740  }
1741  }
1742 }
1743 
1744 
1745 /////////////////////////////////////////////////////////////////////////////
1746 /// @details
1747 /// when a jump edge is removed, the fold tree is separated into two parts. This
1748 /// fucntion is to find all residues connecting to the jump starting residue and flag
1749 /// them in the partner1(n_res) array as true. The residues on the other side are
1750 /// flagged as false. Useful to distinguish two docking partners when fold tree is
1751 /// properly set up.
1752 void
1753 FoldTree::partition_by_jump(
1754  int const jump_number,
1755  FArray1D_bool & partner1
1756 ) const
1757 {
1758  check_topology(); // update derived data if necessary
1759 
1760  assert( jump_number <= num_jump_ );
1761  assert( int(partner1.size1()) >= nres_ );
1762 
1763  // find n-terminal jump vertex
1764  int const pos1( jump_point_[jump_number ].first );
1765 
1766  // mark start vertex as linked:
1767  partner1 = false;
1768  //for ( int i=1; i<= nres_; ++i ) {
1769  // partner1(i) = false;
1770  //}
1771  partner1( pos1 ) = true;
1772 
1773  bool new_member ( true );
1774 
1775  // get pointers to the beginning and end of the edge_list_
1776  // const_iterator is a typedef in fold_tree.h:
1777  //
1778  // typedef std::vector< Edge > EdgeList;
1779  // typedef EdgeList::iterator iterator;
1780  // typedef EdgeList::const_iterator const_iterator;
1781 
1782  const_iterator it_begin( edge_list_.begin() );
1783  const_iterator it_end ( edge_list_.end() );
1784 
1785  while ( new_member ) { // keep adding new members
1786  new_member = false;
1787  for ( const_iterator it = it_begin; it != it_end; ++it ) {
1788  if ( it->label() == jump_number ) continue; // skip jump
1789 
1790  int const start( std::min( it->start(), it->stop() ) );
1791  int const stop ( std::max( it->start(), it->stop() ) );
1792  if ( (partner1( start ) && !partner1( stop )) ||
1793  (partner1( stop ) && !partner1( start )) ) {
1794  new_member = true;
1795  if ( it->is_polymer() ) {
1796  // all the residues
1797  for ( int i=start; i<= stop; ++i ) {
1798  partner1( i ) = true;
1799  }
1800  } else {
1801  // just the vertices
1802  partner1( start ) = true;
1803  partner1( stop ) = true;
1804  }
1805  }
1806  }
1807  }
1808 }
1809 
1810 /////////////////////////////////////////////////////////////////////////////
1811 /// @details partition the fold tree in two parts if a cut would be introduced between seqpos and seqpos+1.
1812 /// Function is an analog to partition_by_jump() -- its goal to find all residues
1813 /// connecting to the jump starting residue and flag
1814 /// them in the partner1(n_res) array as true. The residues on the other side are
1815 /// flagged as false. Useful to distinguish two docking partners when fold tree is
1816 /// properly set up.void
1817 void
1818 FoldTree::partition_by_residue(
1819  int const seqpos,
1820  FArray1D_bool & partner1
1821 ) const
1822 {
1823  check_topology(); // update derived data if necessary
1824 
1825  assert( seqpos <= nres_ );
1826  assert( int(partner1.size1()) >= nres_ );
1827 
1828  partner1 = false;
1829 
1830  // mark part of starting edge as linked.
1831 
1832  // First have to find edge. Standard get_residue_edge() has problem with root? Why?
1833  // Edge edge = get_residue_edge( seqpos );
1834  Edge edge;
1835  bool found_edge( false );
1836  partner1( seqpos ) = true;
1837  for ( const_iterator it = begin(), it_end = end(); it != it_end; ++it ) {
1838 
1839  int const start( std::min( it->start(), it->stop() ) );
1840  int const stop ( std::max( it->start(), it->stop() ) );
1841  if ( it->is_polymer() && start <= seqpos && stop >= seqpos ) {
1842  edge = *it;
1843  found_edge = true;
1844 
1845  // std::cout << "FOUND START EDGE: " << edge.start() << " " << edge.stop() << std::endl;
1846  int const seqpos_edge_start( std::min( edge.start(), edge.stop() ) );
1847  for ( int i = seqpos_edge_start; i< seqpos; ++i ) partner1( i ) = true;
1848 
1849  }
1850  }
1851  if (!found_edge) return;
1852 
1853  bool new_member ( true );
1854 
1855  // get pointers to the beginning and end of the edge_list_
1856  // const_iterator is a typedef in fold_tree.h:
1857  //
1858  // typedef std::vector< Edge > EdgeList;
1859  // typedef EdgeList::iterator iterator;
1860  // typedef EdgeList::const_iterator const_iterator;
1861 
1862  const_iterator it_begin( edge_list_.begin() );
1863  const_iterator it_end ( edge_list_.end() );
1864 
1865  while ( new_member ) { // keep adding new members
1866  new_member = false;
1867  for ( const_iterator it = it_begin; it != it_end; ++it ) {
1868 
1869  int const start( std::min( it->start(), it->stop() ) );
1870  int const stop ( std::max( it->start(), it->stop() ) );
1871 
1872  if ( it->is_polymer() && start <= seqpos && stop >= seqpos ) continue; // skip input edge.
1873 
1874  if ( ( partner1( start ) && !partner1( stop ) ) ||
1875  ( partner1( stop ) && !partner1( start ) ) ) {
1876  new_member = true;
1877  if ( it->is_polymer() ) {
1878  // all the residues
1879  for ( int i=start; i<= stop; ++i ) {
1880  partner1( i ) = true;
1881  }
1882  } else {
1883  // just the vertices
1884  partner1( start ) = true;
1885  partner1( stop ) = true;
1886  }
1887  }
1888  }
1889  }
1890 }
1891 
1892 
1893 int
1894 FoldTree::jump_point(
1895  int const lower_higher, // = 1 or 2
1896  int const jump_number
1897 ) const
1898 {
1899  PyAssert(((jump_number > 0) || (jump_number <= num_jump_)),
1900  "FoldTree::jump_point( int const lower_higher, int const jump_number ): Input variable jump_number is not a valid value.");
1901  check_topology();
1902  if( lower_higher == 1 ) {
1903  return jump_point_[jump_number].first;
1904  } else if( lower_higher == 2 ) {
1905  return jump_point_[jump_number].second;
1906  } else {
1907  std::cout << "FoldTree::jump_point() lower_higher needs to be 1 or 2" << std::endl;
1908  std::exit(9);
1909  }
1910 }
1911 
1912 
1913 ////////////////////////////////////////////////////////////////////////////
1914 /// @details
1915 /// To keep the fold tree non-cyclic, for each jump added, there should be
1916 /// a corresponding cutpoint. First call partition_by_jump() and the cutpoint
1917 /// for this jump would be those two sequentially adjacent residues which are
1918 /// not connected any more if the jump is disconnected.
1919 ///
1920 /// @note This cutpoint is not necessarily unique if the foldtree is sufficiently
1921 /// complex. Chooses the first cutpoint with the desired property, starting at the N-terminus.
1922 /// Will be unique eg if the jump is the intra-template jump used to support a single loop
1923 /// region during loop modeling.
1924 ///
1925 int
1926 FoldTree::cutpoint_by_jump(
1927  int const jump_number
1928 ) const
1929 {
1930  check_topology(); // update derived data if necessary
1931 
1932  FArray1D_bool partner1( nres_, false );
1933  partition_by_jump( jump_number, partner1 );
1934  int i = 1;
1935  while ( i < nres_ && partner1(i) == partner1(i+1) ) i++;
1936  if ( i == nres_ ) {
1937  TR.Fatal << " FoldTree::cutpoint_by_jump error: "
1938  << "can not find the cutpoint! for jump_number: " << jump_number
1939  << std::endl << (*this) << std::endl;
1940  utility_exit();
1941  return i;
1942  } else {
1943  return i;
1944  }
1945 }
1946 
1947 
1948 //////////////////////////////////////////////////////////////////////////
1949 /// @details
1950 /// - edge_count(i): delete the edge (i-1,i), how many residues are in the
1951 /// component of the graph containing i-1?
1952 /// - jump_edge_count(i): delete jump_number i. How many residues are in
1953 /// the component of the graph containing the jump point on the
1954 /// N-terminal side of the jump.
1955 ///
1956 /// @note edge_count(cutpoint+1) doesn't really make sense
1957 /// currently set to 0 but routines should avoid looking at this
1958 /// value (see eg refold_reorder(...) )
1959 
1960 /// @note Not checked out for chemical links
1961 ///
1962 void
1963 FoldTree::setup_edge_counts() const
1964 {
1965  // redimension?
1966  if ( (int)edge_count.size() != nres_ ) {
1967  edge_count = utility::vector1<int>(nres_, 0);
1968  }
1969  if ( (int)jump_edge_count.size() != num_jump_ ) {
1970  jump_edge_count = utility::vector1<int>(num_jump_, -1);
1971  }
1972 
1973  std::fill( edge_count.begin(), edge_count.end(), 0 );
1974  std::fill( jump_edge_count.begin(), jump_edge_count.end(), -1 );
1975 
1976  min_edge_count = nres_;
1977 
1978  const_iterator const it_begin ( edge_list_.begin() );
1979  const_iterator const it_end ( edge_list_.end() );
1980  FArray1D_bool linked(nres_);
1981 
1982  for ( const_iterator it = it_begin; it != it_end; ++it ) {
1983  linked = false;
1984  int const begin_res ( std::min( it->start(), it->stop()) );
1985  int link_count (0);
1986  linked( begin_res ) = true;
1987 
1988  // find all the residues linked to begin_res, when we arent allowed
1989  // to traverse the edge *it
1990  bool new_member = true;
1991  while ( new_member ) {
1992  new_member = false;
1993 
1994  for ( const_iterator it2 = it_begin; it2 != it_end; ++it2 ) {
1995  if ( it2 == it ) continue;
1996  int const start ( std::min( it2->start(), it2->stop() ) );
1997  int const stop ( std::max( it2->start(), it2->stop() ) );
1998  int new_link(0);
1999  if ( linked(start) && !linked(stop) ) {
2000  new_link = stop;
2001  } else if ( linked(stop) && !linked(start) ) {
2002  new_link = start;
2003  }
2004  if ( new_link > 0 ) {
2005  new_member = true;
2006  linked(new_link) = true;
2007  // how many new residues does this edge add?
2008  link_count +=
2009  ( it2->is_jump() ) ? 1 : stop - start;
2010  }
2011  }
2012  } // while ( new_member )
2013 
2014  if ( it->is_jump() ) {
2015  // jump
2016  int const jump_number ( it->label() );
2017  jump_edge_count[ jump_number ] = link_count + 1;
2018  min_edge_count = std::min( min_edge_count, std::max(
2019  jump_edge_count[ jump_number ],
2020  nres_ - jump_edge_count[ jump_number ] ) );
2021  } else {
2022  // peptide edge
2023  int const end_res ( std::max(it->start(), it->stop()) );
2024 
2025  for ( int i= begin_res+1; i<= end_res; ++i ) {
2026  edge_count[i] = link_count + i - begin_res;
2027  min_edge_count = std::min( min_edge_count, std::max(
2028  edge_count[i], nres_ - edge_count[i] ) );
2029  }
2030  }
2031  }
2032 
2033  for ( int i=1; i<= num_jump_; ++i ) assert( jump_edge_count[ i ] >= 1 );
2034 
2035 } // FoldTree::setup_edge_counts(...)
2036 
2037 /*
2038 Commenting this out (pb), since it doesn't really handle the case of chemical edges properly...
2039 Anyhow, going to see if we can do without this, replace with the get_residue_edge routine...
2040 
2041 ///////////////////////////////////////////////////////////////////////
2042 /// @details Returns the folding direction of a given residue. If the residue
2043 /// is in a peptide edge this is the direction in which that edge is traveled if
2044 /// we traverse the tree starting at the root.
2045 ///
2046 /// the direction of a residue could be either n2c(1) or c2n(-1) or dir_jump(0).
2047 /// for the root residue or a residue as the stopping residue of a jump, its direction
2048 /// is dir_jump; for a residue within a peptide edge(including the edge end),
2049 /// its direction is the same as the direction of the edge, i.e.,
2050 /// if edge.start < edge.stop, it is n2c direction.
2051 int
2052 FoldTree::get_residue_direction( int const seqpos ) const
2053 {
2054  // the root residue is special
2055  if ( seqpos == begin()->start() ) return dir_jump;
2056 
2057  for ( const_iterator it = begin(), it_end = end(); it != it_end; ++it ) {
2058  if ( !it->is_polymer() ) {
2059  // jump edge
2060  if ( seqpos == it->stop() ) {
2061  return dir_jump;
2062  }
2063  } else {
2064  // peptide edge
2065  if ( seqpos > it->start() && seqpos <= it->stop() ) {
2066  return 1; // forward
2067  } else if ( seqpos < it->start() && seqpos >= it->stop() ) {
2068  return -1; // backward
2069  }
2070  }
2071  }
2072  utility_exit_with_message( "no edge found that contains seqpos!" );
2073  return 0;
2074 }
2075 */
2076 
2077 
2078 Edge const &
2079 FoldTree::jump_edge( int const jump_number ) const
2080 {
2081  PyAssert(((jump_number > 0) || (jump_number <= num_jump_)),
2082  "FoldTree::jump_edge( int const jump_number ): Input variable jump_number is not a valid value.");
2083  check_order();
2084  return edge_list_[ jump_edge_[ jump_number ] ];
2085 }
2086 
2087 
2088 Edge &
2089 FoldTree::jump_edge( int const jump_number )
2090 {
2091  PyAssert(((jump_number > 0) || (jump_number <= num_jump_)),
2092  "FoldTree::jump_edge( int const jump_number ): Input variable jump_number is not a valid value.");
2093  check_order();
2094  return edge_list_[ jump_edge_[ jump_number ] ];
2095 }
2096 
2097 
2098 Edge const &
2099 FoldTree::get_residue_edge( int const seqpos ) const
2100 {
2101  if ( seqpos == root() ) utility_exit_with_message( "FoldTree:: residue_edge is undefined for root vertex" );
2102 
2103  for ( const_iterator it = begin(), it_end = end(); it != it_end; ++it ) {
2104  if ( seqpos == it->stop() ||
2105  ( it->is_peptide() &&
2106  ( ( seqpos > it->start() && seqpos <= it->stop() ) ||
2107  ( seqpos < it->start() && seqpos >= it->stop() ) ) ) ) {
2108  return *it;
2109  }
2110  }
2111  utility_exit_with_message( "no edge found that contains seqpos!" );
2112  return *begin();
2113 }
2114 
2115 /// @details Returns all edges that build a residue directly off of seqpos
2117 FoldTree::get_outgoing_edges( int const seqpos ) const
2118 {
2119  utility::vector1< Edge > outgoing;
2120  for ( const_iterator it = begin(), it_end = end(); it != it_end; ++it ) {
2121  //SML 9/30/08 it->stop() != seqpos protects one-residue poses from having outgoing edges
2122  if ( (it->start() == seqpos && it->stop() != seqpos) ||
2123  ( it->is_polymer() && ( ( seqpos >= it->start() && seqpos < it->stop() ) ||
2124  ( seqpos <= it->start() && seqpos > it->stop() ) ) ) ) {
2125  outgoing.push_back( *it );
2126  }
2127  }
2128  return outgoing;
2129 }
2130 
2131 ///////////////////////////////////////////////////////////////////////
2132 /// @details Returns the folding direction of a given polymer (peptide) residue. If the residue
2133 /// is in a peptide edge this is the direction in which that edge is traveled if
2134 /// we traverse the tree starting at the root.
2135 /// Will die if residue is root or if residue is built by jump or chemical bond.
2136 int
2137 FoldTree::get_polymer_residue_direction( int const seqpos ) const
2138 {
2139  for ( const_iterator it = begin(), it_end = end(); it != it_end; ++it ) {
2140  if ( it->is_peptide() ) {
2141  // peptide edge
2142  if ( seqpos > it->start() && seqpos <= it->stop() ) {
2143  return 1; // forward
2144  } else if ( seqpos < it->start() && seqpos >= it->stop() ) {
2145  return -1; // backward
2146  }
2147  }
2148  }
2149  utility_exit_with_message( "no peptide edge found that contains (builds) seqpos!" );
2150  return 0;
2151 }
2152 
2153 ///////////////////////////////////////////////////////////////////////
2154 /// @details Internal routine for updating data that is derived from the edge list (which is the only primary data).
2155 
2156 void
2157 FoldTree::update_cutpoints() const
2158 {
2159 
2160  // first: is_cutpoint_
2161  is_cutpoint_.dimension( DRange(0,nres_) );
2162  is_cutpoint_ = true;
2163 
2164  // loop through the peptide edges, each implies a range of NON-cutpoints:
2165  for ( const_iterator it = edge_list_.begin(),
2166  it_end = edge_list_.end(); it != it_end; ++it ) {
2167  if ( it->is_polymer() ) {
2168  for ( int j = std::min( it->start(), it->stop() ),
2169  j_end = std::max( it->start(), it->stop() ); j < j_end; ++j ) {
2170  is_cutpoint_(j) = false;
2171  }
2172  }
2173  }
2174  assert( is_cutpoint_( 0 ) && is_cutpoint_( nres_ ) );
2175 
2176  // count the cutpoints. note that 0,total_residue dont count as cutpoints
2177  // for num_cutpoint_
2178  num_cutpoint_ = 0;
2179 
2180  for ( int i = 1; i < nres_; ++i ) {
2181  if ( is_cutpoint_(i) ) {
2182  ++num_cutpoint_;
2183  }
2184  }
2185 
2186  // now cutpoint_ and cutpoint_map_ (which are inverses)
2187  cutpoint_ = utility::vector1<int>( num_cutpoint_, 0);
2188  cutpoint_map_ = utility::vector1<int>( nres_, 0);
2189 
2190  for ( int i = 1, cut=0; i < nres_; ++i ) {
2191  if ( is_cutpoint_(i) ) {
2192  cutpoint_[ ++cut ] = i;
2193  cutpoint_map_[ i ] = cut;
2194  }
2195  assert( i<nres_-1 || cut == num_cutpoint_ );
2196  }
2197 
2198 }
2199 
2200 
2201 ///////////////////////////////////////////////////////////////////////////////
2202 /// @details Internal routine for updating data that is derived from the edge list (which is the only primary data).
2203 
2204 void
2205 FoldTree::update_nres() const
2206 {
2207  int tmp_nres (0);
2208  for ( const_iterator it = edge_list_.begin(), it_end = edge_list_.end();
2209  it != it_end; ++it ) {
2210  tmp_nres = std::max( tmp_nres, std::max( it->start(), it->stop()) );
2211  }
2212  if ( tmp_nres != nres_ ) {
2213  //std::cout << "FoldTree::update_nres: nres has changed from: " << nres_
2214  // << " to: " << tmp_nres << std::endl;
2215  nres_ = tmp_nres;
2216  }
2217 }
2218 
2219 ///////////////////////////////////////////////////////////////////////////////
2220 /// @details Internal routine for updating data that is derived from the edge list (which is the only primary data).
2221 
2222 void
2223 FoldTree::update_num_jump() const
2224 {
2225  int tmp_num_jump (0);
2226  int biggest_label (0); // for debugging
2227  for ( const_iterator it = edge_list_.begin(), it_end = edge_list_.end();
2228  it != it_end; ++it ) {
2229  if ( it->is_jump() ) {
2230  ++tmp_num_jump;
2231  biggest_label = std::max( biggest_label, it->label() );
2232  }
2233  }
2234 
2235  if ( biggest_label != tmp_num_jump ) {
2236  TR.Fatal << "problem with the fold_tree: biggest_label != num_jump " <<
2237  biggest_label << ' ' << tmp_num_jump << std::endl;
2238  TR.Fatal << *this;
2239  utility_exit();
2240  }
2241 
2242  if ( tmp_num_jump != num_jump_ ) {
2243  //std::cout << "FoldTree::update_num_jump: num_jump has changed from: "
2244  // << num_jump_ << " to: " << tmp_num_jump << std::endl;
2245  num_jump_ = tmp_num_jump;
2246  }
2247 } // FoldTree::update_num_jump
2248 
2249 
2250 ///////////////////////////////////////////////////////////////////////////////
2251 /// @details Internal routine for updating data that is derived from the edge list (which is the only primary data).
2252 /// fills is_jump_point, jump_point
2253 //
2254 void
2255 FoldTree::update_jump_points() const
2256 {
2257  // re-dimension?
2258  if ( (int)is_jump_point_.size() != nres_ ) {
2259  is_jump_point_ = utility::vector1<bool>(nres_, false);
2260  } else {
2261  std::fill(is_jump_point_.begin(), is_jump_point_.end(), false);
2262  }
2263  if ( (int)jump_point_.size() != num_jump_ ) {
2264  jump_point_ = utility::vector1<std::pair<int,int> >(num_jump_);
2265  }
2266 
2267  for ( const_iterator it = edge_list_.begin(), it_end = edge_list_.end();
2268  it != it_end; ++it ) {
2269  if ( it->is_jump() ) {
2270  int const jump_number ( it->label() );
2271  assert( jump_number <= num_jump_ );
2272 
2273  is_jump_point_[ it->start() ] = true;
2274  is_jump_point_[ it->stop () ] = true;
2275 
2276  jump_point_[jump_number].first = std::min( it->start(), it->stop());
2277  jump_point_[jump_number].second = std::max( it->start(), it->stop());
2278  } else if ( it->is_chemical_bond() ) {
2279  // this is a little hacky -- calling chemical bond connections jump_points
2280  // need this for internal use, eg operations like insert_polymer_residue and delete_extra_vertices
2281  is_jump_point_[ it->start() ] = true;
2282  is_jump_point_[ it->stop () ] = true;
2283  }
2284  }
2285 }
2286 
2287 ///////////////////////////////////////////////////////////////////////////////
2288 /// @details fills jump_edge
2289 /// routines that use jump_edge should call check_order to ensure that
2290 /// its up to date
2291 ///
2292 /// @note that this is sensitive to the order of the tree
2293 /// so it's updated in check_order()
2294 ///
2295 /// Internal routine for updating data that is derived from the edge list (which is the only primary data).
2296 //
2297 
2298 void
2299 FoldTree::update_jump_edge() const
2300 {
2301  if ( (int)jump_edge_.size() != num_jump_ ) {
2302  jump_edge_ = utility::vector1<int>(num_jump_, 0);
2303  }
2304  int jump_index(0);
2305  for ( const_iterator it = edge_list_.begin(), it_end = edge_list_.end();
2306  it != it_end; ++it, ++jump_index ) {
2307  if ( it->is_jump() ) {
2308  int const jump_number ( it->label() );
2309  assert( jump_number <= num_jump_ );
2310  assert( edge_list_[ jump_index ] == *it );
2311 
2312  jump_edge_[ jump_number ] = jump_index;
2313  }
2314  }
2315 }
2316 
2317 void
2318 FoldTree::show(std::ostream & out) const
2319 {
2320  out << " Edge \t Jump Jump #\n";
2321  for ( FoldTree::const_iterator it = begin(), it_end = end();
2322  it != it_end; ++it ) {
2323 // how do I reference vector member?
2324  if (it->is_jump()) {
2325  out << " \t" << I(4,4,it->start()) << "--" << I(4,4,it->stop()) << " " << I(3,3,it->label()) << '\n';
2326  } else {
2327  out << I(4,4,it->start()) << "--" << I(4,4,it->stop()) << '\n';
2328  }
2329  }
2330  out << std::endl;
2331 }
2332 
2333 ///////////////////////////////////////////////////////////////////////////////
2334 /// @details Foldtree output to stream
2335 //
2336 // 03/23/05 -- make single-line I/O
2337 std::ostream &
2338 operator <<( std::ostream & os, FoldTree const & t )
2339 {
2340  os << "FOLD_TREE ";
2341  for ( FoldTree::const_iterator it = t.begin(), it_end = t.end();
2342  it != it_end; ++it ) {
2343  os << *it;
2344  }
2345  os << std::endl;
2346  // OL: this is not only super counter-intuitive but also makes silent-io impossible where one wants to end each line with the tag
2347  // the usual behaviour of objects is not to line-feed
2348  // standard call: std::cout << f << std::endl; --- would produce two endlines!
2349  return os;
2350 }
2351 
2352 
2353 /////////////////////////////////////////////////////////////////////////////
2354 /// @details Foldtree input from stream
2355 
2356 std::istream &
2357 operator >>( std::istream & is, FoldTree & t )
2358 {
2359  t.new_topology = true;
2360  t.edge_list_.clear();
2361 
2362  std::string tag;
2363  is >> tag;
2364  if ( !is.fail() && tag == "FOLD_TREE" ) {
2365  while ( !is.fail() ) {
2366  Edge e;
2367  is >> e;
2368  if ( is.fail() ) break;
2369  t.edge_list_.push_back( e );
2370  }
2371  is.clear();
2372  }
2373 
2374  if ( t.edge_list_.size() == 0 ) {
2375  is.setstate( std::ios_base::failbit );
2376  TR.Error << "no fold_tree info in this stream." << std::endl;
2377  } else {
2378  if ( ! t.check_fold_tree() ) {
2379  TR.Error << "bad fold_tree, reordering." << std::endl;
2380  t.reorder( t.edge_list_.begin()->start() );
2381  if ( ! t.check_fold_tree() ) {
2382  TR.Error << "bad fold_tree still bad" << std::endl;
2383  TR.Error << t;
2384  }
2385  }
2386  }
2387  return is;
2388 }
2389 
2390 /////////////////////////////////////////////////////////////////////////////
2391 /// @details Check to see if a foldtree is in valid folding order.
2392 /// To be valid, a fold tree needs to be connected, but not cyclic. So the tree
2393 /// is traversed from the root residue and if any residue has not been visited or
2394 /// has been visited multiple times, the fold tree is bad.
2395 bool
2396 FoldTree::check_fold_tree() const
2397 {
2398  if ( edge_list_.size() <= 0 ) return false;
2399  static FArray1D_bool seen;
2400  if ( new_topology ) update_nres(); // largest vertex
2401  if ( int( seen.size1() ) != nres_ ) seen.dimension( nres_ );
2402 
2403  seen = false;
2404  const_iterator it ( edge_list_.begin() );
2405  seen( it->start() ) = true;
2406  for ( const_iterator it_end = edge_list_.end(); it != it_end; ++it ) {
2407  int const start( it->start() );
2408  int const stop ( it->stop() );
2409  if ( ! seen( start ) || ( start != stop && seen( stop ) ) ) {
2410  TR.Error << "bad fold tree at edge " << start << "--" << stop << " !" << std::endl << *this << std::endl;
2411  return false;
2412  }
2413  if ( start == stop ) continue;
2414  if ( !it->is_polymer() ) {
2415  seen( stop ) = true;
2416  } else {
2417  int const dir( start < stop ? 1 : -1 );
2418  for ( int i=start + dir; i!= stop + dir; i+= dir ) {
2419  if ( seen( i ) ) {
2420  TR.Error << "bad fold tree2!" << std::endl << *this << std::endl;
2421  return false;
2422  }
2423  // for debugging purposes, do not uncomment unless you want it to
2424  // print out very often!
2425  //std::cout << "i=" << i << std::endl;
2426  seen( i ) = true;
2427  }
2428  }
2429  }
2430  for ( int i=1; i<= nres_; ++i ) {
2431  if ( !seen(i) ) {
2432  TR.Error << "bad fold tree3!" << std::endl << *this << std::endl;
2433  return false;
2434  }
2435  }
2436  return true;
2437 } // check_fold_tree()
2438 
2439 bool
2440 FoldTree::check_edges_for_atom_info() const
2441 {
2442 // if ( edge_list_.size() <= 0 ) return false;
2443 // if ( new_topology ) update_nres(); // largest vertex
2444  const_iterator it ( edge_list_.begin() );
2445  for ( const_iterator it_end = edge_list_.end(); it != it_end; ++it ) {
2446  if (it->label()== -2 && ! it->has_atom_info()){
2447  TR<< "bad chemical edge from"<< it->start() << " to "<< it->stop();
2448  return false;
2449  }
2450  }
2451  return true;
2452 }
2453 
2454 ///////////////////////////////////////////////////////////////////////////////
2455 /// @details Set connection atoms for a jump. This is not used by the foldtree, only to communicate to the
2456 /// AtomTree during construction of an atomtree from a foldtree.
2457 ///
2458 
2459 void
2460 FoldTree::set_jump_atoms(
2461  int const jump_number,
2462  std::string const& upstream_atom,
2463  std::string const& downstream_atom,
2464  bool bKeepStubInResidue /* false */
2465 )
2466 {
2467  Edge & edge( jump_edge( jump_number ) );
2468  edge.upstream_atom() = upstream_atom;
2469  edge.downstream_atom() = downstream_atom;
2470  edge.keep_stub_in_residue() = bKeepStubInResidue;
2471  // either set both or none
2472  assert( ( upstream_atom.size() && downstream_atom.size() )
2473  || ( !upstream_atom.size() && !downstream_atom.size() ) );
2474 }
2475 
2476 
2477 //version of above but makes it permutation safe!
2478 //
2479 void
2480 FoldTree::set_jump_atoms(
2481  int const jump_number,
2482  core::Size res1,
2483  std::string const& atom1,
2484  core::Size res2,
2485  std::string const& atom2,
2486  bool bKeepStubInResidue /* false */
2487 )
2488 {
2489  runtime_assert( res1 != res2 );
2490  Edge & edge( jump_edge( jump_number ) );
2491  if ( Size(edge.start()) == res1 ) {
2492  edge.upstream_atom() = atom1;
2493  } else {
2494  runtime_assert( Size(edge.stop()) == res1 );
2495  edge.downstream_atom() = atom1;
2496  }
2497 
2498  if ( Size(edge.start()) == res2 ) {
2499  edge.upstream_atom() = atom2;
2500  } else {
2501  runtime_assert( Size(edge.stop()) == res2 );
2502  edge.downstream_atom() = atom2;
2503  }
2504 
2505  edge.keep_stub_in_residue() = bKeepStubInResidue;
2506  // either set both or none
2507  assert( ( atom1.size() && atom2.size() )
2508  || ( !atom1.size() && !atom2.size() ) );
2509 }
2510 
2511 
2512 /////////////////////////////////////////////////////////////////////////////
2513 /// @details Get the upstream connection resid (connection atom # at the "start" vertex)
2514 /// If it hasn't been set return 0.
2515 /// Also see set_jump_atoms, which sets this data.
2516 //
2518 FoldTree::upstream_atom( int const jump_number ) const
2519 {
2520  Edge const & edge( jump_edge( jump_number ) );
2521  if ( edge.has_atom_info() ) {
2522  return edge.upstream_atom();
2523  } else {
2524  return "";
2525  }
2526 }
2527 
2528 
2529 /////////////////////////////////////////////////////////////////////////////
2530 /// @details Get the downstream connection atomno (connection atom # at the "stop" vertex)
2531 /// If it hasn't been set return 0.
2532 /// Also see set_jump_atoms, which sets this data.
2533 
2534 
2536 FoldTree::downstream_atom( int const jump_number ) const
2537 {
2538  Edge const & edge( jump_edge( jump_number ) );
2539  if ( edge.has_atom_info() ) {
2540  return edge.downstream_atom();
2541  } else {
2542  return "";
2543  }
2544 }
2545 
2546 
2547 
2548 /////////////////////////////////////////////////////////////////////////////
2549 // this assumes no fragment insertions across chainbreaks which is
2550 // guaranteed by the settings of the insert_size map
2551 //
2552 // borrowed some code from refold_reorder
2553 // returns the size of the largest single fixed region after
2554 // a fragment is inserted from begin_res to begin_res+size-1
2555 Size
2556 FoldTree::count_fixed_residues(
2557  Size const begin_res,
2558  Size const size,
2559  Size & min_edge_count_out
2560 ) const
2561 {
2562  check_topology();
2563  // pass out the value for min_edge_count
2564  // this is a measure of the magnitude of the largest single-residue or
2565  // single-jump
2566  // move we could possibly make. ie, its the number of fixed residues for the
2567  // move with the smallest number of fixed residues
2568  min_edge_count_out = min_edge_count;
2569  assert( size > 0 );
2570  Size const end_res ( begin_res + size - 1);
2571  assert( begin_res >= 1 && end_res <= static_cast<Size> ( nres_ ) );
2572 
2573  int best = 0;
2574  if ( ! is_cutpoint_( begin_res-1 ) ) {
2575  int const n_fixed ( edge_count[ begin_res ] );
2576  if ( n_fixed > best ) {
2577  best = n_fixed;
2578  }
2579  }
2580 
2581  if ( ! is_cutpoint_( end_res ) ) {
2582  int const c_fixed ( nres_ - edge_count[ end_res + 1] );
2583  if ( c_fixed > best ) {
2584  best = c_fixed;
2585  }
2586  }
2587 
2588  // how to test this stuff?
2589  for ( int i = 1; i<= num_jump_; ++i ) {
2590  for (int j = 1; j <= 2; ++j ) {
2591  Size const pos = j == 1 ? jump_point_[i].first : jump_point_[i].second;
2592  if ( begin_res <= pos && pos <= end_res ) {
2593  int const fixed
2594  ( j==1 ? nres_ - jump_edge_count[ i ] : jump_edge_count[ i ] );
2595  if ( fixed > best ) {
2596  best = fixed;
2597  }
2598  }
2599  }
2600  }
2601  return best;
2602 }
2603 
2604 void FoldTree::reassign_atoms_for_intra_residue_stubs() {
2605  assert( check_fold_tree() ); // necessary?
2606 
2607  for ( Size jump_nr = 1; jump_nr <= num_jump(); ++jump_nr ) {
2608  if ( !jump_edge( jump_nr ).keep_stub_in_residue() ) continue; // do nothing
2609 
2610  std::string anchor = "";
2611 
2612  if ( jump_edge( jump_nr ).start() == root() ) {
2613  anchor = "N";
2614  } else {
2615 
2616  Edge anchor_edge = get_residue_edge( jump_edge( jump_nr ).start() );
2617  //work out upstream Jump Atom from upstream folding direction
2618 
2619  if ( !anchor_edge.is_jump() ) {
2620  bool bN2C = anchor_edge.start() < anchor_edge.stop();
2621  if ( bN2C ) {
2622  anchor = "C";
2623  } else {
2624  anchor = "N";
2625  }
2626  } else {
2627  //if it is a jump it will be an N now or later when we get to it.
2628  anchor = "N";
2629  }
2630  }
2631 
2632  // choosing the root to be N and setting keep_Stub_in_resiude makes N-CA-C the stub
2633  // C-->CA-->N
2634  std::string root = "N";
2635  TR.Debug << "set anchor and root atom for jump " << jump_nr << " to " << anchor << " and " << root << std::endl;
2636 
2637  std::string const upstream_atom_name = ObjexxFCL::strip_whitespace( jump_edge( jump_nr ).upstream_atom() );
2638  if ( upstream_atom_name != "" && upstream_atom_name != "N" && upstream_atom_name != "C" && upstream_atom_name != "CA" ) {
2639  std::cout << "UPSTREAM_ATOM_NAME" << upstream_atom_name << std::endl;
2640  anchor = upstream_atom_name;
2641  }
2642  std::string const downstream_atom_name = ObjexxFCL::strip_whitespace( jump_edge( jump_nr ).downstream_atom() );
2643  if ( downstream_atom_name != "" && downstream_atom_name != "N" && downstream_atom_name != "C" && downstream_atom_name != "CA" ){
2644  std::cout << "DOWNSTREAM_ATOM_NAME" << downstream_atom_name << std::endl;
2645  root = downstream_atom_name;
2646  }
2647 
2648  set_jump_atoms( jump_nr, anchor, root, true /* keep_stub_in_residue */ );
2649  } // for loop
2650 }
2651 
2652 void FoldTree::put_jump_stubs_intra_residue() {
2653  // TR.Trace << (*this) << std::endl;
2654  assert( check_fold_tree() ); // necessary?
2655  for ( Size jump_nr = 1; jump_nr <= num_jump(); ++jump_nr ) {
2656  if ( ! jump_edge( jump_nr ).has_atom_info() ) {
2657  jump_edge( jump_nr ).keep_stub_in_residue() = true;
2658  } // if there is atom_info already, do not reassign
2659  } // for loop
2660  reassign_atoms_for_intra_residue_stubs();
2661 }
2662 
2663 } // namespace kinematics
2664 } // namespace core