Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
util.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/util.cc
11 /// @brief Kinematics utility functions
12 /// @author Phil Bradley
13 
14 // Unit headers
15 #include <core/kinematics/util.hh>
16 //#include <core/kinematics/tree/IntraResidueStubJumpAtom.hh>
17 // Package headers
18 // AUTO-REMOVED #include <core/id/DOF_ID_Mask.hh>
19 // AUTO-REMOVED #include <core/kinematics/constants.hh>
24 #include <core/id/TorsionID.hh>
26 #include <core/kinematics/types.hh>
27 
28 // Project headers
29 // AUTO-REMOVED #include <core/chemical/AtomType.hh>
30 // AUTO-REMOVED #include <core/chemical/VariantType.hh>
31 // AUTO-REMOVED #include <core/chemical/ResidueConnection.hh>
32 // AUTO-REMOVED #include <core/chemical/ResConnID.hh>
33 
34 // AUTO-REMOVED #include <core/id/DOF_ID_Map.hh>
35 #include <basic/Tracer.hh>
36 
37 #include <utility/excn/Exceptions.hh>
38 
39 // Numeric headers
40 #include <numeric/random/random.hh>
41 
42 // C++ headers
43 #include <cassert>
44 
45 #include <utility/vector1.hh>
46 
47 #include <ObjexxFCL/format.hh>
48 
49 
50 namespace core {
51 namespace kinematics {
52 
53 using namespace id;
54 static numeric::random::RandomGenerator RG(62457); // <- Magic number, do not change it!!!
55 static basic::Tracer TR( "core.kinematics.util");
56 
57 
58 ///////////////////////////////////////////////////////////////////////////////
59 // wrapper for the add_atom recursive function which doesn't know anything
60 // about Residues
61 //
62 /// @details recursively called until all atoms in this reside are added.
63 /// @note The Atoms that are allocated within this function are owned by the atom_ptr
64 /// which is a container of AtomOP's (see AtomPointer.fwd.hh)
65 ///
66 /// @note Returns a raw pointer for internal tree links but memory management is handled by atom_ptr
67 ///
68 
69 
72  int const atomno,
73  int const seqpos,
74  Links const & links,
75  AtomPointer1D & atom_ptr, // owns all the newly allocated atoms
76  bool const add_jump_atom
77 )
78 {
79  using namespace tree;
80 
81  // create new atom
82  AtomOP const atom_p( add_jump_atom ? static_cast< Atom* >( new JumpAtom()) : static_cast< Atom* >(new BondedAtom()));
83  atom_p->set_weak_ptr_to_self( atom_p() );
84 
85  // fill in the atom_ptr data
86  assert( atom_ptr[ atomno ] == 0 );
87  atom_ptr[ atomno ] = atom_p;
88 
89  // set the atom_id information
90  atom_p->id( AtomID( atomno, seqpos ) );
91  atom_p->parent( 0 );
92 
93  utility::vector1< Size > const & nbrs( links[ atomno ] );
94  for ( Size i=1, i_end = nbrs.size(); i<= i_end; ++i ) {
95  int const nbr( nbrs[i] );
96  if ( atom_ptr[ nbr ] != 0 ) continue;
97  atom_p->append_atom( add_atom( nbr, seqpos, links, atom_ptr, false ));
98  }
99 
100  return atom_p();
101 }
102 
103 ///////////////////////////////////////////////////////////////////////////////
104 /////////////////////////////////////////////////////////////////////////////
105 
106 /// \brief pick a postion in n_res as the cutpoint
107 ///
108 /// this is done based on probability info stored in cut_bias_sum.
109 /// This function is used during fold_tree construction.
110 int
112  Size const n_res,
113  ObjexxFCL::FArray1D_float const & cut_bias_sum
114 )
115 {
116 
117  float r = RG.uniform() * cut_bias_sum( n_res );
118 
119  int cutpoint( 0 );
120 
121  for ( Size i = 1; i <= n_res; ++i ) {
122  if ( r > cut_bias_sum(i-1) && r <= cut_bias_sum(i) ) {
123  cutpoint = i;
124  }
125  }
126 
127  if ( cutpoint == 0 ) {
128  TR.Warning << "pick loopy cutpoint = 0! setting = 1" << std::endl;
129  cutpoint = 1;
130  }
131 
132  return cutpoint;
133 }
134 
135 
136 
137 ///////////////////////////////////////////////////////////////////////////////
138 /// helper function for setup_backrub_atom_tree
141  tree::AtomCOP, // old_atom,
142  utility::vector1< id::AtomID > const & // exclude
143 )
144 {
145  utility_exit_with_message("needs to be refactored to meet new tree-building guidelines");
146  tree::AtomOP new_atom( new tree::BondedAtom() );
147  /// Remember to add a call here to new_atom->set_weak_ptr_to_self when this is refactored, if ever
148  /*
149  new_atom->parent(0);
150  new_atom->id ( old_atom->id () );
151  new_atom->xyz( old_atom->xyz() );
152 
153  // add old_atom's (non-exclude-) children
154  for ( Size i=0; i< Size(old_atom->n_children()); ++i ) { // 0-indexing AAARRGGHHH!!!
155  AtomID const & child_id( old_atom->child(i)->id() );
156  if ( std::find( exclude.begin(), exclude.end(), child_id ) == exclude.end() ) {
157  new_atom->append_atom( old_atom->child(i)->clone(0) ); // recursively copies child's children
158  }
159  }
160  */
161  return new_atom;
162 }
163 
164 
165 ///////////////////////////////////////////////////////////////////////////////
166 /// in principal, this should be the inverse of the build_tree function at the beginning
167 ///
168 // void
169 // fold_tree_from_atom_tree(
170 // conformation::ResidueCAPs const & residues
171 // AtomTree const & atom_tree,
172 // FoldTree & fold_tree
173 // )
174 // {
175 
176 // /// get all inter-residue connections
177 // utility::vector1< Edge
178 
181  utility::vector1< AtomID >, // mainchain, // make our own local copy
182  AtomID const &, // downstream_id, // mainchain child of last mainchain atom
183  AtomPointer2D const &, // old_atom_pointer,
184  utility::vector1< std::pair< Size, Size > > const &, // edges,
185  Size const //first_new_pseudo_residue
186 )
187 {
188 
189  // In the interest of making the gameguys' deadline for refactoring atomtree I'm not thinking about this right now.
190  utility_exit_with_message("This code needs to be refactored to use AtomOPs" );
191  /*
192  using utility::vector1;
193 
194  Vector const pseudo_offset( 0,0,0 );
195 // Vector const pseudo_offset( 0.25, 0.25, 0.25 );
196 
197  // constraints on the edge list (note that edges are ordered, ie i,j means edge *from* i *to* j (i-->j)
198  //
199  // -- 1,nbb is the first edge
200  //
201  // -- for each (i,j) after the first there exists an earlier edge (x,i) (ie, have to have seen first index already)
202  //
203  // -- no crossing: no pairs (i,j) and (k,l) with i<k<j<l
204  //
205  // -- for each edge (a,b), a must be downstream of all edges that contain (a,b)
206  // ie if (i,j) contains (a,b) (meaning that the interval [min(i,j),max(i,j)] contains the corresponding ab interval
207  // then there must be a path of edges leading from j to a (j,p1) (p1,p2) (p2,p3) .... (pN,a)
208  // so eg we cant have 1,10 10,7 7,4 1,4 (violated by (1,4) edge: no path from 10 --> 1 and [1,10] contains [1,4])
209  //
210  // -- no edges (i,j) with |i-j|<=1
211  //
212 
213  Size const nbb( mainchain.size() );
214  mainchain.push_back( downstream_id ); // so that we dont clone this guy
215  assert( edges[1].first == 1 && edges[1].second == nbb );
216 
217  /// we're going to add pseudo residues, one for each edge in the edges vector
218  Size n(0);
219 
220  // book-keeping
221 
222  // map from each mainchain_atom to the (possibly empty) list of pseudo-residues
223  vector1< vector1< Size > > mainchain_to_pseudo( nbb );
224 
225  vector1< bool > seen( nbb, false );
226 
227  vector1< Atom* > mainchain_atom_pointer( nbb, 0 );
228  vector1< Atom* > pseudo_atom_pointer( edges.size(), 0 );
229 
230  // create the root of the tree
231  AtomOP root( setup_cloned_atom( old_atom_pointer[ mainchain[1] ], mainchain ) );
232  mainchain_atom_pointer[ 1 ] = root;
233  seen[ 1 ] = true;
234 
235  while ( n < edges.size() ) {
236  ++n;
237  std::pair< Size, Size > const & edge( edges[n] );
238 
239  Size const a( edge.first );
240  Size const b( edge.second );
241  assert( seen[a] );
242 
243  // what should our anchor atom be?
244  // look at all pseudo rsds associated to a
245  AtomOP anchor_atom;
246  Size anchor(0);
247  vector1< Size > const & pseudo_a( mainchain_to_pseudo[a] );
248  for ( Size i=1; i<= pseudo_a.size(); ++i ) {
249  Size const nn( pseudo_a[i] );
250  assert( edges[nn].second == a );
251  if ( ( edges[nn].first < b && b < a ) || ( edges[nn].first > b && b > a ) ) {
252  anchor = nn; // dont break -- want the smallest segment containing a,b
253  }
254  }
255  if ( anchor ) {
256  anchor_atom = pseudo_atom_pointer[ anchor ];
257  } else {
258  // connect to the authentic a
259  anchor_atom = mainchain_atom_pointer[ a ];
260  }
261 
262  // has b been seen before?
263  AtomCOP old_b_atom( old_atom_pointer[ mainchain[b] ] );
264  if ( !seen[ b ] ) {
265  seen[b] = true;
266  // add b and b's non-mainchain children
267  Atom* b_atom( setup_cloned_atom( old_b_atom, mainchain ) );
268  anchor_atom->insert_atom( b_atom ); // NOTE: insert atom
269  mainchain_atom_pointer[ b ] = b_atom;
270  }
271 
272 
273  // add a new pseudo rsd at b's position
274  mainchain_to_pseudo[ b ].push_back( n );
275  Size const pseudo_b_seqpos( first_new_pseudo_residue + n - 1 );
276  AtomID const pseudo_b_id( AtomID( 1, pseudo_b_seqpos ) );
277  // delete the old one
278  Atom* old_pseudo_b_atom( old_atom_pointer[ pseudo_b_id ] );
279  old_pseudo_b_atom->parent()->delete_atom( old_pseudo_b_atom );
280  delete old_pseudo_b_atom;
281  // create a new one
282  Atom* pseudo_b_atom( new BondedAtom() );
283  pseudo_b_atom->id( pseudo_b_id );
284  pseudo_b_atom->xyz( old_b_atom->xyz() + pseudo_offset );
285  anchor_atom->append_atom( pseudo_b_atom );
286  pseudo_atom_pointer[ n ] = pseudo_b_atom;
287  std::cout << "new pseudo! " << n << ' ' << a << ' ' << b << ' ' << mainchain[a] << ' ' << mainchain[b] << ' ' <<
288  pseudo_b_seqpos << ' ' << old_b_atom->id() << ' ' <<
289  old_b_atom->xyz()[0] << ' ' <<
290  old_b_atom->xyz()[1] << ' ' <<
291  old_b_atom->xyz()[2] << std::endl;
292 
293  // check if this edge is terminal, if so add all intervening mainchain atoms and their children
294  {
295  bool terminal( true );
296  for ( Size n2=n+1; n2<= edges.size(); ++n2 ) {
297  if ( ( edges[n2].first == b ) &&
298  ( a < b && edges[n2].second < b || a > b && edges[n2].second > b ) ) {
299  terminal = false;
300  }
301  }
302 
303  if ( terminal ) {
304  int const dir( b<a ? 1 : -1 );
305  AtomOP parent_atom( pseudo_b_atom );
306  for ( int c=b+dir; c != (int)a; c += dir ) {
307  assert( !seen[c] );
308 
309  // add c and c's non-mainchain children
310  AtomCOP old_c_atom( old_atom_pointer[ mainchain[c] ] );
311  Atom* c_atom( setup_cloned_atom( old_c_atom, mainchain ) );
312  parent_atom->insert_atom( c_atom ); // at front of list since this is mainchain. may have already added kids
313  mainchain_atom_pointer[ c ] = c_atom;
314  seen[c] = true;
315 
316  parent_atom = c_atom;
317 
318  } // walk from b->a adding the mainchain atoms and their children to the tree
319 
320  } // if terminal
321 
322  } // scope
323 
324 
325  } // loop over edges, add one pseudo rsd for each edge
326 
327  // confirm that all mainchain atoms have been seen
328  for ( Size i=1; i<= nbb; ++i ) {
329  assert( seen[i] );
330  }
331  return root;
332  */
333  return 0;
334 
335 }
336 
337 /// @brief prints something like this ***1***C***1*********2***C********3****C****2********3*****
338 void
339 simple_visualize_fold_tree( FoldTree const & fold_tree, std::ostream& out ) {
340  for ( Size pos = 1; pos <= fold_tree.nres(); pos++ ) {
341  bool special( false );
342  if ( fold_tree.is_jump_point( pos ) ) {
343  for ( Size jnr=1; jnr<=fold_tree.num_jump(); jnr++ ) {
344  if ( (Size) fold_tree.jump_edge( jnr ).start() == pos || (Size)fold_tree.jump_edge( jnr ).stop() == pos ) {
345  if ( special ) out << "/";
346  out << jnr;
347  special = true;
348  }
349  }
350  }
351  if ( fold_tree.is_cutpoint( pos ) ) {
352  if ( special ) out << "/";
353  out << "C";
354  special = true;
355  }
356  if (!special ) out << "*";
357  }
358  out << std::endl;
359 }
360 
361 
362 /// @brief prints something like this ***1***C***1*********2***C********3****C****2********3*****
363 /// **********xxxxxxxxxxxxx************************************
364 void
365 simple_visualize_fold_tree_and_movemap( FoldTree const & fold_tree, MoveMap const& mm, std::ostream& out ) {
366  std::string move;
367  out << "\n";
368  for ( Size pos = 1; pos <= fold_tree.nres(); pos++ ) {
369  bool special( false );
370  if ( fold_tree.is_jump_point( pos ) ) {
371  for ( Size jnr=1; jnr<=fold_tree.num_jump(); jnr++ ) {
372  if ( (Size) fold_tree.jump_edge( jnr ).start() == pos || (Size)fold_tree.jump_edge( jnr ).stop() == pos ) {
373  if ( special ) {
374  out << "/";
375  move.push_back( '.' );
376  }
377  out << jnr;
378  move.push_back( mm.get_bb( pos ) ? '*' : 'x' );
379  special = true;
380  }
381  }
382  }
383  if ( fold_tree.is_cutpoint( pos ) ) {
384  if ( special ) {
385  out << "/";
386  move.push_back( '.' );
387  }
388  out << "C";
389  move.push_back( mm.get_bb( pos ) ? '*' : 'x' );
390  special = true;
391  }
392  if (!special ) {
393  out << "*";
394  move.push_back( mm.get_bb( pos ) ? '*' : 'x' );
395  }
396  }
397  out << "\n" << move;
398  out << std::endl;
399 }
400 
401 /// @brief prints something like this ***1***C***1*********2***C********3****C****2********3*****
402 /// **********xxxxxxxxxxxxx************************************
403 void
404 simple_visualize_fold_tree_and_movemap_bb_chi( FoldTree const & fold_tree, MoveMap const& mm, std::ostream& out ) {
405  std::string move;
406  std::string move_chi;
407  out << "\n";
408  for ( Size pos = 1; pos <= fold_tree.nres(); pos++ ) {
409  bool special( false );
410  if ( fold_tree.is_jump_point( pos ) ) {
411  for ( Size jnr=1; jnr<=fold_tree.num_jump(); jnr++ ) {
412  if ( (Size) fold_tree.jump_edge( jnr ).start() == pos || (Size)fold_tree.jump_edge( jnr ).stop() == pos ) {
413  if ( special ) {
414  out << "/";
415  move.push_back( '.' );
416  }
417  out << jnr;
418  move.push_back( mm.get_bb( pos ) ? '*' : 'x' );
419  move_chi.push_back( mm.get_chi( pos ) ? '*' : 'x' );
420  special = true;
421  }
422  }
423  }
424  if ( fold_tree.is_cutpoint( pos ) ) {
425  if ( special ) {
426  out << "/";
427  move.push_back( '.' );
428  move.push_back( '.' );
429  }
430  out << "C";
431  move.push_back( mm.get_bb( pos ) ? '*' : 'x' );
432  move_chi.push_back( mm.get_chi( pos ) ? '*' : 'x' );
433  special = true;
434  }
435  if (!special ) {
436  out << "*";
437  move_chi.push_back( mm.get_chi( pos ) ? '*' : 'x' );
438  move.push_back( mm.get_bb( pos ) ? '*' : 'x' );
439  }
440  }
441  out << "\n" << move << "\n" << move_chi;
442  out << std::endl;
443 }
444 
445 
446 ///@brief linearizes (or defoliates, if you prefer) a FoldTree. "default" FoldTrees produced by the PDB reader have all chains (peptide edges) starting from jumps relative to residue 1. This code modifies the tree to instead have all the jumps be relative to the preceding edge. It is not tested with ligands and will not work with "functional" jumps. From A to B:
447 ///A:FOLD_TREE EDGE 1 78 -1 EDGE 1 79 1 EDGE 79 454 -1 EDGE 1 455 2 EDGE 455 540 -1 EDGE 1 541 3 EDGE 541 697 -1
448 ///B:FOLD_TREE EDGE 1 78 -1 EDGE 78 79 1 EDGE 79 454 -1 EDGE 454 455 2 EDGE 455 540 -1 EDGE 540 541 3 EDGE 541 697 -1
452  for( core::kinematics::FoldTree::const_iterator it(tree.begin()), end(tree.end()); it != end; ++it){
453  //if it is not a jump, we don't modify it
454  if( !it->is_jump() ) newtree.add_edge(*it);
455  //if it is a jump, we move start() to stop-1. This is naive but works for the intended case.
456  else newtree.add_edge(core::kinematics::Edge(it->stop()-1, it->stop(), it->label()));
457  }
458  return newtree;
459 }
460 
461 
462 
463 
464 
465 
466 
467 ////////////////////////// sheffler visualize FT ////////////////////////////////////
468 
469 void replace_substr(std::string& str, const std::string from, const std::string to){
470  size_t start_pos = 0;
471  while((start_pos = str.find(from, start_pos)) != std::string::npos) {
472  str.replace(start_pos, from.length(), to);
473  start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
474  }
475 }
476 
477 std::string operator*(std::string const s, size_t n) {
478  std::string r; // empty string
479  r.reserve(n * s.size());
480  for (size_t i=0; i<n; i++) r += s;
481  return r;
482 }
483 
485  // return s;
486  int topad = npad-s.size();
487  if( topad > 0 && topad%2==0) return std::string("-")*(topad/2 ) + s + std::string("-")*(topad/2);
488  if( topad > 0 && topad%2==1) return std::string("-")*(topad/2+1) + s + std::string("-")*(topad/2);
489  else return s;
490 }
492  // return s;
493  int topad = npad-s.size();
494  if( topad > 0 ) return s + std::string("-")*topad;
495  else return s;
496 }
498  // return s;
499  int topad = npad-s.size();
500  if( topad > 0 ) return std::string("-")*topad + s;
501  else return s;
502 }
503 
504 struct Node {
505  Node(std::string _name, Size _jnum, Size _jumpfrom, Size _jumpto, char _jumpmark=(char)NULL, Size _follows=0)
506  : name(_name), jnum(_jnum), jumpfrom(_jumpfrom), jumpto(_jumpto), prefix_len(8), follows(_follows), jumpmark(_jumpmark), parent(NULL) {}
507  ~Node(){ for(utility::vector1<Node*>::iterator i = children.begin(); i != children.end(); ++i) delete *i; }
508  void setparent(Node *p) {
509  parent = p;
510  parent->children.push_back(this);
511  }
512  Node* root() { return parent==NULL ? this : parent->root(); }
514  using ObjexxFCL::string_of;
515  using std::string;
516  string s;
517  for(utility::vector1<Node*>::const_iterator ic = children.begin(); ic != children.end(); ++ic) {
518  string mark = ((*ic)->jumpmark==(char)NULL) ? "-" : string("")+(*ic)->jumpmark;
519  string vchar = children.size()==1 ? "" : (*ic==children.back() ? " " : "|");
520  string schar = children.size()==1 ? "" : (*ic==children.back() ? "\\" : "|");
521  std::string uprsd = ((*ic)->jumpfrom!=0) ? pad_dash_left(3,string_of((*ic)->jumpfrom)) : std::string("");
522  std::string dnrsd = ((*ic)->jumpto!=0) ? pad_dash_right(4,">"+string_of((*ic)->jumpto))+":" : std::string(">");
523  std::string jstr;
524  if( (*ic)->follows!=0 ) { // no mark if follows
525  jstr = "j" + string_of((*ic)->jnum) + ( ((*ic)->follows) ? "="+string_of((*ic)->follows) : "" );
526  } else {
527  jstr = mark + "j" + string_of((*ic)->jnum) + mark;
528  }
529  std::string prefix = schar + uprsd + "--"+pad_dash(prefix_len,jstr) + "--" + dnrsd;
530  string news = (*ic)->str();
531  string pad = string(" ")*(prefix.size()-1);
532  if(children.size()==1) pad += string(" ")*(name.size()+1);
533  replace_substr(news,"\n","\n"+vchar+pad);
534  if(children.size()==1) s += prefix+news;
535  else s += "\n"+prefix+news;
536  }
537  s = name + s;
538  return s;
539  }
541  Size jnum, jumpfrom, jumpto, prefix_len, follows;
542  char jumpmark;
543  Node *parent; // worried about cycles, no owning_ptr
545 };
546 
549  FoldTree const & ft;
550 
552  lb_.resize(ft.nres(),0);
553  ub_.resize(ft.nres(),0);
554  }
555 
556  void get_ft_node_bounds(Size res, Size & out_lb, Size & out_ub) {
557  if(lb_[res]==0) {
558  lb_[res]=1, ub_[res]=ft.nres();
559  for(int i = 1; i <= ft.num_cutpoint(); ++i) {
560  Size c = (Size)ft.cutpoint(i);
561  if( c < res ) lb_[res] = std::max(lb_[res],c+1);
562  if( c >= res ) ub_[res] = std::min(ub_[res],c );
563  }
564  }
565  out_lb = lb_[res];
566  out_ub = ub_[res];
567  }
568 
570  Size lb,ub; get_ft_node_bounds(res,lb,ub);
571  return lb;
572  }
573 
575  Size lb,ub; get_ft_node_bounds(res,lb,ub);
576  return lb==ub;
577  }
578 
579 
581  Size lb,ub; get_ft_node_bounds(res,lb,ub);
582  for(Size i = 1; i <= ft.num_jump(); ++i){
583  Size dn = ft.downstream_jump_residue(i);
584  if( lb <= dn && dn <= ub ) return dn;
585  }
586  return lb; // default subroot is first res
587  }
588 
589  void expand_node_labels_partial_by_contig(std::map<Size,std::string> & node_labels_partial) {
590  utility::vector1<Size> tocheck;
591  for(std::map<Size,std::string>::iterator i = node_labels_partial.begin(); i != node_labels_partial.end(); ++i) {
592  tocheck.push_back(i->first);
593  }
594  for(utility::vector1<Size>::const_iterator i = tocheck.begin(); i != tocheck.end(); ++i) {
595  for(utility::vector1<Size>::const_iterator j = tocheck.begin(); j != tocheck.end(); ++j) {
596  if( *i == *j ) continue;
597  // TR << "check " << *i << " " << *j << endl;
598  if( get_ft_node_lower_bound(*i) == get_ft_node_lower_bound(*j) ) {
599  if(node_labels_partial[*i] != node_labels_partial[*j]) {
600  utility_exit_with_message("non-matching node_labels_partial requested in same FT contig");
601  }
602  }
603  }
604  Size lb,ub; get_ft_node_bounds(*i,lb,ub);
605  for(Size ir = lb; ir <= ub; ++ir) {
606  node_labels_partial[ir] = node_labels_partial[*i];
607  }
608  }
609  }
610 
612  get_res_nodenames( std::map<Size,std::string> node_labels_partial ){
613  using ObjexxFCL::fmt::I;
614  int npad = 1;
615  if( ft.nres() > 9 ) npad = 2;
616  if( ft.nres() > 99 ) npad = 3;
617  if( ft.nres() > 999 ) npad = 4;
618  if( ft.nres() > 9999 ) npad = 5;
619  npad = 0;
620  utility::vector1<std::string> names(ft.nres(),"ERROR_this_name_was_not_set");
621  for(Size i = 1; i <= ft.nres(); ++i) {
622  Size lb,ub; get_ft_node_bounds(i,lb,ub);
623  std::string lbl = node_labels_partial.count(lb) ? node_labels_partial[lb] : "Contig";
624  // Size rt = get_ft_node_subroot(i);
625  // std::string resrange = ((lb==rt)?"":I(npad,lb)+"<-") + I(npad,rt) + ((ub==rt)?"":"->"+I(npad,ub));
626  std::string resrange = I(npad,lb) + ((ub==lb)?"":"-"+I(npad,ub));
627  names[i] = lbl + "(" + resrange + ")";
628  }
629  return names;
630  }
631 
633  Size lb,ub; get_ft_node_bounds(resi,lb,ub);
634  for(Size i=1; i <= ft.num_jump(); ++i) {
635  if( lb <= (Size)ft.downstream_jump_residue(i) && (Size)ft.downstream_jump_residue(i) <= ub ) return i;
636  }
637  return 0;
638  }
639 
640 };
641 
644  FoldTree const & ft,
645  std::map<Size,std::string> const & node_labels_partial_in,
646  std::map<Size,char> const & mark_jump_to_res,
647  std::map<Size,Size> const & jump_follows
648 ){
649  TreeVizBuilder tvb(ft);
650 
651  std::map<Size,std::string> node_labels_partial(node_labels_partial_in);
652  tvb.expand_node_labels_partial_by_contig(node_labels_partial);
653  utility::vector1<std::string> res_to_nodename = tvb.get_res_nodenames(node_labels_partial);
654 
655  // make Node array
656  std::map<std::string,Node*> nodemap;
657  for(Size ir = 1; ir <= ft.nres(); ++ir) {
658  if( nodemap.count(res_to_nodename[ir]) ) continue;
659  Size lb,ub; tvb.get_ft_node_bounds(ir,lb,ub);
660  Size jnum = tvb.get_jump_num_to_contig_of_resi(ir);
661  Size jumpfrom = (jnum&&!tvb.is_single(ft. upstream_jump_residue(jnum))) ? ft. upstream_jump_residue(jnum) : 0;
662  Size jumpto = (jnum&&!tvb.is_single(ft.downstream_jump_residue(jnum))) ? ft.downstream_jump_residue(jnum) : 0;
663  char markjump = (char)NULL;
664  for(Size jr = lb; jr <= ub; ++jr) if(mark_jump_to_res.count(jr)) markjump = mark_jump_to_res.find(jr)->second;
665  Size follows = jump_follows.find(jnum)!=jump_follows.end() ? jump_follows.find(jnum)->second : (Size)0;
666  nodemap[res_to_nodename[ir]] = new Node(res_to_nodename[ir],jnum,jumpfrom,jumpto,markjump,follows);
667  }
668  // set tree topology
669  for(Size i = 1; i <= ft.num_jump(); ++i) {
670  std::string up = res_to_nodename[ft. upstream_jump_residue(i)];
671  std::string dn = res_to_nodename[ft.downstream_jump_residue(i)];
672  if(up==dn) {
673  std::cerr << "bad jump " << i << " from " << ft.upstream_jump_residue(i) << " to " << ft.downstream_jump_residue(i) << std::endl;
674  utility_exit_with_message("BAD FOLD TREE NODES!!!!!!!");
675  }
676  nodemap[dn]->setparent(nodemap[up]);
677  }
678  // sanity check: make sure tree is connected
679  for(std::map<std::string,Node*>::const_iterator i = nodemap.begin(); i != nodemap.end(); ++i) {
680  std::string rootname0 = nodemap.begin()->second->root()->name;
681  if( rootname0 != i->second->root()->name ) utility_exit_with_message("Nodes not connected!!!");
682  // std::cerr << "=========================== " << i->second->name << " ===========================" << std::endl;
683  // std::cerr << i->second->str() << std::endl;
684  // std::cerr << "========================================================================" << std::endl;
685  }
686 
687  return nodemap.begin()->second->root()->str();
688 }
691  std::map<Size,std::string> empty_labels;
692  std::map<Size,char> empty_marks;
693  std::map<Size,Size> empty_follows;
694  return visualize_fold_tree( ft, empty_labels, empty_marks, empty_follows );
695 }
696 
698 visualize_fold_tree( FoldTree const & ft, std::map<Size,std::string> const & node_labels_partial ) {
699  std::map<Size,char> empty_marks;
700  std::map<Size,Size> empty_follows;
701  return visualize_fold_tree( ft, node_labels_partial, empty_marks, empty_follows );
702 }
703 
705 visualize_fold_tree( FoldTree const & ft, std::map<Size,char> const & mark_jump_to_res ) {
706  std::map<Size,std::string> empty_labels;
707  std::map<Size,Size> empty_follows;
708  return visualize_fold_tree( ft, empty_labels, mark_jump_to_res, empty_follows );
709 }
710 
711 // std::string show_foldtree(core::conformation::symmetry::SymmetricConformation const & symm_conf, SymmData const & symmdata) {
712 // Size Nreal = symm_conf.Symmetry_Info()->num_total_residues_without_pseudo();
713 // // get optional labels
714 // std::map<Size,std::string> node_labels_partial;
715 // for(std::map<Size,std::string>::const_iterator i = symmdata.get_virtual_num_to_id().begin(); i != symmdata.get_virtual_num_to_id().end(); ++i) {
716 // node_labels_partial[i->first+Nreal] = i->second;
717 // }
718 // // get non-unique names for each res, inefficient but enures coverage
719 // utility::vector1<std::string> res_to_nodename = get_res_nodenames(symm_conf.fold_tree(),node_labels_partial);
720 // // make Node array
721 // std::map<std::string,Node*> nodemap;
722 // for(Size ir = 1; ir <= symm_conf.size(); ++ir) {
723 // std::string dofstr = "";
724 // std::map<Size,SymDof> dofs( symm_conf.Symmetry_Info()->get_dofs() );
725 // for(std::map<Size,SymDof>::const_iterator i = dofs.begin(); i != dofs.end(); ++i) {
726 // if(symm_conf.fold_tree().downstream_jump_residue(i->first)==ir) dofstr = "ISDOF";
727 // }
728 // if( 0==nodemap.count(res_to_nodename[ir]) ) nodemap[res_to_nodename[ir]] = new Node(res_to_nodename[ir],dofstr);
729 // }
730 // // set tree topology
731 // for(int i = 1; i <= symm_conf.fold_tree().num_jump(); ++i) {
732 // std::string up = res_to_nodename[symm_conf.fold_tree(). upstream_jump_residue(i)];
733 // std::string dn = res_to_nodename[symm_conf.fold_tree().downstream_jump_residue(i)];
734 // if(up==dn) utility_exit_with_message("BAD FOLD TREE NODES!!!!!!!");
735 // nodemap[dn]->setparent(nodemap[up]);
736 // }
737 // // sanity check: make sure tree is connected
738 // for(std::map<std::string,Node*>::const_iterator i = nodemap.begin(); i != nodemap.end(); ++i) {
739 // std::string rootname0 = nodemap.begin()->second->root()->name;
740 // if( rootname0 != i->second->root()->name ) utility_exit_with_message("Nodes not connected!!!");
741 // }
742 // return nodemap.begin()->second->root()->str();
743 // }
744 
745 //////////////////////////// END sheffler visualize fold tree
746 
747 ///@brief remodel a fold tree to account for a large insertion by adding the size of the insert to upstream positions
748 ///@author Steven Lewis smlewi@gmail.com as a favor for Jared
751  core::kinematics::FoldTree const & input_tree, //return a remodeled version of this tree
752  core::Size insert_after, //add insert_size to points after this in primary sequence in the tree
753  core::Size insert_size){
754 
755  if(input_tree.is_jump_point(insert_after)){
756  throw utility::excn::EXCN_Msg_Exception("FoldTree utility remodel_fold_tree_to_account_for_insertion: I do not know how to handle insertion points that are also jump points - does the jump stay where it was or move to the end of the insert?");
757  }
758 
759  core::kinematics::FoldTree return_tree;
760 
761  typedef std::vector< core::kinematics::Edge > EdgeList; //I am not responsible for the std::vector!
762  typedef EdgeList::const_iterator ELconst_iterator;
763 
764  for( ELconst_iterator it(input_tree.begin()), end(input_tree.end()); it!=end; ++it){
765  //get a copy of the old Edge's start/stop, and update them as necessary
766  core::Size start(it->start()), stop(it->stop());
767  if(start>insert_after) start = start+insert_size;
768  if(stop>insert_after) stop = stop+insert_size;
769 
770  //copy old edge to new edge
771  core::kinematics::Edge const new_edge(
772  start,
773  stop,
774  it->label(),
775  it->start_atom(),
776  it->stop_atom(),
777  it->keep_stub_in_residue());
778 
779  //put in new fold tree
780  return_tree.add_edge(new_edge);
781  }
782 
783  //return_tree.reorder(input_tree.root()); //I am not convinced this is necessary or useful here but welcome input on the topic
784  return return_tree;
785 }
786 
787 } // namespace kinematics
788 } // namespace core