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
11 /// @brief
12 /// @author Phil Bradley
13 
14 
15 // Unit headers
17 
18 // Package headers
20 // AUTO-REMOVED #include <core/kinematics/util.hh>
21 #include <core/id/AtomID_Map.hh>
22 #include <core/id/TorsionID.hh>
23 //#include <core/id/types.hh>
24 // AUTO-REMOVED #include <core/kinematics/constants.hh>
25 #include <core/kinematics/Stub.hh>
26 
27 // Project headers
37 #include <core/id/AtomID.hh>
38 #include <core/id/NamedAtomID.hh>
39 #include <core/id/NamedStubID.hh>
43 // AUTO-REMOVED #include <core/kinematics/AtomPointer.hh>
44 #include <core/kinematics/Edge.hh>
46 #include <core/kinematics/util.hh>
47 
48 // AUTO-REMOVED #include <basic/basic.hh>
49 
50 // ObjexxFCL headers
51 // #include <ObjexxFCL/FArray1A.hh>
52 // #include <ObjexxFCL/FArray2A.hh>
53 // #include <ObjexxFCL/FArray3A.hh>
54 // #include <ObjexxFCL/format.hh>
55 // #include <ObjexxFCL/string.functions.hh> // Pretty output
56 
57 // Numeric headers
58 #include <numeric/util.hh>
59 #include <numeric/xyz.functions.hh>
60 
61 // Utility headers
62 #include <utility/assert.hh>
63 #include <utility/exit.hh>
64 #include <utility/pointer/owning_ptr.hh>
65 #include <utility/pointer/access_ptr.hh>
66 #include <utility/io/izstream.hh>
67 
68 // C++ headers
69 // #include <algorithm>
70 #include <cassert>
71 
72 #include <basic/Tracer.hh>
73 
75 
76 #include <utility/vector1.hh>
77 
78 
79 static basic::Tracer TR( "core.conformation.util" );
80 
81 
82 namespace core {
83 namespace conformation {
84 
85 void
87  Residue & moving_rsd,
88  chemical::ResidueConnection const & moving_connection,
89  Residue const & fixed_rsd,
90  chemical::ResidueConnection const & fixed_connection,
91  Conformation const & conformation,
92  bool lookup_bond_length
93 )
94 {
95 
96  // confirm that both connections are defined entirely by atoms internal to their residues,
97  // so we don't need the conformation info (which might not be correct for the moving_rsd if we
98  // are in the process of adding it to the conformation)
99  //
100  runtime_assert( moving_connection.icoor().is_internal() && fixed_connection.icoor().is_internal() );
101 
102  // a1 --- a2 --- (a3)
103  //
104  // (b2) --- b3 --- b4
105  //
106  // a3 and b2 are the pseudo-atoms built from their respective residues using the ideal geometry in the
107  // corresponding ResidueConnection objects
108  //
109  Vector
110  a1( fixed_connection.icoor().stub_atom2().xyz( fixed_rsd, conformation ) ),
111  b4( moving_connection.icoor().stub_atom2().xyz( moving_rsd, conformation ) ),
112 
113  a2( fixed_rsd.xyz( fixed_connection.atomno() ) ),
114  b3( moving_rsd.xyz( moving_connection.atomno() ) ),
115 
116  a3( fixed_connection.icoor().build( fixed_rsd, conformation ) ),
117  b2( moving_connection.icoor().build( moving_rsd, conformation ) );
118 
119  // we want to move b2 to align with a2 and b3 to align with a3. Torsion about the a2->a3 bond
120  // (ie the inter-residue bond) determined by atoms a1 and b4 (torsion set to 0 by default).
121 
122  core::Size fixed_rsd_atom_type_index = fixed_rsd.atom_type_index(fixed_connection.atomno());
123  core::Size moving_rsd_atom_type_index = moving_rsd.atom_type_index(moving_connection.atomno());
124  if( lookup_bond_length ){
125  std::cout<< "moving atom_type_index " << moving_rsd_atom_type_index<< std::endl;
126  std::cout<< "fixed atom_type_index " << fixed_rsd_atom_type_index<< std::endl;
127 
128  // Real bond_length= lookup_bond_length(fixed_rsd_atom_type_index, moving_rsd_atom_type_index);
131 
132  Real bond_length= ideal_bond_lengths->get_bond_length( fixed_rsd_atom_type_index, moving_rsd_atom_type_index);
133  Vector old_bond= a3-a2;
134  Vector new_bond= old_bond;
135  // new_bond.normalize(2);
136  new_bond.normalize(bond_length);
137  Vector offset = new_bond - old_bond;
138 
139 
140  a3 += offset;
141  //b2 -= offset;
142  }
143 
144 
145  kinematics::Stub A( a3, a2, a1 ), B( b3, b2, b4 );
146 
147  for ( Size i=1; i<= moving_rsd.natoms(); ++i ) {
148  Vector global = A.local2global( B.global2local( moving_rsd.xyz(i)));
149  //global.z(global.z() -1.1);
150  moving_rsd.set_xyz(i, global );
151  }
152 
153  Vector global_action_coord= A.local2global( B.global2local( moving_rsd.actcoord() ));
154  //global_action_coord.z(global_action_coord.z() -1.1);
155  //global_action_coord-=.47;
156  moving_rsd.actcoord() = global_action_coord;
157 
158 }
159 
160 
161 ///////////////////////////////////////////////////////////////////////////////////////
162 void
164  Size const seqpos,
165  Conformation & conformation
166 )
167 {
168  using namespace id;
169 
170  Residue const & rsd( conformation.residue( seqpos ) );
171 
172  // create a mini-conformation with
173  Conformation idl;
174  {
175  ResidueOP idl_rsd( ResidueFactory::create_residue( rsd.type() ) );
176  idl.append_residue_by_bond( *idl_rsd );
177  }
178 
179  int idl_pos(1);
180 
181  // intra-residue mainchain bonds and angles
182  Size const nbb( rsd.n_mainchain_atoms() );
183  runtime_assert( nbb >= 2 ); // or logic gets a bit trickier
184  for ( Size i=2; i<= nbb; ++i ) {
185  AtomID
186  bb1_idl( rsd.mainchain_atom(i-1), idl_pos ),
187  bb1 ( rsd.mainchain_atom(i-1), seqpos ),
188  bb2_idl( rsd.mainchain_atom( i), idl_pos ),
189  bb2 ( rsd.mainchain_atom( i), seqpos );
190 
191  // bond length
192  conformation.set_bond_length( bb1, bb2, idl.bond_length( bb1_idl, bb2_idl ) );
193 
194  if ( i<nbb ) {
195  AtomID
196  bb3_idl( rsd.mainchain_atom(i+1), idl_pos ),
197  bb3 ( rsd.mainchain_atom(i+1), seqpos );
198 
199  // bond angle
200  conformation.set_bond_angle( bb1, bb2, bb3, idl.bond_angle( bb1_idl, bb2_idl, bb3_idl ) );
201  }
202  }
203 
204  if ( seqpos>1 && rsd.is_polymer() && !rsd.is_lower_terminus() ) {
205  ResidueOP prev_rsd( ResidueFactory::create_residue( conformation.residue( seqpos-1 ).type() ) );
206  idl.prepend_polymer_residue_before_seqpos( *prev_rsd, 1, true );
207  idl_pos = 2;
208 
209  Size const nbb_prev( prev_rsd->n_mainchain_atoms() );
210  AtomID
211  bb1_idl( prev_rsd->mainchain_atom( nbb_prev ), idl_pos-1 ),
212  bb1 ( prev_rsd->mainchain_atom( nbb_prev ), seqpos-1 ),
213  bb2_idl( rsd.mainchain_atom( 1 ), idl_pos ),
214  bb2 ( rsd.mainchain_atom( 1 ), seqpos ),
215  bb3_idl( rsd.mainchain_atom( 2 ), idl_pos ),
216  bb3 ( rsd.mainchain_atom( 2 ), seqpos );
217  conformation.set_bond_angle( bb1, bb2, bb3, idl.bond_angle( bb1_idl, bb2_idl, bb3_idl ) );
218  }
219 
220  if ( seqpos < conformation.size() && rsd.is_polymer() && !rsd.is_upper_terminus() ) {
221  ResidueOP next_rsd( ResidueFactory::create_residue( conformation.residue( seqpos+1 ).type() ) );
222  idl.append_polymer_residue_after_seqpos( *next_rsd, idl_pos, true );
223 
224  AtomID
225  bb1_idl( rsd.mainchain_atom( nbb-1 ), idl_pos ),
226  bb1 ( rsd.mainchain_atom( nbb-1 ), seqpos ),
227  bb2_idl( rsd.mainchain_atom( nbb ), idl_pos ),
228  bb2 ( rsd.mainchain_atom( nbb ), seqpos ),
229  bb3_idl( next_rsd->mainchain_atom( 1 ), idl_pos+1 ),
230  bb3 ( next_rsd->mainchain_atom( 1 ), seqpos+1 );
231 
232  // bond angle
233  conformation.set_bond_angle( bb1, bb2, bb3, idl.bond_angle( bb1_idl, bb2_idl, bb3_idl ) );
234 
235  // bond length
236  conformation.set_bond_length( bb2, bb3, idl.bond_length( bb2_idl, bb3_idl ) );
237  }
238 
239 
240 
241 }
242 
243 /// @details Just sets the two bond angles and the bond length between seqpos and seqpos+1
244 
245 void
247  Size const seqpos,
248  Conformation & conformation
249 )
250 {
251  using namespace id;
252 
253  Residue const & rsd( conformation.residue( seqpos ) );
254  runtime_assert( seqpos < conformation.size() && rsd.is_polymer() && !rsd.is_upper_terminus() );
255 
256  if ( conformation.fold_tree().is_cutpoint( seqpos ) ) {
257  TR.Warning << "insert_ideal_bonds_at_polymer_junction: seqpos (" << seqpos << ") is a foldtree cutpoint, " <<
258  "returning!" << std::endl;
259  }
260 
261  // create a mini-conformation with ideal bond lengths and angles
262  Conformation idl;
263  {
264  ResidueOP idl_rsd( ResidueFactory::create_residue( rsd.type() ) );
265  idl.append_residue_by_bond( *idl_rsd );
266  }
267 
268  int idl_pos(1);
269 
270  Size const nbb( rsd.n_mainchain_atoms() );
271  runtime_assert( nbb >= 2 ); // or logic gets a bit trickier
272 
273  ResidueOP next_rsd( ResidueFactory::create_residue( conformation.residue( seqpos+1 ).type() ) );
274  idl.append_polymer_residue_after_seqpos( *next_rsd, idl_pos, true /* append with ideal geometry */ );
275 
276  AtomID
277  bb1_idl( rsd.mainchain_atom( nbb-1 ), idl_pos ),
278  bb1 ( rsd.mainchain_atom( nbb-1 ), seqpos ),
279  bb2_idl( rsd.mainchain_atom( nbb ), idl_pos ),
280  bb2 ( rsd.mainchain_atom( nbb ), seqpos ),
281  bb3_idl( next_rsd->mainchain_atom( 1 ), idl_pos+1 ),
282  bb3 ( next_rsd->mainchain_atom( 1 ), seqpos+1 ),
283  bb4_idl( next_rsd->mainchain_atom( 2 ), idl_pos+1 ),
284  bb4 ( next_rsd->mainchain_atom( 2 ), seqpos+1 );
285 
286  // bond angle
287  conformation.set_bond_angle( bb1, bb2, bb3, idl.bond_angle( bb1_idl, bb2_idl, bb3_idl ) );
288 
289  // bond length
290  conformation.set_bond_length( bb2, bb3, idl.bond_length( bb2_idl, bb3_idl ) );
291 
292  // bond angle
293  conformation.set_bond_angle( bb2, bb3, bb4, idl.bond_angle( bb2_idl, bb3_idl, bb4_idl ) );
294 
295  // fix up atoms that depend on the atoms across the bond for their torsion offsets
296  conformation.rebuild_polymer_bond_dependent_atoms( seqpos );
297 
298 }
299 
300 
301 ///////////////////////////////////////////////////////////////////////////////////////
302 void
304  Size const seqpos,
305  Conformation & conformation
306 )
307 {
308  using namespace id;
309 
310  runtime_assert( seqpos > 0 );
311  runtime_assert( conformation.size() >= seqpos );
312  runtime_assert( conformation.size() > 0 );
313  Residue const & rsd( conformation.residue( seqpos ) );
314 
315  //// create a mini-conformation with completely ideal residue ( and nbrs, if appropriate )
316 
317  Conformation idl;
318  {
319  ResidueOP idl_rsd( ResidueFactory::create_residue( rsd.type() ) );
320  idl.append_residue_by_bond( *idl_rsd );
321  }
322 
323  int idl_pos(1);
324  bool lower_connect( false ), upper_connect( false );
325 
326  if ( rsd.is_polymer() ) {
327  // add polymer nbrs?
328  if ( seqpos > 1 && !rsd.is_lower_terminus() && !conformation.fold_tree().is_cutpoint( seqpos-1 ) ) {
329  lower_connect = true;
330  ResidueOP prev_rsd( ResidueFactory::create_residue( conformation.residue( seqpos-1 ).type() ) );
331  idl.prepend_polymer_residue_before_seqpos( *prev_rsd, 1, true );
332  idl_pos = 2;
333  }
334 
335  if ( seqpos < conformation.size() && !rsd.is_upper_terminus() && !conformation.fold_tree().is_cutpoint( seqpos ) ) {
336  upper_connect = true;
337  ResidueOP next_rsd( ResidueFactory::create_residue( conformation.residue( seqpos+1 ).type() ) );
338  idl.append_polymer_residue_after_seqpos( *next_rsd, idl_pos, true );
339  }
340  }
341 
342  //// now set the torsion angles in the ideal conformation... This is to prepare for replacing rsd with
343  //// the idealized version
344 
345  // chi angles
346  for ( Size i=1; i<= rsd.nchi(); ++i ) {
347  idl.set_torsion( TorsionID( idl_pos, CHI, i ), rsd.chi( i ) );
348  }
349  // mainchain torsions, if polymer residue
350  if ( rsd.is_polymer() ) {
351  Size const nbb( rsd.n_mainchain_atoms() );
352  for ( Size i=1; i<= nbb; ++i ) {
353  //if ( ( !lower_connect && i == 1 ) || ( !upper_connect && i >= nbb-1 ) ) continue;
354  idl.set_torsion( TorsionID( idl_pos, BB, i ), rsd.mainchain_torsion( i ) );
355  }
356  }
357 
358 
359  //// now we copy the mainchain bond geometry from ideal conf into the conf to be idealized
360  if ( rsd.is_polymer() ) {
361 
362  // intra-residue mainchain bonds and angles
363  Size const nbb( rsd.n_mainchain_atoms() );
364  runtime_assert( nbb >= 2 ); // or logic gets a bit trickier
365  for ( Size i=2; i<= nbb; ++i ) {
366  AtomID
367  bb1_idl( rsd.mainchain_atom(i-1), idl_pos ),
368  bb1 ( rsd.mainchain_atom(i-1), seqpos ),
369  bb2_idl( rsd.mainchain_atom( i), idl_pos ),
370  bb2 ( rsd.mainchain_atom( i), seqpos );
371 
372  // bond length
373  conformation.set_bond_length( bb1, bb2, idl.bond_length( bb1_idl, bb2_idl ) );
374 
375  if ( i<nbb ) {
376  AtomID
377  bb3_idl( rsd.mainchain_atom(i+1), idl_pos ),
378  bb3 ( rsd.mainchain_atom(i+1), seqpos );
379 
380  // bond angle
381  conformation.set_bond_angle( bb1, bb2, bb3, idl.bond_angle( bb1_idl, bb2_idl, bb3_idl ) );
382  }
383  }
384 
385  if ( lower_connect ) {
386  Residue const & prev_rsd( idl.residue( idl_pos-1 ) );
387 
388  Size const nbb_prev( prev_rsd.n_mainchain_atoms() );
389  AtomID
390  bb1_idl( prev_rsd.mainchain_atom( nbb_prev ), idl_pos-1 ),
391  bb1 ( prev_rsd.mainchain_atom( nbb_prev ), seqpos-1 ),
392  bb2_idl( rsd.mainchain_atom( 1 ), idl_pos ),
393  bb2 ( rsd.mainchain_atom( 1 ), seqpos ),
394  bb3_idl( rsd.mainchain_atom( 2 ), idl_pos ),
395  bb3 ( rsd.mainchain_atom( 2 ), seqpos );
396  conformation.set_bond_angle( bb1, bb2, bb3, idl.bond_angle( bb1_idl, bb2_idl, bb3_idl ) );
397  }
398 
399  if ( upper_connect ) {
400  Residue const & next_rsd( idl.residue( idl_pos+1 ) );
401 
402  AtomID
403  bb1_idl( rsd.mainchain_atom( nbb-1 ), idl_pos ),
404  bb1 ( rsd.mainchain_atom( nbb-1 ), seqpos ),
405  bb2_idl( rsd.mainchain_atom( nbb ), idl_pos ),
406  bb2 ( rsd.mainchain_atom( nbb ), seqpos ),
407  bb3_idl( next_rsd.mainchain_atom( 1 ), idl_pos+1 ),
408  bb3 ( next_rsd.mainchain_atom( 1 ), seqpos+1 );
409 
410  // bond angle
411  conformation.set_bond_angle( bb1, bb2, bb3, idl.bond_angle( bb1_idl, bb2_idl, bb3_idl ) );
412 
413  // bond length
414  conformation.set_bond_length( bb2, bb3, idl.bond_length( bb2_idl, bb3_idl ) );
415  }
416  } // rsd.is_polymer()
417 
418 
419  //// now we orient the ideal residue onto the existing residue and replace it
420  ResidueOP idl_rsd( idl.residue( idl_pos ).clone() );
421 
422  // EXTREMELY SUBTLE DANGEROUS THING ABOUT HAVING Residue const &'s lying around:
423  // if we put "rsd" in place of conformation.residue( seqpos ) below, this will not behave properly.
424  // that's because the xyz's in rsd don't get updated properly to reflect the changes to the conformation
425  // a "refold" is only triggered by another call to conformation.residue
426  // May want to consider making Residue smarter about this kind of thing, ie knowing its from a
427  // Conformation... acting as an observer... could get pretty tricky though...
428  //
429  idl_rsd->orient_onto_residue( conformation.residue( seqpos ) ); // can't use rsd here!
430  conformation.replace_residue( seqpos, *idl_rsd, false );
431 
432 }
433 
434 
435 ///////////////////////////////////////////////////////////////////////////////////////
436 // NOTE: conformation is needed for polymer neighbours
437 // @author Barak 07/2009
438 bool
440  Size const seqpos,
441  Conformation const & conf,
442  Real theta_epsilon,
443  Real D_epsilon
444 )
445 {
446  using namespace core::kinematics;
447  runtime_assert( conf.size() >= seqpos && seqpos >= 1 );
448 
449  Residue const rsd( conf.residue( seqpos ) );
450 
451  // I. Create mini-conformations for both idealized and original residue + nbrs, if appropriate )
452  Conformation miniconf, miniconf_idl;
453  {
454  miniconf.append_residue_by_bond( rsd );
455  ResidueOP prsd_idl( ResidueFactory::create_residue( rsd.type() ) );
456  miniconf_idl.append_residue_by_bond( *prsd_idl );
457  }
458  // add polymer nbrs if needed
459  int seqpos_miniconf(1);
460  //bool lower_connect( false ), upper_connect( false );
461  if ( rsd.is_polymer() ) {
462  // prepending previous neighbour
463  if ( seqpos > 1 && !rsd.is_lower_terminus() && !conf.fold_tree().is_cutpoint( seqpos-1 ) ) {
464  //lower_connect = true; // set but never used ~Labonte
465  seqpos_miniconf = 2; // pushed forward by prependedq residue
466  Residue const & prev_rsd = conf.residue( seqpos-1 );
467  miniconf.safely_prepend_polymer_residue_before_seqpos // TODO: safely is probably unneeded here, verify this point
468  ( prev_rsd, 1, false /*build_ideal_geom*/);
469  ResidueOP pprev_rsd_idl( ResidueFactory::create_residue( prev_rsd.type() ) );
470  miniconf_idl.safely_prepend_polymer_residue_before_seqpos
471  ( *pprev_rsd_idl, 1, true /*build_ideal_geom*/);
472  }
473  // appending next neighbour
474  if ( seqpos < conf.size() && !rsd.is_upper_terminus() && !conf.fold_tree().is_cutpoint( seqpos ) ) {
475  //upper_connect = true; // set but never used ~Labonte
476  Residue const & next_rsd = conf.residue( seqpos+1 );
477  miniconf.safely_append_polymer_residue_after_seqpos
478  ( next_rsd, seqpos_miniconf, false /*build_ideal_geom*/ );
479  ResidueOP pnext_rsd_idl( ResidueFactory::create_residue( next_rsd.type() ) );
480  miniconf_idl.safely_append_polymer_residue_after_seqpos
481  ( *pnext_rsd_idl, seqpos_miniconf, true /*build_ideal_geom*/ );
482  }
483  }
484 
485 
486  // II. Compare angle and length of all residue bonded atoms in the new mini-conformations
487  for ( Size atom = 1, atom_end = miniconf.residue( seqpos_miniconf ).natoms();
488  atom <= atom_end;
489  ++atom )
490  {
491  id::AtomID aid(atom, seqpos_miniconf);
492  if( miniconf.atom_tree().atom(aid).is_jump() ) // skip non-bonded atoms
493  continue;
494  id::DOF_ID dof_theta(aid, id::THETA); // bond angle
495  id::DOF_ID dof_D(aid, id::D); // bond length
496  if( ! numeric::equal_by_epsilon(
497  miniconf.dof( dof_theta ), miniconf_idl.dof( dof_theta ), theta_epsilon ) ) {
498  TR << "Non-ideal residue detected: "
499  << " Residue #" << seqpos << " atom #" << atom << "( " << rsd.atom_name( atom ) << " ) " << ": "
500  << " Ideal theta=" << miniconf_idl.dof( dof_theta)
501  << ", Inspected theta=" << miniconf.dof( dof_theta )
502  << " (in Radians)"
503  << std::endl;
504  return false;
505  }
506  if( ! numeric::equal_by_epsilon(
507  miniconf.dof( dof_D), miniconf_idl.dof (dof_D), D_epsilon ) ) {
508  TR << "Non-ideal residue detected: "
509  << " Residue #" << seqpos << " atom #" << atom << "( " << rsd.atom_name( atom ) << " ) " << ": "
510  << " Ideal D=" << miniconf_idl.dof( dof_D)
511  << ", Inspected D=" << miniconf.dof( dof_D )
512  << std::endl;
513  return false;
514  }
515  }
516 
517  return true;
518 }
519 
520 
521 
522 /// @details For building variant residues, eg
523 /// @note Need conformation for context in case we have to rebuild atoms, eg backbone H
524 
525 void
527  Residue const & source_rsd,
528  Residue & target_rsd,
529  Conformation const & conformation
530 )
531 {
532 
533  Size const natoms( target_rsd.natoms() );
534 
535  utility::vector1< bool > missing( natoms, false );
536  bool any_missing( false );
537 
538  for ( Size i=1; i<= natoms; ++i ) {
539  std::string const & atom_name( target_rsd.atom_name(i) );
540  if ( source_rsd.has( atom_name ) ) {
541  target_rsd.atom( i ).xyz( source_rsd.atom( atom_name ).xyz() );
542  } else {
543  TR.Debug << "copy_residue_coordinates_and_rebuild_missing_atoms: missing atom " << target_rsd.name() << ' ' <<
544  atom_name << std::endl;
545  any_missing = true;
546  missing[i] = true;
547  }
548  }
549 
550  if ( any_missing ) {
551  target_rsd.seqpos( source_rsd.seqpos() ); // in case fill_missing_atoms needs context info
552  target_rsd.chain ( source_rsd.chain () );
553  target_rsd.fill_missing_atoms( missing, conformation );
554  }
555 
556 }
557 
558 /// @details Helper function for below
559 std::ostream &
560 print_atom( id::AtomID const & id, Conformation const & conf, std::ostream & os )
561 {
562  Residue const & rsd( conf.residue(id.rsd() ) );
563  os << rsd.atom_name( id.atomno() ) << " (" << id.atomno() << ") " << rsd.name() << ' ' << rsd.seqpos();
564  return os;
565 }
566 
567 ///
568 void
570  kinematics::tree::Atom const & atom,
571  Conformation const & conf, std::ostream & os
572 ) {
573  os << "ATOM "; print_atom( atom.id(), conf, os ) << std::endl;
574  os << "CHILDREN: ";
575  for ( Size i=0; i< atom.n_children(); ++i ) {
576  print_atom( atom.child(i)->id(), conf, os ) << ' ';
577  }
578  os << std::endl;
579  for ( Size i=0; i< atom.n_children(); ++i ) {
580  show_atom_tree( *atom.child(i), conf, os );
581  }
582 }
583 
584 /// helper function for residue replacement/residuetype switching
585 /// @note Will call new_rsd->fill_missing_atoms if the new residue has atoms
586 /// that the old one doesn't
587 
588 void
590  conformation::Conformation & conformation,
591  Size const seqpos,
592  chemical::ResidueType const & new_rsd_type
593 )
594 {
595 
596  Residue const & old_rsd( conformation.residue( seqpos ) );
597  ResidueOP new_rsd( ResidueFactory::create_residue( new_rsd_type ) );
598  conformation::copy_residue_coordinates_and_rebuild_missing_atoms( old_rsd, *new_rsd, conformation );
599  conformation.replace_residue( seqpos, *new_rsd, false );
600 
601 }
602 
603 
604 ///////////////////////////////////////////////////////////////////////////////
605 /// @brief construct a variant of an existing pose residue
606 /// @details eg make a terminus variant, and replace the orignal in pose.
607 /// @note this copies any atoms in common between old and new residues, rebuild the others
608 void
610  conformation::Conformation & conformation,
611  chemical::VariantType const & variant_type,
612  Size const seqpos
613 )
614 {
615 
616  Residue const & old_rsd( conformation.residue( seqpos ) );
617 
618  // the type of the desired variant residue
619  chemical::ResidueTypeSet const & rsd_set( old_rsd.residue_type_set() );
620  chemical::ResidueType const & new_rsd_type( rsd_set.get_residue_type_with_variant_added( old_rsd.type(), variant_type ) );
621 
623 }
624 
625 ///////////////////////////////////////////////////////////////////////////////
626 /// @brief construct a non-variant of an existing pose residue
627 /// @details eg remove a terminus variant, and replace the orignal in pose.
628 /// @note this copies any atoms in common between old and new residues, rebuild the others
629 void
631  conformation::Conformation & conformation,
632  chemical::VariantType const & variant_type,
633  Size const seqpos
634 )
635 {
636 
637  Residue const & old_rsd( conformation.residue( seqpos ) );
638 
639  // the type of the desired variant residue
640  chemical::ResidueTypeSet const & rsd_set( old_rsd.residue_type_set() );
641  chemical::ResidueType const & new_rsd_type( rsd_set.get_residue_type_with_variant_removed( old_rsd.type(), variant_type ) );
642 
644 }
645 
646 
647 ///////////////////////////////////////////////////////////////////////////////
648 void
650  conformation::Conformation & conformation,
651  Size const seqpos
652 )
653 {
655 }
656 
657 ///////////////////////////////////////////////////////////////////////////////
658 void
660  conformation::Conformation & conformation,
661  Size const seqpos
662 )
663 {
665 }
666 
667 ///////////////////////////////////////////////////////////////////////////////
668 void
670  conformation::Conformation & conformation,
671  Size const seqpos
672 )
673 {
675 }
676 
677 ///////////////////////////////////////////////////////////////////////////////
678 void
680  conformation::Conformation & conformation,
681  Size const seqpos
682 )
683 {
685 }
686 
687 
688 ///////////////////////////////////////////////////////////////////////////////
689 /// @details Build an atom-tree from a fold-tree and a set of residues
690 /// atoms in the tree are allocated with new (on the heap) and held in owning pointers in atom_pointer
691 /// @note atom_pointer is cleared at the beginning and then filled with AtomOPs to all the atoms
692 ///
693 
694 void
696  kinematics::FoldTree const & fold_tree,
697  conformation::ResidueCAPs const & residues,
698  kinematics::AtomPointer2D & atom_pointer
699  )
700 {
701  using conformation::Residue;
702 
703  // note -- we clear atom_pointer
704  atom_pointer.clear();
705  atom_pointer.resize( residues.size() );
706 
707  // build first atom. make it a "JumpAtom"
708  {
709  int const start_pos( fold_tree.root() );
710  Residue const & rsd( *(residues[start_pos]) );
711 
712  build_residue_tree( residues, rsd, fold_tree, atom_pointer[ start_pos ] );
713 
714  }
715 
716  // traverse tree, build edges
717  for ( kinematics::FoldTree::const_iterator it = fold_tree.begin(),
718  it_end = fold_tree.end(); it != it_end; ++it ) {
719  if ( it->is_jump() ) {
720  build_jump_edge( *it, residues, atom_pointer );
721 
722  } else if ( it->label() == kinematics::Edge::PEPTIDE ) {
723  // build a peptide edge
724  build_polymer_edge( *it, residues, atom_pointer );
725 
726  } else if ( it->label() == kinematics::Edge::CHEMICAL ) {
727  build_chemical_edge( *it, residues, atom_pointer );
728 
729  } else {
730  std::cerr << "Failed to identify kinematics::Edge label in core/kinematics/util.cc::build_tree()" << std::endl;
731  std::cerr << "Label = " << it->label() << std::endl;
732  utility_exit();
733  }
734  }
735 
736  // now guarantee that jump stubs are residue-internal if desired
737  for ( kinematics::FoldTree::const_iterator it = fold_tree.begin(),
738  it_end = fold_tree.end(); it != it_end; ++it ) {
739  if ( it->is_jump() && it->keep_stub_in_residue() ) {
740  promote_sameresidue_child_of_jump_atom( *it, residues, atom_pointer );
741  }
742  }
743 }
744 
745 
746 ///////////////////////////////////////////////////////////////////////////////
747 /// @details root_atomno is the root for the sub atom-tree of this edge.
748 /// anchor_atomno is the entry point of this sub atom-tree into the main atom-tree.
749 
750 void
752  kinematics::Edge const & edge,
753  conformation::ResidueCAPs const & residues,
754  kinematics::AtomPointer2D & atom_pointer
755  )
756 {
757  assert( edge.is_jump() );
758 
759  int const estart ( edge.start() );
760  int const estop ( edge.stop () );
761 
762  // these may have been set in the edge
763  Size anchor_atomno, root_atomno;
764  get_anchor_and_root_atoms( *residues[ estart ], *residues[ estop ], edge, anchor_atomno, root_atomno );
765 
766  // get the anchor atom
767  kinematics::tree::AtomOP anchor_atom( atom_pointer( id::AtomID( anchor_atomno, estart ) ) );
768  assert( anchor_atom );
769 
770  // build the new residue
771  build_residue_tree( root_atomno, *residues[ estop ], atom_pointer[ estop ], true /*Jump*/ );
772 
773  // now wire in the new residue connection
774  anchor_atom->insert_atom( atom_pointer[ id::AtomID( root_atomno, estop ) ]() );
775 
776 
777  // std::cout << "build_jump_edge: " << edge << ' ' << estop << ' ' << root_atomno << ' ' <<
778  // estart << ' ' << anchor_atomno << std::endl;
779 
780  // std::cout << "TREE AFTER BEGIN: " << edge << std::endl;
781  // anchor_atom->show();
782  // assert( anchor_atom->id() == AtomID( anchor_atomno, estart ) );
783  // std::cout << "TREE AFTER END: " << edge << std::endl;
784 
785 }
786 
787 
788 ///////////////////////////////////////////////////////////////////////////////
789 /// @details assumes that the start residue of edge has already been built. Traverse
790 ///the polymer edge residue by residue and after building sub atom-tree for this residue,
791 ///attaches the edge's subtree to the anchor_atom in the previous residue.
792 ///
793 void
795  kinematics::Edge const & edge,
796  conformation::ResidueCAPs const & residues,
797  kinematics::AtomPointer2D & atom_pointer
798  )
799 {
800  int const start( edge.start() );
801  int const stop ( edge.stop() );
802  int const dir ( edge.polymer_direction() );
803 
804  assert( dir == 1 || dir == -1 );
805 
806  id::AtomID first_anchor;
807  for ( int pos=start+dir; pos != stop + dir; pos += dir ) {
808  conformation::Residue const & rsd( *residues[pos] );
809  int const anchor_pos( pos-dir );
810  Size anchor_atomno, root_atomno;
811  get_anchor_and_root_atoms( *residues[ anchor_pos ], rsd, edge, anchor_atomno, root_atomno );
812 
813  // build the new residue tree, fill in the atom_pointer array
814  build_residue_tree( root_atomno, rsd, atom_pointer[pos], false /*Jump*/ );
815 
816  kinematics::tree::AtomOP anchor_atom( atom_pointer( id::AtomID( anchor_atomno, anchor_pos ) ) );
817  kinematics::tree::AtomOP root_atom( atom_pointer( id::AtomID( root_atomno, pos ) ) );
818  assert( anchor_atom && root_atom );
819  anchor_atom->insert_atom( root_atom() );
820  //std::cout << "build_polymer_edge: " << edge << ' ' << pos << ' ' << root_atomno << ' ' <<
821  // anchor_pos << ' ' << anchor_atomno << std::endl;
822  //if ( pos == start+dir ) first_anchor = AtomID( anchor_atomno, anchor_pos );
823  }
824  // if ( start != stop ) {
825  // std::cout << "TREE AFTER BEGIN: " << edge << std::endl;
826  // atom_pointer[ first_anchor ]->show();
827  // std::cout << "TREE AFTER END: " << edge << std::endl;
828  // }
829 }
830 
831 ///////////////////////////////////////////////////////////////////////////////
832 /// @details assumes that the start residue of edge has already been built. Traverse
833 ///the chemical edge residue by residue and after building sub atom-tree for this residue,
834 ///attaches the edge's subtree to the anchor_atom in the previous residue.
835 ///
836 void
838  kinematics::Edge const & edge,
839  conformation::ResidueCAPs const & residues,
840  kinematics::AtomPointer2D & atom_pointer
841  )
842 {
843 
844  int const estart ( edge.start() );
845  int const estop ( edge.stop () );
846 
847  // these may have been set in the edge
848  Size anchor_atomno, root_atomno;
849  get_anchor_and_root_atoms( *residues[ estart ], *residues[ estop ], edge, anchor_atomno, root_atomno );
850 
851  build_residue_tree( root_atomno, *residues[ estop ], atom_pointer[ estop ], false /*Jump*/ );
852 
853  // get the anchor atom
854  kinematics::tree::AtomOP anchor_atom( atom_pointer( id::AtomID( anchor_atomno, estart ) ) );
855  kinematics::tree::AtomOP root_atom( atom_pointer( id::AtomID( root_atomno, estop ) ) );
856  assert( anchor_atom && root_atom );
857 
858  anchor_atom->insert_atom( root_atom() );
859 }
860 
861 /////////////////////////////////////////////////////////////////////////////
862 ///\brief get the root atom for building residue atom-tree given the folding direction "dir"
863 int
865  conformation::Residue const & rsd,
866  int const dir // +1, -1, or "dir_jump"
867  )
868 {
869  // if dir == 1 or -1, we are building a contiguous edge ("peptide edge")
870  // in the fold_tree ( ==> residue should be a polymer type? )
871  int const forward( 1 );
872  int const backward( -1 );
873 
874 
875  if ( dir == forward ) {
876  // N for proteins, P for DNA
877  if ( rsd.is_polymer() ) {
878  if ( rsd.is_lower_terminus() ) {
879  // this is a little strange to be folding through a terminal residue but kinematics doesn't
880  // have to correlate perfectly with chemical
881  return rsd.mainchain_atom(1);
882  } else {
883  return rsd.lower_connect_atom(); //mainchain_atoms()[1];
884  }
885  } else {
886  return get_root_atomno( rsd, kinematics::dir_jump );
887  }
888  } else if ( dir == backward ) {
889  if ( rsd.is_polymer() ) {
890  if ( rsd.is_upper_terminus() ) {
891  // this is a little strange to be folding through a terminal residue but kinematics doesn't
892  // have to correlate perfectly with chemical
893  return rsd.mainchain_atom( rsd.mainchain_atoms().size() );
894  } else {
895  // C for proteins, O3* for DNA
896  return rsd.upper_connect_atom(); //mainchain_atoms()[ rsd.mainchain_atoms().size() ];
897  }
898  } else {
899  return get_root_atomno( rsd, kinematics::dir_jump );
900  }
901  } else {
902  assert( dir == kinematics::dir_jump );
903  // default for jumps, use the N-terminal attachment?
904  if ( rsd.mainchain_atoms().empty() ) {
905  // SHORT TERM HACK -- need to add some logic for root atomno
906  return 1;
907  } else {
908  // PB 10/29/07 - changing to use an interior mainchain atom
909  //
910  // old choice of mainchain_atoms()[1] meant that changing omega of jump_pos-1 would propagate
911  // C-terminal to jump_pos, which is bad for loop modeling where the usual assumption was that
912  // we can use loop_begin-1 and loop_end+1 as jump points
913  //
914  Size const nbb( rsd.n_mainchain_atoms() ); // 1 2 3 4 5 6 -- nbb
915  Size const mainchain_index( ( nbb-1 )/2 + 1 ); // 1 1 2 2 3 3 -- mainchain_index
916  return rsd.mainchain_atoms()[ mainchain_index ];
917  //return rsd.mainchain_atoms()[1];
918  }
919  }
920 }
921 
922 /// @details Determine which atom to use as the root of the root residue in the atomtree.
923 /// It is sometimes useful to be able to control the atom chosen as the root of the atomtree, eg in graphics.
924 /// The logic below uses atom_info stored in the foldtree for jump edges emanating from the root residue
925 /// to override the default atom (if the root residue is a jump_point and said atom_info exists)
926 ///
927 
928 Size
930  conformation::Residue const & rsd,
931  kinematics::FoldTree const & fold_tree
932  )
933 {
934  Size const seqpos( rsd.seqpos() );
935  assert( seqpos == Size( fold_tree.root() ) ); // need to refactor foldtree to use Size instead of int
936 
937  Size root_atomno = get_root_atomno( rsd, kinematics::dir_jump ); // the default setting
938 
939  if ( fold_tree.is_jump_point( seqpos ) ) {
940  for ( Size i=1; i<= fold_tree.num_jump(); ++i ) {
941  kinematics::Edge const & edge( fold_tree.jump_edge( i ) );
942  if ( seqpos == Size(edge.start()) && edge.has_atom_info() ) {
943  root_atomno = rsd.atom_index( edge.upstream_atom() );
944  TR.Debug << "Using jump " << i <<
945  " anchor atom as atomtree root " << edge.upstream_atom() << std::endl;
946  break;
947  }
948  }
949  }
950  return root_atomno;
951 }
952 
953 /// @details A wrapper function to build an atom-tree for a residue. Uses information from the foldtree to
954 /// find the proper root atom if it is not defined, and determine the direction in which to build the residue.
955 /// The goal of this function is to allow the Conformation to rebuild parts of the AtomTree in a way that is
956 /// compatible with what would be built if we erased the entire atomtree and rebuilt it using the foldtree.
957 /// Also used to build the atomtree for the root residue when we are building the atomtree from scratch.
958 
959 void
961  conformation::ResidueCAPs const & residues,
962  conformation::Residue const & rsd,
963  kinematics::FoldTree const & fold_tree,
964  kinematics::AtomPointer1D & atom_ptr
965  )
966 {
967  // determine root_atomno and whether root_atom is a jump_atom
968 
969  bool root_atom_is_jump_atom( false );
970  int root_atomno(0);
971 
972  int const seqpos( rsd.seqpos() );
973 
974  if ( seqpos == fold_tree.root() ) {
975  root_atom_is_jump_atom = true;
976 
977  root_atomno = get_root_residue_root_atomno( rsd, fold_tree );
978 
979  } else {
980  // seqpos is not the root of the fold_tree
981  kinematics::Edge const & edge( fold_tree.get_residue_edge( seqpos ) ); // the edge that builds seqpos
982 
983  if ( edge.is_peptide() ) {
984  // peptide edge
985  root_atomno = get_root_atomno( rsd, edge.polymer_direction() ); // the default setting
986  } else if ( edge.is_jump() ) {
987  // jump edge
988  root_atom_is_jump_atom = true;
989  if ( edge.has_atom_info() ) {
990  root_atomno = rsd.atom_index( edge.downstream_atom() );
991  } else {
992  root_atomno = get_root_atomno( rsd, kinematics::dir_jump ); // the default setting
993  }
994  } else {
995  //// chemical edge -- atomnumbers of connections should be programmed in
996  //assert( edge.has_atom_info() );
997  //root_atomno = rsd.atom_index( edge.downstream_atom() );
998  // Connection atoms are not always present in the edge, but might be; else use defaults.
999  int const estart ( edge.start() );
1000  int const estop ( edge.stop () );
1001  Size anchor_atno, root_atno;
1002  get_anchor_and_root_atoms( *residues[ estart ], *residues[ estop ], edge, anchor_atno, root_atno );
1003  root_atomno = (int) root_atno; // stupid Size/int confusion...
1004  }
1005  }
1006  assert( root_atomno );
1007 
1008  // now call the main build_residue_tree function
1009  build_residue_tree( root_atomno, rsd, atom_ptr, root_atom_is_jump_atom );
1010 }
1011 
1012 ///////////////////////////////////////////////////////////////////////////////
1013 /// @brief Check if this atom neighbor has been black-listed ("CUT_BOND" in params file).
1014 bool
1015 check_good_neighbor( Size const & atom_index, utility::vector1< Size > const & cut_nbrs ) {
1016  for ( Size kk=1; kk<=cut_nbrs.size(); ++kk ) {
1017  if ( cut_nbrs[kk] == atom_index ) return false;
1018  }
1019  return true;
1020 }
1021 
1022 ///////////////////////////////////////////////////////////////////////////////
1023 /// @brief is atom2 the last atom of our chi angle ?
1024 inline
1025 bool
1027  Size const atom1, // current atom
1028  Size const atom2, // potential nbr
1029  utility::vector1< utility::vector1< Size > > const & chi_atoms
1030  )
1031 {
1032  int const nchi( chi_atoms.size() );
1033 
1034  for ( int i=1; i<= nchi; ++i ) {
1035  utility::vector1< Size > const & atoms( chi_atoms[i] );
1036  if ( atom1 == atoms[2] &&
1037  atom2 == atoms[1] ) return true;
1038 
1039  if ( atom1 == atoms[3] &&
1040  atom2 == atoms[4] ) return true;
1041  }
1042  return false;
1043 
1044 }
1045 
1046 ///////////////////////////////////////////////////////////////////////////////
1047 /// @brief would we be breaking into a chi angle by adding atom2 to the tree now?
1048 inline
1049 bool
1051  Size const atom1, // current atom
1052  Size const atom2, // potential nbr
1053  utility::vector1< utility::vector1< Size > > const & chi_atoms,
1054  utility::vector1< bool > const & is_done
1055  )
1056 {
1057  int const nchi( chi_atoms.size() );
1058 
1059  //not an interruption if atom1 and atom2 delineate a chi angle.
1060  for ( int i=1; i<= nchi; ++i ) {
1061  utility::vector1< Size > const & atoms( chi_atoms[i] );
1062 
1063  if ( atom2 == atoms[2] &&
1064  ( atom1 == atoms[1] || atom1 == atoms[3] ) ) return false;
1065 
1066  if ( atom2 == atoms[3] &&
1067  ( atom1 == atoms[2] || atom1 == atoms[4] ) ) return false;
1068  }
1069 
1070 
1071  for ( int i=1; i<= nchi; ++i ) {
1072  utility::vector1< Size > const & atoms( chi_atoms[i] );
1073 
1074  if ( atom2 == atoms[2] &&
1075  atom1 != atoms[1] &&
1076  atom1 != atoms[3] ) return true;
1077 
1078  if ( atom2 == atoms[3] &&
1079  atom1 != atoms[2] &&
1080  atom1 != atoms[4] ) return true;
1081 
1082  if ( (atom2 == atoms[1] && is_done[ atoms[4] ]) ||
1083  (atom2 == atoms[4] && is_done[ atoms[1] ]) ) return true;
1084 
1085  }
1086  return false;
1087 
1088 }
1089 
1090 
1091 ///////////////////////////////////////////////////////////////////////////////
1092 /// @brief simply fill the "links" by adding, for each atom, its bonded neighbors
1093 void
1095  conformation::Residue const & rsd,
1096  kinematics::Links & links
1097  )
1098 {
1099  int const natoms( rsd.natoms() );
1100 
1101  links.clear();
1102  links.resize( natoms );
1103 
1104  for ( int atomno1=1; atomno1<= natoms; ++atomno1 ) {
1105  utility::vector1< Size > const & nbrs( rsd.nbrs( atomno1 ) );
1106  utility::vector1< Size > const & cut_nbrs( rsd.cut_bond_neighbor( atomno1 ) );
1107  for ( Size jj=1; jj<= nbrs.size(); ++jj ) {
1108  if (!check_good_neighbor( nbrs[jj], cut_nbrs ) ) continue;
1109  links[ atomno1 ].push_back( nbrs[jj] );
1110  }
1111  }
1112 }
1113 
1114 ///////////////////////////////////////////////////////////////////////////////
1115 // called recursively
1116 
1117 // Rule I -- dont enter a chi angle in the middle (atoms 2 or 3 ),
1118 // and don't enter a chi angle from one side if the other side's atoms have already been added to the tree
1119 //
1120 //
1121 // Rule II -- if you're atom 2 and atom 1 hasn't been done, put that first
1122 // likewise for atoms 3 and 4
1123 //
1124 // Rule III -- mainchain atoms 1st, tiebreaking by rule II
1125 //
1126 // Rule IV -- heavyatoms before hydrogens, subject to other three rules
1127 //
1128 /// @brief set correct order for how atoms are linked to each other.
1129 ///
1130 /// this function is called recursively.
1131 /// @li atom1 is the root of links at the current level.
1132 /// @li full_links store information about UNORDERED bonded neighbors for each atom in this residue.
1133 /// @li is_done indicates which atoms have already been linked.
1134 /// @li is_mainchain, is_chi, is_hydrogen and chi atoms are self explanatory
1135 /// @li new_links store information about ORDERED bonded neighbors (links) for each atom in this residue.
1136 void
1138  int const atom1,
1139  kinematics::Links const & full_links,
1140  utility::vector1< bool > & is_done,
1141  utility::vector1< bool > const & is_mainchain,
1142  utility::vector1< bool > const & is_chi,
1143  utility::vector1< bool > const & is_hydrogen,
1144  utility::vector1< utility::vector1< Size > > const & chi_atoms,
1145  kinematics::Links & new_links
1146  )
1147 {
1148  is_done[atom1] = true;
1149 
1150  utility::vector1< Size > const & full_l( full_links[atom1] );
1151  utility::vector1< Size > & new_l( new_links[atom1] );
1152 
1153  assert( new_l.empty() );
1154 
1155  Size const n_nbrs( full_l.size() );
1156 
1157  if ( n_nbrs == 1 ) {
1158  Size const nbr( full_l[1] );
1159  if ( !is_done[nbr] ) {
1160  // special case -- we have no choice but to add this guy otherwise setup will fail
1161  new_l.push_back( nbr );
1162  setup_atom_links( nbr, full_links, is_done, is_mainchain, is_chi, is_hydrogen, chi_atoms, new_links );
1163  }
1164  return;
1165  }
1166 
1167  // top priority -- within a chi angle, and mainchain
1168  for ( Size i=1; i<= n_nbrs; ++i ) {
1169  int const atom2( full_l[i] );
1170  if ( is_done[ atom2 ] ) continue;
1171 
1172  if ( is_mainchain[ atom2 ] && is_chi[ atom1 ] && is_chi[ atom2 ] && chi_continuation( atom1, atom2, chi_atoms ) ) {
1173  new_l.push_back( atom2 );
1174  setup_atom_links( atom2, full_links, is_done, is_mainchain, is_chi,
1175  is_hydrogen, chi_atoms, new_links );
1176  }
1177  }
1178 
1179  // next priority -- mainchain
1180  for ( Size i=1; i<= n_nbrs; ++i ) {
1181  int const atom2( full_l[i] );
1182  if ( is_done[ atom2 ] ) continue;
1183 
1184  if ( is_mainchain[ atom2 ] ) {
1185  new_l.push_back( atom2 );
1186  setup_atom_links( atom2, full_links, is_done, is_mainchain, is_chi,
1187  is_hydrogen, chi_atoms, new_links );
1188  }
1189  }
1190 
1191  // next priority -- within a chi angle and heavy.
1192  for ( Size i=1; i<= n_nbrs; ++i ) {
1193  int const atom2( full_l[i] );
1194  if ( is_done[ atom2 ] ) continue;
1195 
1196  if ( is_chi[ atom1 ] && is_chi[ atom2 ] && chi_continuation( atom1, atom2, chi_atoms ) && !is_hydrogen[ atom2 ] ) {
1197  new_l.push_back( atom2 );
1198  setup_atom_links( atom2, full_links, is_done, is_mainchain, is_chi,
1199  is_hydrogen, chi_atoms, new_links );
1200  }
1201  }
1202 
1203  // next priority -- any heavy atom chi?
1204  for ( Size i=1; i<= n_nbrs; ++i ) {
1205  int const atom2( full_l[i] );
1206  if ( is_done[ atom2 ] ) continue;
1207 
1208  if ( is_chi[ atom2 ] && !is_hydrogen[ atom2 ]) {
1209  new_l.push_back( atom2 );
1210  setup_atom_links( atom2, full_links, is_done, is_mainchain, is_chi,
1211  is_hydrogen, chi_atoms, new_links );
1212  }
1213  }
1214 
1215 
1216  // next priority -- any chi -- could be hydrogen
1217  for ( Size i=1; i<= n_nbrs; ++i ) {
1218  int const atom2( full_l[i] );
1219  if ( is_done[ atom2 ] ) continue;
1220 
1221  if ( is_chi[ atom2 ] ) {
1222  new_l.push_back( atom2 );
1223  setup_atom_links( atom2, full_links, is_done, is_mainchain, is_chi,
1224  is_hydrogen, chi_atoms, new_links );
1225  }
1226  }
1227 
1228  // next priority -- heavyatoms
1229  for ( Size i=1; i<= n_nbrs; ++i ) {
1230  int const atom2( full_l[i] );
1231  if ( is_done[ atom2 ] ) continue;
1232  if ( is_chi[ atom2 ] && chi_interruption( atom1, atom2, chi_atoms, is_done ) ) continue;
1233  if ( !is_hydrogen[ atom2 ] ) {
1234  new_l.push_back( atom2 );
1235  setup_atom_links( atom2, full_links, is_done, is_mainchain, is_chi,
1236  is_hydrogen, chi_atoms, new_links );
1237  }
1238  }
1239 
1240 
1241  // lowest priority -- hydrogens
1242  for ( Size i=1; i<= n_nbrs; ++i ) {
1243  int const atom2( full_l[i] );
1244  if ( is_done[ atom2 ] ) continue;
1245  if ( is_chi[ atom2 ] && chi_interruption( atom1, atom2, chi_atoms, is_done ) ) continue;
1246  new_l.push_back( atom2 );
1247  setup_atom_links( atom2, full_links, is_done, is_mainchain, is_chi,
1248  is_hydrogen, chi_atoms, new_links );
1249  }
1250 }
1251 
1252 ///////////////////////////////////////////////////////////////////////////////
1253 /// @brief given the root_atomno, set up rules for how other atoms are linked for this residue
1254 ///a wrapper function calling setup_atom_links recursively .
1255 void
1257  conformation::Residue const & rsd,
1258  int const root_atomno,
1259  kinematics::Links & links
1260  )
1261 {
1262  typedef utility::vector1< bool > BVec;
1263 
1264  //////////////////////////////////
1265  // get the full list of atom nbrs:
1266  kinematics::Links full_links;
1267 
1268  setup_links_simple( rsd, full_links );
1269 
1270  // natoms
1271  Size const natoms( rsd.natoms() );
1272 
1273  ////////////////
1274  // chi atoms
1275  BVec is_chi( natoms, false ); // vector bool
1276  utility::vector1< utility::vector1< Size > > const & chi_atoms
1277  ( rsd.chi_atoms() );
1278  for ( Size i=1; i<= chi_atoms.size(); ++i ) {
1279  for ( int j=1; j<= 4; ++j ) {
1280  is_chi[ chi_atoms[i][j] ] = true;
1281  }
1282  }
1283 
1284 
1285  //////////////////
1286  // mainchain atoms
1287  BVec is_mainchain( natoms, false ); // vector bool
1288  utility::vector1< Size > const & mainchain( rsd.mainchain_atoms() );
1289  for ( Size i=1; i<= mainchain.size(); ++i ) {
1290  is_mainchain[ mainchain[i] ] = true;
1291  }
1293  is_mainchain[ rsd.atom_index("OVL1") ] = true;
1294  is_mainchain[ rsd.atom_index("OVL2") ] = true;
1295  }
1297  is_mainchain[ rsd.atom_index("OVU1") ] = true;
1298  }
1299 
1300  ////////////
1301  // hydrogens
1302  BVec is_hydrogen( natoms, false );
1303  for ( Size i=1; i<= natoms; ++i ) {
1304  is_hydrogen[i] = rsd.atom_type(i).is_hydrogen();
1305  }
1306 
1307 
1308  links.clear();
1309  links.resize( natoms );
1310 
1311  BVec is_done( natoms, false ); // keep track of what's done
1312  setup_atom_links( root_atomno, full_links, is_done, is_mainchain, is_chi,
1313  is_hydrogen, chi_atoms, links );
1314 
1315 
1316 
1317  // check for an atom that wasn't added
1318  for ( Size i=1; i<= natoms; ++i ){
1319  if ( !is_done[ i ] ) {
1320  std::cout << "Unable to setup links for residue " << std::endl;
1321  for ( Size j=1; j<= natoms; ++j ) {
1322  std::cout << rsd.atom_name(j) << ' ' << is_done[j] << ' ' << is_mainchain[j] << ' ' << is_chi[j] << ' ' <<
1323  is_hydrogen[j] << std::endl;
1324  }
1325  utility_exit();
1326  }
1327  }
1328 }
1329 
1330 
1331 ///////////////////////////////////////////////////////////////////////////////
1332 ///\brief set up a local atom-tree for a residue from the defined root atom.
1333 void
1335  int const root_atomno,
1336  conformation::Residue const & rsd,
1337  kinematics::AtomPointer1D & atom_ptr,
1338  bool const root_is_jump_atom
1339  )
1340 {
1341  Size const natoms( rsd.natoms() );
1342 
1343  atom_ptr.clear();
1344  atom_ptr.resize( natoms ); // default C-TOR for AtomOP is 0 initialized
1345 
1346  // setup the atom nbrs so that the tree will match the desired torsion
1347  // angles
1348  kinematics::Links links;
1349  setup_links( rsd, root_atomno, links );
1350 
1351  // now build the residue atom-tree using the recursive function add_atom
1352  kinematics::add_atom( root_atomno, rsd.seqpos(), links, atom_ptr, root_is_jump_atom );
1353 
1354  // fill in the coordinates from the residue into the atomtree
1355  for ( Size i=1; i<= natoms; ++i ) {
1356  atom_ptr[i]->xyz( rsd.atom(i).xyz() );
1357  }
1358 }
1359 
1360 /// @details Get the incoming connection and all outgoing connections from a residue
1361 
1362 void
1364  conformation::Residue const & new_rsd,
1365  kinematics::FoldTree const & fold_tree,
1366  conformation::ResidueCAPs const & residues,
1367  id::BondID & new_rsd_in,
1368  utility::vector1< id::BondID > & new_rsd_out
1369  )
1370 {
1371 
1372  Size const seqpos( new_rsd.seqpos() );
1373 
1374  // setup incoming connection
1375  if ( fold_tree.is_root( seqpos ) ) {
1376  new_rsd_in.atom1 = id::BOGUS_ATOM_ID;
1377  new_rsd_in.atom2 = id::AtomID( get_root_residue_root_atomno( new_rsd, fold_tree ), seqpos );
1378  } else {
1379  Size anchor_atomno, root_atomno, anchor_pos;
1380  kinematics::Edge const & edge( fold_tree.get_residue_edge( seqpos ) );
1381  if ( edge.is_polymer() ) anchor_pos = seqpos - edge.polymer_direction();
1382  else anchor_pos = edge.start();
1383  get_anchor_and_root_atoms( *residues[ anchor_pos ], new_rsd, edge, anchor_atomno, root_atomno );
1384  new_rsd_in.atom1 = id::AtomID( anchor_atomno, anchor_pos );
1385  new_rsd_in.atom2 = id::AtomID( root_atomno, seqpos );
1386  }
1387 
1388 
1389  // setup the outgoing connections
1390  new_rsd_out.clear();
1391  utility::vector1< kinematics::Edge > const outgoing_edges( fold_tree.get_outgoing_edges( seqpos ) );
1392  for ( utility::vector1< kinematics::Edge >::const_iterator it= outgoing_edges.begin(); it != outgoing_edges.end(); ++it ) {
1393  Size anchor_atomno, root_atomno;
1394  Size const root_pos( ( it->is_polymer() ) ? seqpos + it->polymer_direction() : it->stop() );
1395  get_anchor_and_root_atoms( new_rsd, *residues[ root_pos ], *it, anchor_atomno, root_atomno );
1396  new_rsd_out.push_back( id::BondID( id::AtomID( anchor_atomno, seqpos ), id::AtomID( root_atomno, root_pos ) ) );
1397  }
1398 }
1399 
1400 
1401 /// @details Helper function for conformation routines.
1402 /// Uses fold_tree to deduce the incoming/outgoing connections for the new residue and the old residue
1403 /// We want it to be the case that the tree we get after this call is the same one that we would have gotten
1404 /// by calling build_tree
1405 void
1407  conformation::Residue const & new_rsd,
1408  //conformation::Residue const & old_rsd,
1409  kinematics::FoldTree const & fold_tree,
1410  conformation::ResidueCAPs const & residues,
1411  kinematics::AtomTree & atom_tree
1412  )
1413 {
1414  id::BondID new_rsd_in;
1415  utility::vector1< id::BondID > new_rsd_out;
1416 
1417  get_residue_connections( new_rsd, fold_tree, residues, new_rsd_in, new_rsd_out );
1418 
1419  // build the new atoms
1420  kinematics::AtomPointer1D new_atoms;
1421  build_residue_tree( residues, new_rsd, fold_tree, new_atoms );
1422 
1423  // now replace the atoms
1424  atom_tree.replace_residue_subtree( new_rsd_in, new_rsd_out, new_atoms );
1425 
1426  // preserve same-residue jump status if necessary
1427  if ( fold_tree.is_jump_point( new_rsd.seqpos() ) && !fold_tree.is_root( new_rsd.seqpos() ) ) {
1428  kinematics::Edge const & edge( fold_tree.get_residue_edge( new_rsd.seqpos() ) );
1429  if ( edge.is_jump() && edge.keep_stub_in_residue() ) {
1430  promote_sameresidue_child_of_jump_atom( edge, residues, atom_tree );
1431  }
1432  }
1433 }
1434 
1435 /// @brief Inserts/ appends new residue subtree into an existing atomtree
1436 /// @note The foldtree must already have been changed to reflect the new residue
1437 /// @note The residues array should already have been inserted into
1438 /// @note The sequence position of the new residue is deduced from new_rsd.seqpos()
1439 /// @note This function handles renumbering of the atomtree if necessary
1440 void
1442  conformation::Residue const & new_rsd,
1443  kinematics::FoldTree const & fold_tree,
1444  conformation::ResidueCAPs const & residues,
1445  kinematics::AtomTree & atom_tree
1446  )
1447 {
1448 
1449  Size const seqpos( new_rsd.seqpos() );
1450  Size const nres( fold_tree.nres() );
1451  Size const old_nres( atom_tree.size() );
1452  assert( nres == residues.size() && seqpos <= nres && old_nres == nres-1 );
1453 
1454  /////////////////////////////////
1455  // setup for renumbering atomtree
1456  utility::vector1< int > old2new( old_nres, 0 );
1457  for ( Size i=1; i<= old_nres; ++i ) {
1458  if ( i< seqpos ) old2new[i] = i;
1459  else old2new[i] = i+1;
1460  }
1461 
1462  // renumber the atomtree, fold_tree
1463  atom_tree.update_sequence_numbering( nres, old2new );
1464  assert( atom_tree.size() == nres );
1465 
1466  replace_residue_in_atom_tree( new_rsd, fold_tree, residues, atom_tree );
1467 
1468 }
1469 
1470 
1471 /// @details Get the atom-index of the atom to which the residue at position seqpos should be anchored in
1472 /// constructing the atomtree.
1473 
1474 int
1475 get_anchor_atomno( conformation::Residue const & anchor_rsd, Size const seqpos, kinematics::FoldTree const & fold_tree )
1476 {
1477  int anchor_atomno(0);
1478  assert( seqpos != (Size)fold_tree.root() );
1479 
1480  kinematics::Edge const & edge( fold_tree.get_residue_edge( seqpos ) );
1481 
1482  if ( edge.is_jump() ) {
1483  // jump edge
1484  assert( (seqpos == (Size)edge.stop()) && ((Size)anchor_rsd.seqpos() == (Size)edge.start()) );
1485  if ( edge.has_atom_info() ) {
1486  anchor_atomno = anchor_rsd.atom_index( edge.upstream_atom() );
1487  } else {
1488  anchor_atomno = get_anchor_atomno( anchor_rsd, kinematics::dir_jump );
1489  }
1490  } else if ( edge.is_peptide() ) {
1491  // peptide edge
1492  int const dir( edge.polymer_direction() );
1493  assert( anchor_rsd.seqpos() == seqpos-dir );
1494  anchor_atomno = get_anchor_atomno( anchor_rsd, dir );
1495  } else {
1496  // chemical edge
1497  assert( seqpos == static_cast< Size >( edge.stop() ) && anchor_rsd.seqpos() == static_cast< Size >( edge.start() ) && edge.has_atom_info() );
1498  anchor_atomno = anchor_rsd.atom_index( edge.upstream_atom() );
1499  }
1500  assert( anchor_atomno );
1501  return anchor_atomno;
1502 }
1503 
1504 ///////////////////////////////////////////////////////////////////////////////
1505 int
1507  conformation::Residue const & rsd,
1508  int const dir // forward(1), backward(-1), or "dir_jump"
1509  )
1510 {
1511  // if dir == 1 or -1, we are building a contiguous edge ("peptide edge")
1512  // in the fold_tree ( ==> residue should be a polymer type? )
1513  int const forward( 1 ), backward( -1 );
1514 
1515  if ( dir == forward ) {
1516  // C for proteins, O3* for DNA
1517  if ( rsd.is_polymer() ) {
1518  if ( rsd.is_upper_terminus() ) {
1519  // this is a little strange to be folding through a terminal residue but kinematics doesn't
1520  // have to correlate perfectly with chemical
1521  return rsd.mainchain_atom( rsd.mainchain_atoms().size() );
1522  } else {
1523  return rsd.upper_connect_atom();
1524  }
1525  } else {
1526  return get_anchor_atomno( rsd, kinematics::dir_jump );
1527  }
1528  } else if ( dir == backward ) {
1529  // N for proteins, P for DNA
1530  if ( rsd.is_polymer() ) {
1531  if ( rsd.is_lower_terminus() ) {
1532  // this is a little strange to be folding through a terminal residue but kinematics doesn't
1533  // have to correlate perfectly with chemical
1534  return rsd.mainchain_atom(1);
1535  } else {
1536  return rsd.lower_connect_atom();
1537  }
1538  } else {
1539  return get_anchor_atomno( rsd, kinematics::dir_jump );
1540  }
1541 
1542  } else {
1543  assert( dir == kinematics::dir_jump );
1544  // default for jumps, use the N-terminal attachment?
1545  if ( rsd.mainchain_atoms().empty() ) {
1546  // SHORT TERM HACK -- need to add some logic for root atomno
1547  return 1;
1548  } else {
1549  // PB 10/29/07 - changing to use an interior mainchain atom
1550  Size const nbb( rsd.n_mainchain_atoms() ); // 1 2 3 4 5 6 -- nbb
1551  Size const mainchain_index( ( nbb-1 )/2 + 1 ); // 1 1 2 2 3 3 -- mainchain_index
1552  return rsd.mainchain_atoms()[ mainchain_index ];
1553  //return rsd.mainchain_atoms()[1];
1554  }
1555  }
1556 }
1557 
1558 /// @details Determines the anchor and root atom indices based on residue types and the foldtree edge.
1559 
1560 void
1562  conformation::Residue const & anchor_rsd,
1563  conformation::Residue const & root_rsd,
1564  kinematics::Edge const & edge,
1565  Size & anchor_atomno,
1566  Size & root_atomno
1567  )
1568 {
1569  ASSERT_ONLY(Size const anchor_pos( anchor_rsd.seqpos() );)
1570  ASSERT_ONLY(Size const root_pos( root_rsd.seqpos() );)
1571 
1572  if ( edge.is_polymer() ) {
1573  // POLYMER EDGE
1574  int const dir( edge.polymer_direction() );
1575  assert( dir == 1 || dir == -1 );
1576  assert( root_pos == anchor_pos + dir );
1577  anchor_atomno = get_anchor_atomno( anchor_rsd, dir );
1578  root_atomno = get_root_atomno ( root_rsd, dir );
1579  } else {
1580  assert( anchor_pos == Size(edge.start()) && root_pos == Size(edge.stop()) );
1581  if ( edge.has_atom_info() ) {
1582  // JUMP OR CHEMICAL W/ ATOM INFO
1583  anchor_atomno = anchor_rsd.atom_index( edge.upstream_atom() );
1584  root_atomno = root_rsd.atom_index( edge.downstream_atom() );
1585  } else {
1586  if ( edge.is_jump() ) {
1587  // JUMP EDGE
1588  anchor_atomno = get_anchor_atomno( anchor_rsd, kinematics::dir_jump );
1589  root_atomno = get_root_atomno( root_rsd, kinematics::dir_jump );
1590  } else if ( edge.is_chemical_bond() ) {
1591  // CHEMICAL EDGE
1592  get_chemical_root_and_anchor_atomnos( anchor_rsd, root_rsd, anchor_atomno, root_atomno );
1593  } else {
1594  utility_exit_with_message( "Unrecognized edge type!" );
1595  }
1596  }
1597  }
1598  return;
1599 }
1600 
1601 
1602 // this code assumed we were also being passed old_rsd:
1603 // optionally debug some things before making atom_tree call
1604 /**if ( debug ) {
1605  BondID old_rsd_in;
1606  vector1< BondID > old_rsd_out;
1607  get_residue_connections( old_rsd, fold_tree, residues, old_rsd_in, old_rsd_out );
1608  assert( new_rsd_in.atom1 == old_rsd_in.atom1 && new_rsd_out.size() == old_rsd_out.size() );
1609  for ( Size i=1; i<= new_rsd_out.size(); ++i ) {
1610  assert( new_rsd_out[i].atom2 == old_rsd_out[i].atom2 );
1611  }
1612  }**/
1613 
1614 
1615 ///////////////////////////////////////////////////////////////////////////////
1616 
1617 void
1619  kinematics::Edge const & edge,
1620  conformation::ResidueCAPs const & residues,
1621  kinematics::AtomTree & atom_tree
1622 )
1623 {
1624  assert( edge.is_jump() );
1625  Size root_pos( edge.stop() ), anchor_atomno, root_atomno;
1626  get_anchor_and_root_atoms( *residues[ edge.start() ], *residues[ root_pos ], edge, anchor_atomno, root_atomno );
1627  atom_tree.promote_sameresidue_nonjump_child( id::AtomID( root_atomno, root_pos ) );
1628 }
1629 
1630 
1631 void
1633  kinematics::Edge const & edge,
1634  conformation::ResidueCAPs const & residues,
1635  kinematics::AtomPointer2D const & atom_pointer
1636 )
1637 {
1638  assert( edge.is_jump() );
1639  Size root_pos( edge.stop() ), anchor_atomno, root_atomno;
1640  get_anchor_and_root_atoms( *residues[ edge.start() ], *residues[ root_pos ], edge, anchor_atomno, root_atomno );
1641  kinematics::tree::AtomOP root_atom( atom_pointer[ id::AtomID( root_atomno, root_pos ) ]() );
1642  assert( root_atom->is_jump() );
1643  kinematics::tree::AtomOP same_residue_child( 0 );
1644  for ( Size i=0; i< root_atom->n_nonjump_children(); ++i ) {
1645  kinematics::tree::AtomOP child( atom_pointer[ root_atom->get_nonjump_atom( i )->id() ]() ); // want nonconst, use atom_pointer
1646  if ( Size(child->id().rsd()) == root_pos ) {
1647  same_residue_child = child;
1648  break;
1649  }
1650  }
1651  if ( same_residue_child ) {
1652  assert( !same_residue_child->is_jump() );
1653  root_atom->delete_atom( same_residue_child );
1654  root_atom->insert_atom( same_residue_child );
1655  } else {
1656  TR.Warning << "Unable to keep stub in residue: jump_atom has no non-jump, same-residue children!" << std::endl;
1657  }
1658 }
1659 
1660 void
1662  conformation::Residue const & rsd_anchor,
1663  conformation::Residue const & rsd_root,
1664  Size & anchor_atom_no,
1665  Size & root_atom_no
1666  )
1667 {
1668  assert( rsd_anchor.is_bonded( rsd_root ) );
1669 
1670  Size first_connection_id = rsd_anchor.connections_to_residue( rsd_root )[ 1 ];
1671  chemical::ResConnID first_connection = rsd_anchor.connect_map( first_connection_id );
1672  anchor_atom_no = rsd_anchor.residue_connection( first_connection_id ).atomno();
1673  root_atom_no = rsd_root.residue_connection( first_connection.connid() ).atomno();
1674 }
1675 
1676 ///////////////////////////////////////////////////////////////////////////////
1677 //
1678 // right now, this is used by the pose to setup a mapping which is
1679 // passed in to the atomtree when replacing one residue with another
1680 //
1681 //
1682 // maybe the behavior should really be to identify atoms with the same
1683 // name in the two residues and map them...
1684 //
1685 // oh well, this will work for rewiring backbone connections properly;
1686 // basically the atomtree will use this mapping when it is replacing
1687 // the atoms of rsd1 with the subtree formed by the atoms of rsd2
1688 // for this to work, all outgoing connections from the rsd1 atoms have
1689 // to have their rsd1-atom represented in this map, so the atomtree
1690 // knows where to attach the child when rsd2 is put in.
1691 
1692 ///
1693 /// @details only map by atom number, not by identity currently.
1694 void
1696  id::AtomID_Map< id::AtomID > & atom_map,
1697  conformation::Residue const & rsd1,
1698  conformation::Residue const & rsd2
1699  )
1700 {
1701 
1702  // PB -- this whole function is going to go away soon, so I'm not really worried about all the hacks
1703 
1704  int const seqpos1( rsd1.seqpos() );
1705  int const seqpos2( rsd2.seqpos() );
1706 
1707  utility::vector1< Size > const &
1708  mainchain1( rsd1.mainchain_atoms() ),
1709  mainchain2( rsd2.mainchain_atoms() );
1710 
1711  assert( mainchain1.size() == mainchain2.size() );
1712 
1713  // special case for virtual residues -- fpd
1714  if ( mainchain1.size() == 0 &&
1715  rsd1.type().name3() == "XXX" && rsd2.type().name3() == "XXX") {
1716  assert( rsd1.atoms().size() == rsd2.atoms().size() );
1717 
1718  for ( Size i=1, i_end = rsd1.atoms().size(); i<= i_end; ++i ) {
1719  atom_map.set( id::AtomID( i, seqpos1 ), id::AtomID( i, seqpos2 ) );
1720  }
1721  } else {
1722  for ( Size i=1, i_end = mainchain1.size(); i<= i_end; ++i ) {
1723  atom_map.set( id::AtomID( mainchain1[i], seqpos1 ),
1724  id::AtomID( mainchain2[i], seqpos2 ) );
1725  }
1726  if ( rsd1.is_DNA() && rsd2.is_DNA() ) {
1727  // special case for dna-dna jumps anchored at sidechain atoms
1728  for ( Size i=1; i<= 4; ++i ) {
1729  atom_map.set( id::AtomID( rsd1.chi_atoms(1)[i], seqpos1 ),
1730  id::AtomID( rsd2.chi_atoms(1)[i], seqpos2 ) );
1731  }
1732  }
1733 
1734  if ( rsd1.is_RNA() && rsd2.is_RNA() ) {
1735  // By the way, this is a total hack AND SHOULD NOT BE CHECKED IN
1736  // BEFORE CONSULTING WITH PHIL! -- rhiju
1737  // special case for rna-rna jumps anchored at sidechain atoms
1738  if ( rsd1.name1() == rsd2.name1() ) {
1739  for ( Size i=1; i<= rsd1.natoms(); ++i ) {
1740  atom_map.set( id::AtomID( i, seqpos1 ),
1741  id::AtomID( i, seqpos2 ) );
1742  }
1743  }
1744  }
1745 
1746  }
1747 
1748  /// Now include atoms involved in residue connections, since these might be anchor points for the atomtree
1749  for ( Size connid=1; connid<= rsd1.n_residue_connections() && connid <= rsd2.n_residue_connections(); ++connid ) {
1750  Size const atom1( rsd1.type().residue_connection( connid ).atomno() );
1751  Size const atom2( rsd2.type().residue_connection( connid ).atomno() );
1752  if ( rsd1.atom_name( atom1 ) == rsd2.atom_name( atom2 ) ) {
1753  atom_map.set( id::AtomID( atom1, seqpos1 ), id::AtomID( atom2, seqpos2 ) );
1754  }
1755  }
1756 }
1757 
1758 /// @brief Replace a CYS with a CYD or vice-versa for changing disulfide bonds.
1759 /// @param[in] index Position of the residue to replace.
1760 /// @param[in] cys_type_name3 The 3-letter name of the cys type to use: e.g. CYS
1761 /// or CYD.
1762 /// @param[inout] conf The conformation to modify
1763 /// @details Substitutes a residue with the given cys type, keeping as many of
1764 /// the existing atom positions as possible. If the original residue has a
1765 /// disulfide variant it will be removed, otherwise a disulfide variant will
1766 /// be added. Should work with any ResidueTypeSet that has the proper
1767 /// disulfide variants. If the replacement fails for any reason a warning
1768 /// will be printed.
1769 /// @return true if the replacement was successful, false otherwise.
1770 bool change_cys_state( Size const index, std::string cys_type_name3, Conformation & conf ) {
1771  // Cache information on old residue.
1772  Residue const & res( conf.residue( index ) );
1773  chemical::ResidueTypeSet const & residue_type_set = res.type().residue_type_set();
1774 
1775  // make sure we're working on a cys
1776  if ( res.aa() != chemical::aa_cys ) {
1777  TR.Warning << "WARNING: change_cys_state() was called on non-cys residue " << index << ", skipping!" << std::endl;
1778  return false;
1779  }
1780 
1781  // Get the residue type set of the desired new residue type. Unfortunately
1782  // variant types for residues define in different parameter files aren't
1783  // yet handled via functions such as ResidueTypeSet::get_residue_type_with_variant_*
1784  // functions, so we need the name3 string to grab the possible residue types and
1785  // look through them manually to find the right one.
1786  chemical::ResidueTypeCOPs const & possible_types = residue_type_set.name3_map( cys_type_name3 );
1787 
1788  // Track the variant types of the old residue type. We want the
1789  // new residue to have the same variant type as the old.
1790  utility::vector1< chemical::VariantType > variant_types = res.type().variant_types();
1791 
1792  // check and handle disulfide state
1793  if ( res.has_variant_type( chemical::DISULFIDE ) && cys_type_name3 == "CYS" ) {
1794  // if the old residue has DISULFIDE variant type then we are removing a
1795  // disulfide, so remove the variant type from the list
1796  variant_types.erase( std::find( variant_types.begin(), variant_types.end(), chemical::DISULFIDE ) );
1797  } else {
1798  if ( cys_type_name3 == "CYD" ) variant_types.push_back( chemical::DISULFIDE ); // creating a disulfide
1799  }
1800 
1801  // Run through all possible new residue types.
1802  for ( chemical::ResidueTypeCOPs::const_iterator
1803  type_iter = possible_types.begin(), type_end = possible_types.end();
1804  type_iter != type_end; ++type_iter )
1805  {
1806  bool perfect_match( true ); // indicates this type has all the same variant types as the old residue
1807  for ( Size kk = 1; kk <= variant_types.size(); ++kk ) {
1808  if ( ! (*type_iter)->has_variant_type( variant_types[ kk ] ) ) {
1809  perfect_match = false;
1810  break;
1811  }
1812  }
1813 
1814  if ( perfect_match ) { // Do replacement.
1815  ResidueOP new_res = ResidueFactory::create_residue( **type_iter, res, conf );
1817  conf.replace_residue( index, *new_res, false );
1818 
1819  return true;
1820  }
1821  }
1822 
1823  // If we are here then a residue type match wasn't found; issue error message.
1824  TR.Error << "ERROR: Couldn't find a " << cys_type_name3 << " equivalent for residue " << index << "." <<std::endl;
1825  return false;
1826 }
1827 
1830  id::AtomID const & atom_id,
1831  conformation::Residue const & rsd
1832 ){
1833  std::string atom_name;
1834  Size rsd_id;
1835  if ( atom_id.atomno() <= rsd.atoms().size() ) {
1836  atom_name = rsd.atom_name( atom_id.atomno() );
1837  rsd_id = atom_id.rsd();
1838  } else {
1839  TR.Error << "[ ERROR ] Can't resolve atom_id " << atom_id << std::endl;
1840  rsd_id = 0;
1841  atom_name ="";
1842  }
1843 
1844  return id::NamedAtomID( atom_name, rsd_id );
1845 }
1846 
1847 id::AtomID
1849  id::NamedAtomID const & named_atom_id,
1850  conformation::Residue const & rsd
1851 ){
1852  return id::AtomID( rsd.atom_index( named_atom_id.atom() ), named_atom_id.rsd() );
1853 }
1854 
1857  id::StubID const & stub_id,
1858  conformation::Residue const & rsd
1859 ){
1860  using namespace core::id;
1861  if ( stub_id.center().valid() ) {
1862  return NamedStubID(
1863  NamedAtomID( atom_id_to_named_atom_id( stub_id.center() , rsd ) ),
1864  NamedAtomID( atom_id_to_named_atom_id( stub_id.atom( 1 ), rsd ) ),
1865  NamedAtomID( atom_id_to_named_atom_id( stub_id.atom( 2 ), rsd ) ),
1866  NamedAtomID( atom_id_to_named_atom_id( stub_id.atom( 3 ), rsd ) )
1867  );
1868  } else {
1869  return NamedStubID( // TODO does this make sense? if input stub is bad, what should be done?
1870  NamedAtomID( atom_id_to_named_atom_id( stub_id.atom( 1 ), rsd ) ),
1871  NamedAtomID( atom_id_to_named_atom_id( stub_id.atom( 2 ), rsd ) ),
1872  NamedAtomID( atom_id_to_named_atom_id( stub_id.atom( 3 ), rsd ) )
1873  );
1874  }
1875 }
1876 
1877 id::StubID
1879  id::NamedStubID const & named_stub_id,
1880  conformation::Residue const & rsd
1881 ){
1882  using namespace core::id;
1883  if ( named_stub_id.center().valid() ) {
1884  return StubID(
1885  AtomID( named_atom_id_to_atom_id( named_stub_id.center() , rsd ) ),
1886  AtomID( named_atom_id_to_atom_id( named_stub_id.atom( 1 ), rsd ) ),
1887  AtomID( named_atom_id_to_atom_id( named_stub_id.atom( 2 ), rsd ) ),
1888  AtomID( named_atom_id_to_atom_id( named_stub_id.atom( 3 ), rsd ) )
1889  );
1890  } else {
1891  return StubID( // TODO does this make sense? if input stub is bad, what should be done?
1892  AtomID( named_atom_id_to_atom_id( named_stub_id.atom( 1 ), rsd ) ),
1893  AtomID( named_atom_id_to_atom_id( named_stub_id.atom( 1 ), rsd ) ),
1894  AtomID( named_atom_id_to_atom_id( named_stub_id.atom( 2 ), rsd ) ),
1895  AtomID( named_atom_id_to_atom_id( named_stub_id.atom( 3 ), rsd ) )
1896  );
1897  }
1898 }
1899 
1900 
1901 
1902 /// @brief Introduce cysteines at the specified location and define a
1903 /// disulfide bond between them.
1904 /// @details Does not do the repacking & minimization required to place the
1905 /// disulfide correctly.
1906 void
1907 form_disulfide(Conformation & conformation, Size lower_res, Size upper_res)
1908 {
1909  // Verify we're dealing with a FA conformation
1910  runtime_assert( conformation.is_fullatom() );
1911 
1912  chemical::ResidueTypeSetCAP restype_set =
1914 
1915  // Break existing disulfide bonds to lower
1916  if( conformation.residue(lower_res).aa() == chemical::aa_cys &&
1917  conformation.residue( lower_res ).has_variant_type( chemical::DISULFIDE ) &&
1918  conformation.residue_type( lower_res ).has_atom_name( "SG" ) // full atom residue
1919  )
1920  {
1921  Size const connect_atom( conformation.residue( lower_res ).atom_index( "SG" ) );
1922  Size other_res( 0 );
1923  Size conn(0);
1924  for ( conn = conformation.residue( lower_res ).type().n_residue_connections(); conn >= 1; --conn ) {
1925  if( Size( conformation.residue(lower_res).type().residue_connection(conn).atomno() ) == connect_atom ) {
1926  other_res = conformation.residue( lower_res ).connect_map( conn ).resid();
1927  break;
1928  }
1929  }
1930  if ( other_res == 0 ) {
1931  TR.Error << "Error: Residue " << lower_res << " was disulfide bonded but had no partner" << std::endl;
1932  utility_exit();
1933  }
1934 
1935  if(other_res == upper_res) {
1936  // Already a disulfide bond
1937  runtime_assert_msg(conformation.residue( upper_res ).connect_map( conn ).resid() == lower_res,
1938  "Error: Disulfide bond wasn't reciprical");
1939  return;
1940  }
1941 
1942  // Break the disulfide bond to upper_res
1943  bool result = change_cys_state( other_res, "CYS", conformation );
1944  runtime_assert_msg(result,"Error converting CYD->CYS");
1945  }
1946  else {
1947  ResidueOP lower_cyd = ResidueFactory::create_residue( restype_set->name_map("CYD"), conformation.residue(lower_res), conformation );
1949  conformation.residue(lower_res), *lower_cyd, conformation );
1950  conformation.replace_residue(lower_res, *lower_cyd, false /*backbone already oriented*/); // doug
1951  }
1952  // Break existing disulfide bonds to upper
1953  if( conformation.residue(upper_res).aa() == chemical::aa_cys &&
1954  conformation.residue( upper_res ).has_variant_type( chemical::DISULFIDE ) &&
1955  conformation.residue_type( upper_res ).has_atom_name( "SG" ) // full atom residue
1956  )
1957  {
1958  Size const connect_atom( conformation.residue( upper_res ).atom_index( "SG" ) );
1959  Size other_res( 0 );
1960  Size conn(0);
1961  for ( conn = conformation.residue( upper_res ).type().n_residue_connections(); conn >= 1; --conn ) {
1962  if( Size( conformation.residue(upper_res).type().residue_connection(conn).atomno() ) == connect_atom ) {
1963  other_res = conformation.residue( upper_res ).connect_map( conn ).resid();
1964  break;
1965  }
1966  }
1967  if ( other_res == 0 ) {
1968  TR.Warning << "Warning: Residue " << upper_res << " was disulfide bonded but had no partner" << std::endl;
1969  utility_exit();
1970  }
1971 
1972  // Break the disulfide bond to lower_res
1973  bool result = change_cys_state( other_res, "CYS", conformation );
1974  runtime_assert_msg(result,"Error converting CYD->CYS");
1975  }
1976  else {
1977  ResidueOP upper_cyd = ResidueFactory::create_residue( restype_set->name_map("CYD"), conformation.residue(upper_res), conformation );
1979  conformation.residue(upper_res), *upper_cyd, conformation );
1980  conformation.replace_residue(upper_res, *upper_cyd, false /*backbone already oriented*/);
1981  }
1982 
1983  // Both residues are now CYD
1984  runtime_assert(conformation.residue(lower_res).name() == "CYD" && conformation.residue(upper_res).name() == "CYD" );
1985 
1986  //form the bond between the two residues
1987  conformation.declare_chemical_bond(lower_res,"SG",upper_res,"SG");
1988 
1989 }
1990 
1991 /// @brief Find whether there is a disulfide defined between two residues
1992 ///
1993 /// @details We define a disulfide to exist between a pair of residues iff
1994 /// -# They are both cysteines
1995 /// -# They are bonded by their sidechains
1996 bool
1997 is_disulfide_bond( conformation::Conformation const& conformation, Size residueA_pos, Size residueB_pos)
1998 {
1999  Residue const& A = conformation.residue(residueA_pos);
2000  Residue const& B = conformation.residue(residueB_pos);
2001 
2002  if( !A.is_protein() || !B.is_protein() )
2003  return false;
2004 
2005  //both Cys or CysD
2006  if( A.type().name1() != 'C' || B.type().name1() != 'C' )
2007  return false;
2008 
2009  //bonded
2010  Size a_connect_atom;
2011  if( A.type().has_atom_name( "SG" ) )
2012  a_connect_atom = A.atom_index( "SG" );
2013  else {
2014  runtime_assert( A.type().has_atom_name( "CEN" ) ); //should be fa or centroid
2015  a_connect_atom = A.atom_index( "CEN" );
2016  }
2017  for ( Size connection = A.type().n_residue_connections(); connection >= 1; --connection ) {
2018  //check if A bonded to B
2019  if ( (Size) A.type().residue_connection( connection ).atomno() == a_connect_atom && //bond to sg, not the backbone
2020  A.connect_map( connection ).resid() == residueB_pos ) { //bonded to B
2021  return true;
2022  }
2023  }
2024 
2025  return false;
2026 }
2027 
2028 /// @brief Generate a list of all disulfide bonds in the conformation
2029 void
2030 disulfide_bonds( conformation::Conformation const& conformation, utility::vector1< std::pair<Size,Size> > & disulfides )
2031 {
2032  for( Size i=1; i<= conformation.size(); ++i)
2033  {
2034  Residue const& res(conformation.residue(i));
2035 
2036  // Skip things besides CYD
2037  if( !(res.aa() == chemical::aa_cys && res.has_variant_type(chemical::DISULFIDE) ))
2038  continue;
2039  Size connect_atom( 0);
2040  if( res.type().has_atom_name( "SG" ))
2041  connect_atom = res.atom_index( "SG" );
2042  else if( res.type().has_atom_name( "CEN" ))
2043  connect_atom = res.atom_index( "CEN" );
2044  else {
2045  TR.Warning << "Warning: unable to establish which atom to use for the disulfide to residue "
2046  << i << std::endl;
2047  continue;
2048  }
2049 
2050  Size other_res(0);
2051  Size conn;
2052  for( conn = conformation.residue( i ).type().n_residue_connections(); conn >= 1; --conn ) {
2053  if( Size( conformation.residue( i ).type().residue_connection(conn).atomno() ) == connect_atom ) {
2054  other_res = conformation.residue( i ).connect_map( conn ).resid();
2055  break;
2056  }
2057  }
2058  if ( other_res == 0 ) {
2059  TR.Error << "Error: Residue " << i << " was disulfide bonded but had no partner" << std::endl;
2060  utility_exit();
2061  }
2062 
2063  // Output the pair once
2064  if( i < other_res ) {
2065  disulfides.push_back( std::make_pair(i, other_res) );
2066  }
2067  }
2068 }
2069 
2070  // @brief determine torsion bins for given phi/psi/omega combination
2071  // assume that omega is 180 if not specified
2072  // @author Amelie Stein
2073  // @date Wed May 2 11:18:29 PDT 2012
2074  // placed here to make it accessible to a wide range of applications, but it's quite possible that placing this code elsewhere would be better
2075  // bin boundaries are currently hard-coded -- ideally in the future these can be read from external files, and thus adapted if desired
2076  char get_torsion_bin (core::Real phi, core::Real psi, core::Real omega) // omega defaults to 180 if not specified otherwise
2077  {
2078  if (phi > 180)
2079  phi -= 360; // KIC returns positive values that need to be adjusted
2080  if (psi > 180)
2081  psi -= 360;
2082  if (omega > 180)
2083  omega -= 360;
2084  char pos_bin = 'X';
2085 
2086  if (omega > 90 || omega < -90) { // trans --> uppercase letters
2087  if (phi <= 0) {
2088  if (psi < -130 || psi > 50) {
2089  pos_bin = 'B';
2090  } else { // -130 <= psi <= 50
2091  pos_bin = 'A';
2092  }
2093  } else { // phi > 0
2094  if (psi < -90 || psi > 90) {
2095  pos_bin = 'E';
2096  } else { // -90 <= psi <= 90
2097  pos_bin = 'G';
2098  }
2099  }
2100  } else { // cis --> lowercase letters
2101  if (phi <= 0) {
2102  if (psi < -130 || psi > 50) {
2103  pos_bin = 'b';
2104  } else { // -130 <= psi <= 50
2105  pos_bin = 'a';
2106  }
2107  } else { // phi > 0
2108  if (psi < -90 || psi > 90) {
2109  pos_bin = 'e';
2110  } else { // -90 <= psi <= 90
2111  pos_bin = 'g';
2112  }
2113  }
2114  }
2115  return pos_bin;
2116  }
2117 
2118 
2119 } // namespace conformation
2120 } // namespace core