Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Conformation.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
24 #include <core/id/AtomID_Map.hh>
25 #include <core/id/TorsionID.hh>
26 #include <core/id/NamedAtomID.hh>
27 
29 
30 // Project headers
37 
38 #include <basic/Tracer.hh>
39 #include <basic/prof.hh>
40 #include <basic/basic.hh>
41 #include <basic/options/option.hh>
42 #include <basic/options/keys/in.OptionKeys.gen.hh>
43 
45 
46 #include <numeric/constants.hh>
47 
48 // ObjexxFCL headers
49 #include <ObjexxFCL/format.hh>
50 #include <ObjexxFCL/string.functions.hh>
51 
52 // Numeric headers
53 #include <numeric/xyz.functions.hh>
54 // AUTO-REMOVED #include <numeric/random/random.hh>
55 
56 // Utility headers
57 #include <utility/assert.hh>
58 #include <utility/exit.hh>
59 #include <utility/pointer/owning_ptr.hh>
60 #include <utility/pointer/access_ptr.hh>
61 
62 // C++ headers
63 #include <algorithm>
64 #include <cassert>
65 #include <set>
66 
67 
68 //Auto Headers
76 #include <utility/vector1.hh>
77 #include <numeric/random/random.fwd.hh>
78 #include <boost/foreach.hpp>
79 
80 //Auto Headers
82 #define foreach BOOST_FOREACH
83 
84 using basic::T;
85 using basic::Error;
86 using basic::Warning;
87 
88 static basic::Tracer TR("core.conformation.Conformation");
89 
90 namespace core {
91 namespace conformation {
92 
93 using namespace ObjexxFCL;
94 
95 /// @brief default destructor
97 {
98  clear();
99  notify_connection_obs( ConnectionEvent( this, ConnectionEvent::DISCONNECT ) );
100 }
101 
102 
104  utility::pointer::ReferenceCount(),
105  fold_tree_( new FoldTree ),
106  atom_tree_( new AtomTree ),
107  residue_coordinates_need_updating_( false ),
108  residue_torsions_need_updating_( false ),
109  structure_moved_( true )
110 {
111  atom_tree_->set_weak_pointer_to_self( atom_tree_() );
112 }
113 
114 /// @details copy constructor
116  utility::pointer::ReferenceCount()
117 {
118  basic::ProfileThis doit( basic::CONFORMATION_COPY );
119  // residues
120  for ( Size i=1; i<= src.size(); ++i ) {
121  residues_.push_back( src.residues_[i]->clone() );
122  }
123 
124  // kinematics
125  fold_tree_ = new FoldTree( *src.fold_tree_ );
126  atom_tree_ = new AtomTree( *src.atom_tree_ );
127  atom_tree_->set_weak_pointer_to_self( atom_tree_() );
128 
129  // chain info
131  // secstruct
132  secstruct_ = src.secstruct_;
133 
134  // bookkeeping
137 
138  dof_moved_ = src.dof_moved_;
139  xyz_moved_ = src.xyz_moved_;
140 
142 
143 }
144 
145 
146 /// @details operator= implementation.
147 /// If lengths & sequence of source and target are different, will fire a
148 /// LengthEvent::INVALIDATE signal and then an IdentityEvent::INVALIDATE signal.
149 Conformation &
151 {
152  if ( &src == this ) return *this;
153 
154  basic::ProfileThis doit( basic::CONFORMATION_COPY );
155 
156  if ( src.size() == size() && sequence_matches( src ) ) {
157  in_place_copy( src );
158  } else {
159 
160  // delete current data
161  clear();
162 
163  // residues
164  for ( Size i=1; i<= src.size(); ++i ) {
165  residues_.push_back( src.residues_[i]->clone() );
166  }
167 
168  // kinematics
169  (*fold_tree_) = (*src.fold_tree_);
170  (*atom_tree_) = (*src.atom_tree_);
171 
172  // chain info
174  // secstruct
175  secstruct_ = src.secstruct_;
176 
177  // bookkeeping
180 
181  dof_moved_ = src.dof_moved_;
182  xyz_moved_ = src.xyz_moved_;
183 
185 
186  // length may have radically changed, tell length observers to invalidate their data
187  notify_length_obs( LengthEvent( this, LengthEvent::INVALIDATE, 0, 0, NULL ), false );
188  // identity may have radically changed, tell length observers to invalidate their data
189  notify_identity_obs( IdentityEvent( this, IdentityEvent::INVALIDATE, 0, NULL ), false );
190  }
191 
192  notify_xyz_obs( XYZEvent( this ) );
193 
194  return *this;
195 }
196 
197 
198 ///@details make a copy of this conformation( allocate actual memory for it )
201 {
202  return new Conformation( *this );
203 }
204 
205 ///@details determine the type of the ConformationOP
206 bool
207 Conformation::same_type_as_me( Conformation const & other, bool recurse /* = true */ ) const
208 {
209  if ( recurse ) {
210  return other.same_type_as_me( *this, false );
211  } else {
212  return true;
213  }
214 }
215 
216 /// @brief Am I composed of the same sequence of ResidueType objects as other?
217 /// DANGER! Fails, unexpectedly, if a histidine pair has a different tautomerization.
218 /// tex, 9/12/08
219 /// The above comment points out that this method isn't a clearly defined idea, because there
220 /// are many ways that someone could imagine comparing the a sequence, including:
221 /// - cutpoint variants
222 /// - tautomers
223 /// - disulfides
224 /// For some applications, it's probably to get strings of the one-letter names of
225 /// the sequence and compare those instead.
226 bool
228 {
229  if ( size() != other.size() ) return false;
230  for ( Size ii = 1, iiend = size(); ii <= iiend; ++ii ) {
231  if ( & residue(ii).type() != & other.residue(ii).type() ) {
232  return false;
233  }
234  }
235  return true;
236 }
237 
238 ///////////////////////////////////////////////////////////////////////////////
239 /// @details setup atom tree as well from the fold tree
240 void
241 Conformation::fold_tree( FoldTree const & fold_tree_in )
242 {
243  if ( size() != Size(fold_tree_in.nres()) ) {
244  std::string msg;
245  msg += "Conformation: fold_tree nres should match conformation nres. conformation nres: ";
246  msg += string_of( size() );
247  msg += " fold_tree nres: " + string_of( fold_tree_in.nres() ) ;
248  utility_exit_with_message( msg );
249  }
251  (*fold_tree_) = fold_tree_in;
252  setup_atom_tree();
253 }
254 
255 /// @details Declare that a chemical bond exists between two residues
256 void
258  Size const seqpos1,
259  std::string const & atom_name1,
260  Size const seqpos2,
261  std::string const & atom_name2
262 )
263 {
264 
265  Residue & rsd1( *residues_[ seqpos1 ] );
266  Residue & rsd2( *residues_[ seqpos2 ] );
267 
268  // find the connection ids
269  Size const atom1( rsd1.atom_index( atom_name1 ) );
270  Size const atom2( rsd2.atom_index( atom_name2 ) );
271  Size connid1(0);
272  for ( Size connid=1; connid<= rsd1.n_residue_connections(); ++connid ) {
273  if ( Size(rsd1.residue_connection( connid ).atomno()) == atom1 ) {
274  connid1 = connid;
275  }
276  }
277  Size connid2(0);
278  for ( Size connid=1; connid<= rsd2.n_residue_connections(); ++connid ) {
279  if ( Size(rsd2.residue_connection( connid ).atomno()) == atom2 ) {
280  connid2 = connid;
281  }
282  }
283  if ( !connid1 ) utility_exit_with_message( rsd1.name()+" doesnt have connection at "+atom_name1 );
284  if ( !connid2 ) utility_exit_with_message( rsd2.name()+" doesnt have connection at "+atom_name2 );
285  rsd1.residue_connection_partner( connid1, seqpos2, connid2 );
286  rsd2.residue_connection_partner( connid2, seqpos1, connid1 );
287 }
288 
289 ///////////////////////////////////////////////////////////////////////////////
290 /// @details copy a stretch of coordinates/torsions from another pose
291 /// Fires IdentityEvent signals as residues are replaced.
292 void
294  Size const size,
295  Conformation const & src,
296  Size const begin,
297  Size const src_begin
298 )
299 {
300 
301  for ( Size i=0; i< size; ++i ) {
302  Size const seqpos ( begin + i );
303  Size const seqpos_src( src_begin + i );
304  replace_residue( seqpos, src.residue(seqpos_src), false );
305  }
306 }
307 
308 ///////////////////////////////////////////////////////////////////////////////
309 /// @details replace a residue
310 /// Fires an IdentityEvent signal.
311 void
313  Size const seqpos,
314  Residue const & new_rsd_in,
315  bool const orient_backbone
316 )
317 {
318  // temporarily hold onto the current residue
319  ResidueOP old_rsd_ptr( residues_[ seqpos ] );
320  Residue const & old_rsd( *old_rsd_ptr );
321 
322  // helper function, hides direct access to residues_
323  residues_replace( seqpos, new_rsd_in );
324 
325  // reference to new residue
326  Residue & new_rsd( *residues_[ seqpos ] );
327 
328  // transform coordinates to align backbone with current backbone
329  // note that this also copies backbone coords from old_rsd
330  // ie, it's the same as the rotamer-building residue placement operation
331  //
332  if ( orient_backbone ) {
333  residues_[seqpos]->place( old_rsd, *this );
334  }
335 
336 
338 
340 // if ( !residue_torsions_need_updating_ ) update_residue_torsions( seqpos );
341 
342  notify_identity_obs( IdentityEvent( this, IdentityEvent::RESIDUE, seqpos, &new_rsd ), false );
343 }
344 
345 
346 /// @brief function to replace a residue based on superposition on
347 /// the specified input atom pairs
348 /// NOTE: at the moment, only superposition on 3 atoms works
349 /// Fires an IdentityEvent signal.
350 void
352  Size const seqpos,
353  Residue const & new_rsd_in,
354  utility::vector1< std::pair< std::string, std::string > > const & atom_pairs
355 )
356 {
357  //first we'll set the correct atom coordinates, then we'll let
358  //the other replace residue function deal with everything else
359 
360  // temporarily hold onto the current residue
361  ResidueOP old_rsd_ptr( residues_[ seqpos ] );
362  Residue const & old_rsd( *old_rsd_ptr );
363 
364  Residue new_rsd = new_rsd_in;
365 
366  new_rsd.orient_onto_residue( old_rsd, atom_pairs );
367 
368  //2. call replace res without orienting backbone( no coordinates will be changed ),
369  // only the conformation internal data structures are updated
370 
371  replace_residue( seqpos, new_rsd, false);
372 
373 }
374 
375 ///////////////////////////////////////////////////////////////////////////////
376 /// @details add a residue into residues_ container, update its seqpos, chainid as well
377 /// fold tree and atoms.
378 /// Fires a LengthEvent::RESIDUE_APPEND signal.
379 void
381  conformation::Residue const & new_rsd,
382  Size const anchor_pos,
383  std::string const& anchor_atom, // could be zero
384  std::string const& root_atom, // ditto
385  bool const start_new_chain // default false
386 )
387 {
389 
390  // handle first residue: special case
391  if ( size() < 1 ) {
392  append_residue( new_rsd, false, "", id::BOGUS_NAMED_ATOM_ID, start_new_chain );
393  return;
394  }
395 
396  assert( anchor_pos ); // should be set
397 
398  //if ( !anchor_atomno ) anchor_atomno = kinematics::get_anchor_atomno( residue_( anchor_pos ), kinematics::dir_jump );
399  //if ( !root_atomno ) root_atomno = kinematics::get_root_atomno ( new_rsd, kinematics::dir_jump );
400 
401  // now call our internal append method
402  append_residue( new_rsd, true, root_atom, id::NamedAtomID( anchor_atom, anchor_pos ), start_new_chain );
403 }
404 
405 
406 ///////////////////////////////////////////////////////////////////////////////
407 /// @details The default behavior is to append by a polymeric connection to the preceding residue
408 /// If we want to connect via a non-polymer connection, we give the connection number, anchor residue
409 /// and the connection number for the anchor residue. These connection numbers are wrt the connections_
410 /// arrays in Residue and ResidueType
411 /// If build_ideal_bond is TRUE it will transform the coordinates of the new residue so that the bond
412 /// geometry of the new bond is ideal according to the icoor_internal data in the residues.
413 /// Otherwise the incoming coordinates of new_rsd are preserved.
414 /// Fires a LengthEvent::RESIDUE_APPEND signal.
415 void
417  conformation::Residue const & new_rsd,
418  bool const build_ideal_geometry, // = false,
419  int residue_connection_index, // = 0,
420  Size anchor_pos, // = 0,
421  int anchor_residue_connection_index, // = 0
422  bool const start_new_chain, // default false
423  bool const lookup_bond_length // default false
424 )
425 {
426  if(!build_ideal_geometry) assert(!lookup_bond_length); // lookup only possible if building ideal geometry
427 
429 
430  // handle first residue: special case
431  if ( size() < 1 ) {
432  append_residue( new_rsd, false, "", id::BOGUS_NAMED_ATOM_ID, start_new_chain );
433  return;
434  }
435 
436  Size const seqpos( size() + 1 );
437  bool const polymer_connection( residue_connection_index == 0 );
438 
439  if ( polymer_connection ) anchor_pos = seqpos - 1; // polymer connection is to the preceding residue
440  if ( polymer_connection ) anchor_residue_connection_index = residue_( anchor_pos ).type().upper_connect_id();
441  if ( polymer_connection ) residue_connection_index = new_rsd.type().lower_connect_id();
442 
443  Residue const & anchor_rsd( residue_( anchor_pos ) ); // no call to residue(anchor_pos)
444 
445  // debug
446  if ( polymer_connection ) {
447  // otherwise confirm that we are making a valid polymer bond
448  runtime_assert( ( anchor_rsd.is_polymer() && !anchor_rsd.is_upper_terminus() ) &&
449  ( new_rsd.is_polymer() && !new_rsd.is_lower_terminus() ) ); //Chokes for misplaced "TER" cards
450  } else {
451  // if using a non-polymer connection, confirm that anchor_pos & anchor_residue_connection_index are set
452  assert( anchor_pos && anchor_residue_connection_index );
453  }
454 
455  //////////////////////////////////////////////////
456  ResidueOP ideal_geometry_rsd;
457  if ( build_ideal_geometry ) {
458  // get the geometries of the new bond
459  chemical::ResidueConnection new_rsd_connection;
460  chemical::ResidueConnection anchor_rsd_connection;
461 
462  if ( polymer_connection ) {
463  // polymer connection
464  new_rsd_connection = new_rsd.lower_connect();
465  anchor_rsd_connection = anchor_rsd.upper_connect();
466  } else {
467  // using a non-polymer residue-residue connection
468  new_rsd_connection = new_rsd.residue_connection( residue_connection_index );
469  anchor_rsd_connection = anchor_rsd.residue_connection( anchor_residue_connection_index );
470  }
471 
472  // this is a little wasteful, creating a new copy, but we need non-const access
473  ideal_geometry_rsd = new_rsd.clone();
474 
475  if ( residue_coordinates_need_updating_ ) update_residue_coordinates( anchor_pos ); // safety
476  orient_residue_for_ideal_bond( *ideal_geometry_rsd, new_rsd_connection, anchor_rsd, anchor_rsd_connection, *this, lookup_bond_length );
477 
478  }
479 
480  //////////////////////////////////////////////////////
481  // determine anchor and root atoms
482  id::AtomID anchor_id(0,anchor_pos);
483  int root_atomno;
484 
485  if ( polymer_connection ) {
486  // connecting by a polymer bond
487  root_atomno = new_rsd.lower_connect_atom();
488  anchor_id.atomno() = anchor_rsd.upper_connect_atom();
489  } else {
490  // non-polymer connection
491  root_atomno = new_rsd.residue_connection( residue_connection_index ).atomno();
492  anchor_id.atomno() = anchor_rsd.residue_connection( anchor_residue_connection_index ).atomno();
493  }
494 
495  std::string root_atom = "";
496  if ( root_atomno ) root_atom = new_rsd.atom_name( root_atomno );
497 
498  // Now call our internal append method
499  if ( build_ideal_geometry ) {
501  *ideal_geometry_rsd,
502  false /* not by a jump */,
503  root_atom,
504  atom_id_to_named_atom_id(anchor_id, anchor_rsd),
505  start_new_chain
506  );
507  } else {
509  new_rsd,
510  false /* not by a jump */,
511  root_atom,
512  atom_id_to_named_atom_id(anchor_id, anchor_rsd),
513  start_new_chain );
514  }
515 
516  if ( build_ideal_geometry && polymer_connection ) rebuild_polymer_bond_dependent_atoms( seqpos - 1 );
517 
518  // update the connection info stored inside the residues
519  //if ( !polymer_connection ) {
520  residues_[ seqpos ]->residue_connection_partner( residue_connection_index, anchor_pos, anchor_residue_connection_index );
521  residues_[ anchor_pos ]->residue_connection_partner( anchor_residue_connection_index, seqpos, residue_connection_index );
522  //}
523 
524 } // append_residue_by_bond
525 
526 
527 
528 ///////////////////////////////////////////////////////////////////////////////
529 /// @details add a residue into residues_ container, update its seqpos, chainid as well
530 /// fold tree and atoms.
531 /// private now -- this is our internal routine with everything determined ahead of time
532 /// root_atomno and anchor_id.atomno() may not be filled in yet
533 /// Fires a LengthEvent::RESIDUE_APPEND signal.
534 void
536  conformation::Residue const & new_rsd_in,
537  bool const attach_by_jump,
538  std::string const& root_atom,
539  id::NamedAtomID anchor_id,
540  bool const start_new_chain
541 )
542 {
544 
545  Size const seqpos( size() + 1 );
546  assert( seqpos == fold_tree_->nres() + 1 );
547 
548  // is this the first residue?
549  bool const first_residue( seqpos == 1 );
550 
551  // append to residues
552  residues_append( new_rsd_in, start_new_chain );
553 
554  // get reference to new rsd
555  Residue const & new_rsd( *residues_[ seqpos ] );
556 
557  int anchor_atomno( 0 );
558 
559  // If there is an anchor atom specified, find its index number in the residue.
560  if ( anchor_id.atom().size() ) anchor_atomno = residues_[ anchor_id.rsd() ]->atom_index( anchor_id.atom() );
561  // update the fold_tree
562  if ( first_residue ) {
563  fold_tree_->simple_tree( 1 );
564  } else {
565  int root_atomno = 0;
566  if ( root_atom.size() ) root_atomno = new_rsd.atom_index( root_atom );
567 
568  // try to detect a non-polymer chemical bond:
569  if ( !attach_by_jump && ( new_rsd.is_ligand() || // needed because new_rsd.is_lower_terminus() asserts this is a polymer
570  new_rsd.is_lower_terminus() || anchor_id.rsd() != seqpos-1 ||
571  residues_[ seqpos-1 ]->is_upper_terminus() || // if we got here we're connect to seqpos-1...
572  root_atomno != int(new_rsd_in.lower_connect_atom()) || // ...by our lower-connect-atom
573  anchor_atomno != int(residues_[ seqpos-1 ]->upper_connect_atom()) ) ) {
574  // must be a chemical bond since the criteria for a polymer connection are not met
575  TR << "appending residue by a chemical bond in the foldtree: " << seqpos << ' ' <<
576  new_rsd.name() << " anchor: " << anchor_id << " root: " << root_atom << std::endl;
577  fold_tree_->append_residue_by_chemical_bond( anchor_id.rsd(), anchor_id.atom(), root_atom );
578  } else {
579  fold_tree_->append_residue( attach_by_jump, anchor_id.rsd(), anchor_id.atom(), root_atom );
580  }
581  }
582  TR.Debug << "CURRENT_" << *fold_tree_ << std::endl;
583 
584  // update the atom_tree.
585  // alternatively we could call setup_atom_tree, would be more expensive.
586  // note that, inside these routines, new_rsd's sequence number is being used.
587  // good thing we set it already.
588 
589  if ( first_residue ) {
590  assert( atom_tree_->empty() );
591  setup_atom_tree(); // just this once
592 
593  } else {
595  }
596 
598  //if ( !residue_torsions_need_updating_ ) update_residue_torsions( seqpos );
599 
600  notify_length_obs( LengthEvent( this, LengthEvent::RESIDUE_APPEND, seqpos - 1, 1, &new_rsd ), false );
601 } // append_residue
602 
603 
604 ///////////////////////////////////////////////////////////////////////////////
605 /// @details private
606 /// need to update:
607 /// 1. seqpos of Residues, residue_connection_partners_ info in Residues
608 /// 2. xyz_moved, dof_moved
609 ///
610 void
612  Size const new_size,
613  utility::vector1< Size > const & old2new
614 )
615 {
616  // residues:
617  for ( Size i=1; i<= size(); ++i ) {
618  // seqpos and residue_connection_partners
619  residues_[i]->update_sequence_numbering( old2new );
620  }
621 
622  // chain_endings not done here -- use rederive_chain_endings after the residues_ array is OK
623 
624  // xyz_moved, dof_moved
625  xyz_moved_.update_sequence_numbering( new_size, old2new );
626  dof_moved_.update_sequence_numbering( new_size, old2new );
627 
628 }
629 
630 ///////////////////////////////////////////////////////////////////////////////
631 ///@details
632 ///rebuilds the atoms that are dependent on the bond between seqpos an seqpos+1 for their
633 ///torsion offset
634 void
636 {
638  rebuild_polymer_bond_dependent_atoms( seqpos+1, -1 );
639 }
640 
641 
642 ///////////////////////////////////////////////////////////////////////////////
643 // private
644 void
645 Conformation::rebuild_polymer_bond_dependent_atoms( Size const seqpos, int const upper_lower )
646 {
647  // assumes no interpendencies among the atoms being built
649  Residue const & rsd( residue_(seqpos) );
650 // for ( Size i=1, ie=rsd.natoms(); i<= ie; ++i ) {
651 // if ( ( upper_lower == -1 && rsd.icoor(i).depends_on_polymer_lower() ) ||
652 // ( upper_lower == 1 && rsd.icoor(i).depends_on_polymer_upper() ) ) {
653 // set_xyz( AtomID(i,seqpos), rsd.icoor(i).build( rsd, *this ) );
654 // }
655 // }
656 
657 
658 
659  for ( Size i=1, ie=rsd.natoms(); i<= ie; ++i ) {
660 // if( upper_lower == -1 && rsd.atom_name( i ) == " O1P" ) std::cout << "Conformation.cc O1P, seqpos= " << seqpos << std::endl;
661 // if( upper_lower == -1 && rsd.atom_name( i ) == " O2P" ) std::cout << "Conformation.cc O2P, seqpos= " << seqpos << std::endl;
662 
663 
664  if ( ( upper_lower == -1 && rsd.icoor(i).depends_on_polymer_lower() ) ||
665  ( upper_lower == -1 && rsd.atom_name( i ) == " O2P" ) || //TERRIBLE HACK! FIX bEFORE CHECKING IN!
666  ( upper_lower == -1 && rsd.atom_name( i ) == " O1P" ) || //TERRIBLE HACK! FIX BEFORE CHECKING IN!
667  ( upper_lower == 1 && rsd.icoor(i).depends_on_polymer_upper() ) ) {
668  set_xyz( AtomID(i,seqpos), rsd.icoor(i).build( rsd, *this ) );
669  }
670  }
671 }
672 
673 ///////////////////////////////////////////////////////////////////////////////
674 ///@details
675 /// @note This could be rewritten to avoid a refold using set_bond_angle, etc might be safer since
676 /// by-xyz ignores possibility of propagating dependencies from the moving atoms...
677 void
679 {
680 
681  // assumes no interpendencies among the atoms being built
683  Residue const & rsd( residue_(seqpos) );
684  for ( Size i=1, ie=rsd.natoms(); i<= ie; ++i ) {
685  if ( rsd.icoor(i).depends_on_residue_connection( connid ) ) {
686  set_xyz( AtomID(i,seqpos), rsd.icoor(i).build( rsd, *this ) );
687  }
688  }
689 }
690 
691 
692 ///////////////////////////////////////////////////////////////////////////////
693 
694 void
696  Residue const & new_rsd,
697  Size const seqpos,
698  bool const build_ideal_geometry // = false
699 )
700 {
703  append_polymer_residue_after_seqpos( new_rsd, seqpos, build_ideal_geometry );
704 }
705 
706 ///////////////////////////////////////////////////////////////////////////////
707 /// @details Fires a LengthEvent::RESIDUE_PREPEND signal at seqpos + 1 due to
708 /// insert_polymer_residue() call.
709 void
711  Residue const & new_rsd,
712  Size const seqpos,
713  bool const build_ideal_geometry // = false
714 )
715 {
717  assert( !new_rsd.is_lower_terminus() );
718 
719  ResidueOP ideal_geometry_rsd;
720  if ( build_ideal_geometry ) {
722  Residue const & anchor_rsd( residue_( seqpos ) ); // not residue(seqpos)
723  assert( !anchor_rsd.is_upper_terminus() );
724  // this is a little wasteful, creating a new copy, but we need non-const access
725  ideal_geometry_rsd = new_rsd.clone();
726 
727  orient_residue_for_ideal_bond(*ideal_geometry_rsd, new_rsd.lower_connect(), anchor_rsd, anchor_rsd.upper_connect(), *this );
728  }
729  bool const join_lower( true );
730  bool const join_upper( !fold_tree_->is_cutpoint( seqpos ) );
731 
732  if ( build_ideal_geometry ) insert_polymer_residue( *ideal_geometry_rsd, seqpos+1, join_lower, join_upper );
733  else insert_polymer_residue( new_rsd, seqpos+1, join_lower, join_upper );
734 
735  if ( build_ideal_geometry ) {
737  }
738 
739  assert( dof_moved_[seqpos+1].size() == new_rsd.natoms() &&
740  xyz_moved_[seqpos+1].size() == new_rsd.natoms() );
741 }
742 
743 ///////////////////////////////////////////////////////////////////////////////
744 /// @details Fires a LengthEvent::RESIDUE_PREPEND signal.
745 void
747  Residue const & new_rsd,
748  Size const seqpos,
749  bool const build_ideal_geometry // = false
750 )
751 {
753  prepend_polymer_residue_before_seqpos( new_rsd, seqpos, build_ideal_geometry );
754 }
755 
756 ///////////////////////////////////////////////////////////////////////////////
757 /// @details Fires a LengthEvent::RESIDUE_PREPEND signal.
758 void
760  Residue const & new_rsd,
761  Size const seqpos,
762  bool const build_ideal_geometry // = false
763 )
764 {
766  assert( !new_rsd.is_upper_terminus() );
767 
768  ResidueOP ideal_geometry_rsd;
769  if ( build_ideal_geometry ) {
771  Residue const & anchor_rsd( residue_( seqpos ) ); // not residue(seqpos)
772  assert( !anchor_rsd.is_lower_terminus() );
773  // this is a little wasteful, creating a new copy, but we need non-const access
774  ideal_geometry_rsd = new_rsd.clone();
775 
776  orient_residue_for_ideal_bond(*ideal_geometry_rsd, new_rsd.upper_connect(), anchor_rsd, anchor_rsd.lower_connect(), *this );
777  }
778 
779  bool const join_upper( true );
780  bool const join_lower( !fold_tree_->is_cutpoint( seqpos-1 ) );
781 
782  if ( build_ideal_geometry ) insert_polymer_residue( *ideal_geometry_rsd, seqpos, join_lower, join_upper );
783  else insert_polymer_residue( new_rsd, seqpos, join_lower, join_upper );
784 
785  if ( build_ideal_geometry ) {
787  }
788 
789  assert( dof_moved_[seqpos].size() == new_rsd.natoms() &&
790  xyz_moved_[seqpos].size() == new_rsd.natoms() );
791 }
792 
793 
794 
795 /// @details Delete a residue from the Conformation the slow way -- triggers a rebuild of the atomtree
796 /// Fires a LengthEvent::RESIDUE_DELETE signal.
797 /// @note Could be upstream and/or downstream of a jump or chemical edge, or the root of the tree
798 /// @note Not well-tested. Expect funny behavior in new or different situations (email pbradley@fhcrc.org)
799 ///
800 /// LOGIC: uses fold_tree.delete_seqpos to handle shifting the topology around if necessary, then calls setup_atom_tree
801 
802 void
804 {
806  fold_tree_->delete_seqpos( seqpos );
807 
808  residues_delete( seqpos );
809 
810  setup_atom_tree();
811 
813 
814  assert( atom_tree_->size() == size() && Size(fold_tree_->nres()) == size() );
815 
816  notify_length_obs( LengthEvent( this, LengthEvent::RESIDUE_DELETE, seqpos, -1, NULL ), false );
817 }
818 
819 
820 /// @details Like above but only one call to setup_atom_tree
821 /// Fires a LengthEvent::RESIDUE_DELETE signal.
822 void
823 Conformation::delete_residue_range_slow( Size const range_begin, Size const range_end )
824 {
826  Size const range_size( range_end - range_begin + 1 );
827  assert( range_size >= 1);
828  for ( Size i=1; i<= range_size; ++i ) {
829  fold_tree_->delete_seqpos( range_begin );
830  residues_delete( range_begin );
831  }
832 
833  setup_atom_tree();
834 
836 
837  assert( atom_tree_->size() == size() && Size(fold_tree_->nres()) == size() );
838 
839  notify_length_obs( LengthEvent( this, LengthEvent::RESIDUE_DELETE, range_begin, -range_size, NULL ), false );
840 }
841 
842 
843 ///////////////////////////////////////////////////////////////////////////////
844 /// @details delete a polymer residues
845 /// Fires a LengthEvent::RESIDUE_DELETE signal.
846 void
848 {
850  assert( !fold_tree_->is_jump_point( seqpos ) );
851 
852  residues_delete( seqpos ); // handles renumbering of residues, _moved, chains
853 
854  // delete from AtomTree, foldtree
855  // this atom_tree_ call could be more robust if we passed in the fold_tree_
856  // currently it assumes 1 incoming connxn, <=1 outgoing connxn
857  atom_tree_->delete_seqpos( seqpos );
858  fold_tree_->delete_seqpos( seqpos );
859 
860  residue_torsions_need_updating_ = true; // could reupdate before and after
861 
862  assert( atom_tree_->size() == size() && Size(fold_tree_->nres()) == size() );
863 
864  notify_length_obs( LengthEvent( this, LengthEvent::RESIDUE_DELETE, seqpos, -1, NULL ), false );
865 }
866 
867 
868 ///////////////////////////////////////////////////////////////////////////////
869 /// @details insert a polymer residue
870 /// Fires a LengthEvent::RESIDUE_PREPEND signal.
871 void
873  Residue const & new_rsd_in,
874  Size const seqpos, // desired seqpos of new_rsd
875  bool const join_lower,
876  bool const join_upper
877 )
878 {
880  // debug termini status
881  if ( join_lower ) assert( !new_rsd_in.is_lower_terminus() );
882  if ( join_upper ) assert( !new_rsd_in.is_upper_terminus() );
883 
884  // this handles all renumbering internal to the Residues, *_moved arrays
885  residues_insert( seqpos, new_rsd_in, !join_upper );
886 
887  Residue const & new_rsd( residue_( seqpos ) );
888 
889  fold_tree_->insert_polymer_residue( seqpos, join_lower, join_upper );
890 
892 
893  residue_torsions_need_updating_ = true; // could reupdate before and after
894 
895  assert( atom_tree_->size() == size() && Size(fold_tree_->nres()) == size() );
896 
897  notify_length_obs( LengthEvent( this, LengthEvent::RESIDUE_PREPEND, seqpos, 1, &new_rsd ), false );
898 }
899 
900 
901 ///////////////////////////////////////////////////////////////////////////////
902 /// @details insert a residue by jump
903 /// Fires a LengthEvent::RESIDUE_PREPEND signal.
904 void
906  Residue const & new_rsd_in,
907  Size const seqpos, // desired seqpos of new_rsd
908  Size anchor_pos, // in the current sequence numbering, ie before insertion of seqpos
909  std::string const& anchor_atom, // could be ""
910  std::string const& root_atom, // ditto
911  bool new_chain
912 )
913 {
915  ASSERT_ONLY(Size const old_size( size() );) //, new_size( old_size+1 );
916  assert( old_size );
917  assert( fold_tree_->is_cutpoint( seqpos-1 ) );
918 
919  //int anchor_atomno( 0 );
920  //if ( anchor_atom.size() ) {
921  // anchor_atomno = residues_[ anchor_pos ]->atom_index( anchor_atom ); // set but never used ~Labonte
922  //}
923  //if ( !anchor_atomno ) anchor_atomno = kinematics::get_anchor_atomno( residue_( anchor_pos ), kinematics::dir_jump );
924  //if ( !root_atomno ) root_atomno = kinematics::get_root_atomno ( new_rsd_in, kinematics::dir_jump );
925 
926  // this handles all renumbering internal to the Residues, *_moved arrays
927  residues_insert( seqpos, new_rsd_in, false, new_chain );
928 
929  Residue const & new_rsd( residue_( seqpos ) );
930 
931  assert( new_rsd.seqpos() == seqpos );
932 
933  fold_tree_->insert_residue_by_jump( seqpos, anchor_pos /* in the OLD numbering system */, anchor_atom, root_atom );
934 
936 
938 
939  assert( atom_tree_->size() == size() && Size(fold_tree_->nres()) == size() );
940 
941  notify_length_obs( LengthEvent( this, LengthEvent::RESIDUE_PREPEND, seqpos, 1, &new_rsd ), false );
942 }
943 
944 ///////////////////////////////////////////////////////////////////////////////
945 /// @details Insert one conformation into another. Some tricky issues:
946 /// (1) residue connections: assume all residue connections within conf carry over, after renumbering residues positions
947 /// (2) jump numbers: see FoldTree::insert_fold_tree_by_jump
948 /// (3) chains: chain endings are inserted before insert_seqpos, and after insert_seqpos+conf.size()-1
949 /// ie. at the beginning and ending of the inserted conformation; all internal chain endings from conf are used
950 /// (4) atom_tree: setup_atom_tree is called to rebuild from scratch using the fold_tree
951 ///
952 
953 void
955  Conformation const & conf,
956  Size const insert_seqpos, // rsd 1 in conf goes here
957  Size const insert_jumppos, // jump#1 in conf goes here
958  Size const anchor_pos, // in the current sequence numbering, ie before insertion of conf
959  Size const anchor_jump_number, // the desired jump number of the anchoring jump, default=0
960  std::string const & anchor_atom, // could be ""
961  std::string const & root_atom // ditto
962 )
963 {
964  /// ensure that residue data is OK
966 
967  /// save some info
968  Size const old_size( size() );
969  Size const insert_size( conf.size() );
970  Size const new_size( old_size + insert_size );
971  assert( old_size );
972 
973  /// sanity checks
974  bool const fold_tree_polymer_bond( !fold_tree_->is_cutpoint( insert_seqpos-1 ) );
975  bool const residues_polymer_bond( insert_seqpos > 1 && insert_seqpos <= old_size &&
976  residue( insert_seqpos-1 ).is_polymer_bonded( insert_seqpos ) );
977  if ( fold_tree_polymer_bond || residues_polymer_bond ) {
978  utility_exit_with_message("cant insert 'by_jump' into a polymer stretch");
979  }
980 
981  /// sequence numbering of existing residues, *_moved --> do this before changing residues_ array
982  {
983  utility::vector1< Size > old2new;
984  for ( Size i=1; i<= old_size; ++i ) old2new.push_back( ( i >= insert_seqpos ) ? i+insert_size : i );
985  update_sequence_numbering( new_size, old2new );
986  }
987 
988  /// insert the residues from conf
989  {
990  utility::vector1< Size > old2new;
991  for ( Size i=1; i<= insert_size; ++i ) old2new.push_back( i+insert_seqpos-1 );
992 
993  utility::vector1< ResidueOP > new_residues;
994  for ( Size i=1; i<= insert_size; ++i ) {
995  ResidueOP new_rsd( conf.residue(i).clone() );
996  new_rsd->update_sequence_numbering( old2new );
997  Size const new_seqpos( old2new[i] );
998  residues_.insert( residues_.begin() + new_seqpos-1, new_rsd );
999  xyz_moved_[ new_seqpos ].clear(); xyz_moved_[ new_seqpos ].resize( new_rsd->natoms(), true );
1000  dof_moved_[ new_seqpos ].clear(); dof_moved_[ new_seqpos ].resize( new_rsd->natoms(), true );
1001  secstruct_.insert( secstruct_.begin() + ( new_seqpos - 1 ), secstruct_[i] );
1002  }
1003  }
1004 
1005 
1006  /// chains
1007  {
1008  utility::vector1< Size > new_chain_endings;
1009  for ( utility::vector1< Size >::const_iterator ch=chain_endings_.begin(); ch != chain_endings_.end(); ++ch ) {
1010  new_chain_endings.push_back( (*ch<insert_seqpos ? *ch : *ch + insert_size ) );
1011  }
1012  for ( Size i=1; i< conf.num_chains(); ++i ) new_chain_endings.push_back( conf.chain_end(i) + insert_seqpos-1 );
1013  if ( insert_seqpos > 1 &&
1014  std::find(new_chain_endings.begin(),new_chain_endings.end(),insert_seqpos-1) == new_chain_endings.end())
1015  new_chain_endings.push_back( insert_seqpos-1 );
1016  if ( insert_seqpos <= old_size &&
1017  std::find(new_chain_endings.begin(),new_chain_endings.end(),insert_seqpos+insert_size-1) == new_chain_endings.end())
1018  new_chain_endings.push_back( insert_seqpos+insert_size-1 );
1019  std::sort( new_chain_endings.begin(), new_chain_endings.end() );
1020  chain_endings_ = new_chain_endings;
1022  }
1023 
1024  /// FoldTree
1025  fold_tree_->insert_fold_tree_by_jump( conf.fold_tree(), insert_seqpos, insert_jumppos, anchor_pos, anchor_jump_number,
1026  anchor_atom, root_atom );
1027 
1028  /// AtomTree
1029  setup_atom_tree();
1030 
1031  /// not sure if this is necessary, perhaps around the insertion? can't hurt though...
1033 
1034 }
1035 
1036 
1037 
1038 
1039 ///////////////////////////////////////////////////////////////////////////////
1040 id::AtomID
1041 Conformation::jump_atom_id( int const jump_number ) const
1042 {
1043 
1044  // the fold_tree may or may not contain the information necessary
1045  // to determine the exact AtomID of the corresponding JumpAtom
1046  //
1047 
1048  kinematics::Edge const & edge( fold_tree_->jump_edge( jump_number ) );
1049 
1050  Size const seqpos( edge.stop() );
1051 
1052  if ( edge.has_atom_info() ) {
1053  return id::AtomID( residues_[ seqpos ]->atom_index( edge.downstream_atom() ), seqpos );
1054  } else {
1055  // get the default atomno used for Jump attachment
1056  int const atomno( get_root_atomno( residue_( seqpos ),
1058  return AtomID( atomno, seqpos );
1059  }
1060 }
1061 
1062 
1063 ///////////////////////////////////////////////////////////////////////////////
1064 void
1066  AtomID const & id,
1067  PointPosition const & position
1068 )
1069 {
1070  // update atomtree coords
1071  if ( !atom_tree_->empty() ) atom_tree_->set_xyz( id, position );
1072 
1073  // update residue coords
1074  residues_[ id.rsd() ]->set_xyz( id.atomno(), position );
1075 
1076  // notify scoring
1077  set_xyz_moved( id );
1078 }
1079 
1080 void
1082  utility::vector1<AtomID> const & ids,
1083  utility::vector1<PointPosition> const & positions
1084 )
1085 {
1086  runtime_assert( ids.size() == positions.size() );
1087 
1088  // update atomtree coords
1089  if ( !atom_tree_->empty() ) atom_tree_->batch_set_xyz( ids, positions );
1090 
1091  // update residue coords
1092  for (core::Size i=1; i<=ids.size(); ++i)
1093  residues_[ ids[i].rsd() ]->set_xyz( ids[i].atomno(), positions[i] );
1094 
1095  // notify scoring
1096  set_xyz_moved( ids );
1097 }
1098 
1099 
1100 void
1102  utility::vector1<AtomID> const & ids,
1104 ) const
1105 {
1106  positions.resize( ids.size() );
1107 
1108  // update residue coords
1109  for (core::Size i=1; i<=ids.size(); ++i)
1110  positions[i] = xyz( ids[i] );
1111 }
1112 
1113 
1114 
1115 
1116 ///////////////////////////////////////////////////////////////////////////////
1117 id::DOF_ID
1119 {
1120  if ( tor_id.type() == id::JUMP ) {
1121  // jump rigid-body offset degree of freedom
1122  int const rb_no( tor_id.torsion() );
1123  assert( rb_no >= 1 && rb_no <= 6 );
1124  int const jump_number( tor_id.rsd() );
1125  AtomID const id( jump_atom_id( jump_number ) );
1126  return DOF_ID( id, id::get_rb_type( rb_no ) );
1127  } else {
1128  // bb or chi
1129  // find out what are the four atoms that define this torsion angle
1130  AtomID id1, id2, id3, id4;
1131  bool const fail
1132  ( get_torsion_angle_atom_ids( tor_id, id1, id2, id3, id4 ) );
1133 
1134  if ( fail ) {
1135  // probably a backbone torsion undefined b/c of a cutpoint
1136  return id::BOGUS_DOF_ID;
1137  }
1138  return atom_tree_->torsion_angle_dof_id( id1, id2, id3, id4 );
1139  }
1140 }
1141 
1142 
1143 ///////////////////////////////////////////////////////////////////////////////
1144 Real
1145 Conformation::torsion( TorsionID const & tor_id ) const
1146 {
1147  using numeric::conversions::degrees;
1148 
1149  if ( tor_id.type() == id::JUMP ) {
1150  // jump rigid-body offset
1151  return atom_tree_->dof( dof_id_from_torsion_id( tor_id ) );
1152 
1153  } else {
1154  // get torsion angle from the Residue
1155  //
1156  // note the use of the residue(...) access method
1157  // this will ensure that the torsions in the residue are in sync
1158  // with the atomtree torsions. Use of residues_[...]-> would not
1159  // be safe.
1160  //
1161  if ( tor_id.type() == id::BB ) {
1162  return residue( tor_id.rsd() ).mainchain_torsion( tor_id.torsion() );
1163  } else {
1164  return residue( tor_id.rsd() ).chi( tor_id.torsion() );
1165  }
1166  }
1167 }
1168 
1169 
1170 ///////////////////////////////////////////////////////////////////////////////
1171 ///
1172 void
1174  TorsionID const & tor_id,
1175  Real const setting
1176 )
1177 {
1178  using numeric::conversions::radians;
1179 
1180  if ( tor_id.type() == id::JUMP ) {
1181  // jump rigid-body offset degree of freedom
1182  DOF_ID const dof_id( dof_id_from_torsion_id( tor_id ) );
1183  atom_tree_->set_dof( dof_id, setting );
1184 
1185  // update book-keeping to reflect that this torsion has changed
1186  set_dof_moved( dof_id );
1187 
1188  } else {
1189  // bb or chi
1190 
1191  // update residue torsions
1192  if ( tor_id.type() == id::BB ) {
1193  residues_[ tor_id.rsd() ]->mainchain_torsions()[ tor_id.torsion() ]
1194  = setting;
1195  } else {
1196  residues_[ tor_id.rsd() ]->chi()[ tor_id.torsion() ] = setting;
1197  }
1198 
1199  // find out what are the four atoms that define this torsion angle
1200  AtomID id1, id2, id3, id4;
1201  bool const fail
1202  ( get_torsion_angle_atom_ids( tor_id, id1, id2, id3, id4 ) );
1203 
1204  if ( fail ) return;
1205 
1206  // atomtree works in radians
1207  DOF_ID const dof_id
1208  ( atom_tree_->set_torsion_angle( id1, id2, id3, id4, radians(setting) ) );
1209 
1210  if ( !dof_id.valid() ) {
1211  //
1212  TR.Warning << "Unable to find torsion angle in atom_tree: " <<
1213  tor_id << std::endl;
1214  return;
1215  }
1216 
1217  // update book-keeping to reflect that this torsion has changed
1218  set_dof_moved( dof_id );
1219  }
1220 }
1221 
1222 
1223 ///////////////////////////////////////////////////////////////////////////////
1224 // returns TRUE for FAILURE
1225 bool
1227  TorsionID const & tor_id,
1228  AtomID & id1,
1229  AtomID & id2,
1230  AtomID & id3,
1231  AtomID & id4
1232 ) const
1233 {
1234  int const torsion( tor_id.torsion() );
1235  Size const seqpos( tor_id.rsd() );
1236 
1237  bool fail( false );
1238  if ( tor_id.type() == id::BB ) {
1239  // backbone torsion, eg if protein: 1==phi, 2==psi, 3==omega
1240  // may fail if we are at a chainbreak
1241  fail = backbone_torsion_angle_atoms( tor_id, id1, id2, id3, id4 );
1242  } else if ( tor_id.type() == id::CHI ) {
1243  id1.rsd() = id2.rsd() = id3.rsd() = id4.rsd() = seqpos;
1244  id1.atomno() = residue_( seqpos ).chi_atoms( torsion )[1];
1245  id2.atomno() = residue_( seqpos ).chi_atoms( torsion )[2];
1246  id3.atomno() = residue_( seqpos ).chi_atoms( torsion )[3];
1247  id4.atomno() = residue_( seqpos ).chi_atoms( torsion )[4];
1248  } else {
1249  std::cerr << "Conformation::get_torsion_angle_atom_ids: " << tor_id <<
1250  " Jump 'torsions' are not described by four atoms!" << std::endl;
1251  utility_exit();
1252  }
1253  return fail;
1254 }
1255 
1256 
1257 ///////////////////////////////////////////////////////////////////////////////
1258 void
1260  AtomID const & atom1,
1261  AtomID const & atom2,
1262  AtomID const & atom3,
1263  AtomID const & atom4,
1264  Real const setting
1265 )
1266 {
1268  DOF_ID const dof_id( atom_tree_->set_torsion_angle( atom1, atom2, atom3, atom4, setting ) );
1269  if ( dof_id.valid() ) {
1270  set_dof_moved( dof_id );
1271  } else {
1272  TR << "set_torsion_angle failed, unable to find dof_id: " << atom1 << ' ' << atom2 << ' ' << atom3 << ' ' <<
1273  atom4 << std::endl;
1274  }
1275 }
1276 
1277 ////////////////////////////////////////////////////////////////////////////////////////
1278 /// @details
1279 /// Set two bond angles and a bond length. DOES NOT DO ANY DIHEDRALS -- NOT EVEN OMEGA IF ITS A PROTEIN
1280 
1281 void
1283 {
1284  // use residuetype's rather than residues to avoid triggering a refold
1285  chemical::ResidueType const & lower_rsd_type( residue_type( seqpos ) );
1286  chemical::ResidueType const & upper_rsd_type( residue_type( seqpos+1 ) );
1287 
1288  // what are the four atoms that define the bonds/angles?
1289  Size const nbb( lower_rsd_type.mainchain_atoms().size() );
1290  AtomID const atom1( lower_rsd_type.mainchain_atom( nbb - 1 ), seqpos );
1291  AtomID const atom2( lower_rsd_type.mainchain_atom( nbb ), seqpos );
1292  AtomID const atom3( upper_rsd_type.mainchain_atom( 1 ), seqpos+1 );
1293  AtomID const atom4( upper_rsd_type.mainchain_atom( 2 ), seqpos+1 );
1294 
1295  // what is the ideal geometry?
1296  chemical::ResidueConnection const & connect1( lower_rsd_type.upper_connect() );
1297  chemical::ResidueConnection const & connect2( upper_rsd_type.lower_connect() );
1298 
1299  Real const bond_distance( connect1.icoor().d() );
1300  Real const bond_angle1( numeric::constants::d::pi - connect1.icoor().theta() );
1301  Real const bond_angle2( numeric::constants::d::pi - connect2.icoor().theta() );
1302 
1303  assert( ( connect1.icoor().stub_atom2().atomno() == Size( atom1.atomno() ) ) &&
1304  ( connect1.icoor().stub_atom1().atomno() == Size( atom2.atomno() ) ) &&
1305  ( connect2.icoor().stub_atom1().atomno() == Size( atom3.atomno() ) ) &&
1306  ( connect2.icoor().stub_atom2().atomno() == Size( atom4.atomno() ) ) );
1307 
1308  set_bond_angle( atom1, atom2, atom3, bond_angle1 );
1309  set_bond_angle( atom2, atom3, atom4, bond_angle2 );
1310  set_bond_length( atom2, atom3, bond_distance );
1311 
1312  // unfortunately this appears to trigger a refold, in that it works in cartesian space to update the atom
1313  // positions.
1314  //
1315  // could be rewritten to communicate directly with the atomtree...
1316  //
1318 }
1319 
1320 ////////////////////////////////////////////////////////////////////////////////////////
1321 /// @details
1322 /// Set two bond angles and a bond length. DOES NOT DO ANY DIHEDRALS -- NOT EVEN OMEGA IF ITS A PROTEIN
1323 
1324 void
1326 {
1327  // we use residues_[ xx ] rather than residue(xx) to avoid triggering refold/angle update
1328  //
1329  // determine what the other residue for this connection is:
1330  ResidueCOP rsd1( residues_[ pos1 ]() );
1331  Size const pos2( rsd1->connect_map( connid1 ).resid() );
1332  Size const connid2( rsd1->connect_map( connid1 ).connid() );
1333  ResidueCOP rsd2( residues_[ pos2 ]() );
1334 
1335  // what is the ideal geometry?
1336  chemical::ResidueConnection const & connect1( rsd1->residue_connection( connid1 ) );
1337  chemical::ResidueConnection const & connect2( rsd2->residue_connection( connid2 ) );
1338 
1339  Real const bond_distance( connect1.icoor().d() );
1340  Real const bond_angle1( numeric::constants::d::pi - connect1.icoor().theta() );
1341  Real const bond_angle2( numeric::constants::d::pi - connect2.icoor().theta() );
1342 
1343  AtomID const atom1( connect1.icoor().stub_atom2().atomno(), pos1 );
1344  AtomID const atom2( connect1.icoor().stub_atom1().atomno(), pos1 );
1345  AtomID const atom3( connect2.icoor().stub_atom1().atomno(), pos2 );
1346  AtomID const atom4( connect2.icoor().stub_atom2().atomno(), pos2 );
1347 
1348  set_bond_angle( atom1, atom2, atom3, bond_angle1 );
1349  set_bond_angle( atom2, atom3, atom4, bond_angle2 );
1350  set_bond_length( atom2, atom3, bond_distance );
1351 
1352  // need to do something similar here:
1353  //
1356 
1357 }
1358 
1359 ///////////////////////////////////////////////////////////////////////////////
1360 /// @note in radians!!
1361 ///
1362 void
1364  AtomID const & atom1,
1365  AtomID const & atom2,
1366  AtomID const & atom3,
1367  Real const setting
1368 )
1369 {
1370  DOF_ID const dof_id( atom_tree_->set_bond_angle( atom1, atom2, atom3, setting ) );
1371  if ( dof_id.valid() ) {
1372  set_dof_moved( dof_id );
1373  }
1374 }
1375 
1376 ///////////////////////////////////////////////////////////////////////////////
1377 void
1379  AtomID const & atom1,
1380  AtomID const & atom2,
1381  Real const setting
1382 )
1383 {
1384  DOF_ID const dof_id( atom_tree_->set_bond_length( atom1, atom2, setting ) );
1385  if ( dof_id.valid() ) {
1386  set_dof_moved( dof_id );
1387  }
1388 }
1389 
1390 /////////////////////////////////////////////////////
1391 void
1393  id::StubID const & instub_id,
1394  FragRT const & outstub_transforms,
1395  FragXYZ const & frag_xyz
1396 )
1397 {
1398  utility::vector1< AtomID > moved_atoms;
1399 
1400  atom_tree_->insert_fragment( instub_id, outstub_transforms, frag_xyz, moved_atoms );
1401 
1402  for ( Size i=1; i<= moved_atoms.size(); ++i ) {
1403  set_dof_moved( moved_atoms[i] );
1404  }
1405 
1406 }
1407 
1408 /// @details Copy any un-registered coordinate or DOF changes into the existing residues.
1409 /// For now, the AtomTree only tracks which Residues need external coordinate changes,
1410 /// and not internal coordinate changes. When internal coordinates go out-of-date in
1411 /// the atom tree, the "update_internal_coordinates" recursion begins at the root. Moreover,
1412 /// the Conformation updates internal coordinates for all residues when it updates. However,
1413 /// when this changes and the AtomTree starts tracking which residues need to have their
1414 /// internal coordinates updated, then it will be necessary to add a call to
1415 /// update_residue_torsions() here.
1416 void
1418 {
1420 }
1421 
1422 /////////////////////////////////////////////////////
1423 /** work in progress
1424 void
1425 insert_chemical_chainbreak_between_polymer_residues( Size const lower_seqpos )
1426 {
1427  ResidueOP lower_rsd( residues_[ lower_seqpos ] );
1428 
1429  // the type of the desired variant residue
1430  ResidueTypeSet const & rsd_set( lower_rsd->residue_type_set() );
1431 
1432  ResidueType const & new_lower_rsd_type
1433  ( rsd_set.get_residue_type_with_variant_removed( lower_rsd.type(), UPPER_TERMINUS ) );
1434  ResidueOP new_lower_rsd( ResidueFactory::create_residue( new_lower_rsd_type ) );
1435 
1436 
1437 }
1438 **/
1439 /////////////////////////////////////////////////////
1440 ///
1441 
1442 void
1444 {
1445  if ( lower_seqpos < 1 || lower_seqpos >= size() ) return;
1446 
1447  Residue const & lower( *residues_[ lower_seqpos ] ), upper( *residues_[ lower_seqpos + 1 ] );
1448 
1449  bool const disconnected(
1450  lower.chain() != upper.chain() || lower.is_upper_terminus() ||
1451  upper.is_lower_terminus() || !lower.is_polymer() || !upper.is_polymer()
1452  );
1453 
1454  if ( !disconnected ) set_polymeric_connection( lower_seqpos, lower_seqpos+1 );
1455 
1456 }
1457 
1458 
1459 /// @details identify polymeric connections
1460 /// The lower residue connects to the upper residue through its upper_connect connection
1461 /// The upper residue connects to the lower residue through its lower_connect connection
1462 void
1464  Size res_id_lower,
1465  Size res_id_upper
1466 )
1467 {
1468  Size const lr_conn_id( residue_( res_id_lower ).type().upper_connect_id());
1469  Size const ur_conn_id( residue_( res_id_upper ).type().lower_connect_id());
1470  residues_[ res_id_lower ]->residue_connection_partner( lr_conn_id, res_id_upper, ur_conn_id );
1471  residues_[ res_id_upper ]->residue_connection_partner( ur_conn_id, res_id_lower, lr_conn_id );
1472 }
1473 
1474 void
1476 {
1477  using namespace graph;
1478 
1479  utility::vector1< Size > resid_2_incomp( size(), 0 );
1480  Size num_incomp( 0 );
1481  for ( Size ii = 1; ii <= size(); ++ii ) {
1482  if ( residue(ii).has_incomplete_connection() ) {
1483  ++num_incomp;
1484  resid_2_incomp[ ii ] = num_incomp;
1485  }
1486  }
1487  if ( num_incomp == 0 ) return;
1488 
1489  TR.Debug << "Looking for connection partners for " << num_incomp << " residues" << std::endl;
1490 
1491  utility::vector1< Size > incomp_2_resid( num_incomp );
1492  for ( Size ii = 1; ii <= size(); ++ii ) {
1493  if ( resid_2_incomp[ ii ] != 0 ) {
1494  incomp_2_resid[ resid_2_incomp[ ii ]] = ii;
1495  }
1496  }
1497 
1498  /// Create point graph
1499  PointGraphOP pg = new PointGraph;
1500  pg->set_num_vertices( num_incomp );
1501  Distance maxrad( 0.0 );
1502  Distance maxd( 0.0 );
1503  for ( Size ii = 1; ii <= num_incomp; ++ii ) {
1504  Residue const & ii_res = residue( incomp_2_resid[ ii ] );
1505  pg->get_vertex(ii).data().xyz() = ii_res.atoms()[ ii_res.nbr_atom() ].xyz();
1506  if ( ii_res.nbr_radius() > maxrad ) maxrad = ii_res.nbr_radius();
1507  for ( Size jj = 1; jj <= ii_res.type().n_residue_connections(); ++jj ) {
1508  if ( ii_res.connection_incomplete( jj ) ) {
1509  if ( maxd < ii_res.type().residue_connection(jj).icoor().d() ) {
1510  maxd = ii_res.type().residue_connection(jj).icoor().d();
1511  }
1512  }
1513  }
1514  }
1515 
1516  // Two angstrom extra radius for finding bonds... very generous
1517  maxd += 2.0;
1518  Distance neighbor_cutoff = maxrad + maxd;
1519  find_neighbors<core::conformation::PointGraphVertexData,core::conformation::PointGraphEdgeData>( pg, neighbor_cutoff );
1520 
1521  // Iterate across neighbors of incomplete residues; compare incomplete connection points against each other.
1522  for ( Size ii = 1; ii <= num_incomp; ++ii ) {
1523  Size const ii_resid = incomp_2_resid[ ii ];
1524  Size const ii_n_conn = residue( ii_resid ).type().n_residue_connections();
1525  Residue const & ii_res( residue( ii_resid ) );
1526  for ( Size jj = 1; jj <= ii_n_conn; ++jj ) {
1527  if ( ! ii_res.connection_incomplete( jj ) ) continue;
1528 
1529  Size const jjatom = ii_res.residue_connection( jj ).atomno();
1530  bool multiple_connections_for_jjatom = ii_res.type().n_residue_connections_for_atom( jjatom ) > 1;
1531 
1532  Distance best_match( 0.0 ), best_jj( 0.0 ), best_kk( 0.0 );
1533  Size best_match_resid( 0 );
1534  Size best_match_connid( 0 );
1535 
1537  ii_iter = pg->get_vertex( ii ).upper_edge_list_begin(),
1538  ii_end_iter = pg->get_vertex( ii ).upper_edge_list_end();
1539  ii_iter != ii_end_iter; ++ii_iter ) {
1540  Size const neighb_id = ii_iter->upper_vertex();
1541  Size const neighb_resid = incomp_2_resid[ neighb_id ];
1542  Residue const & neighb( residue( neighb_resid ) );
1543  Size const neighb_n_conn = neighb.type().n_residue_connections();
1544 
1545  for ( Size kk = 1; kk <= neighb_n_conn; ++kk ) {
1546  if ( ! neighb.connection_incomplete( kk ) ) continue;
1547 
1548  Size const kkatom = neighb.residue_connection( kk ).atomno();
1549 
1550  bool multiple_connections_for_kkatom = neighb.type().n_residue_connections_for_atom(kkatom) > 1;
1551  Distance kk_distance = ii_res.connection_distance( *this,
1552  jj, neighb.atom( neighb.type().residue_connection( kk ).atomno() ).xyz() );
1553 
1554  Distance jj_distance = neighb.connection_distance( *this,
1555  kk, ii_res.atom( ii_res.type().residue_connection( jj ).atomno() ).xyz() );
1556 
1557  //std::cout << "kk_distance: " << kk_distance << " jj_distance: " << jj_distance << std::endl;
1558 
1559  if ( multiple_connections_for_jjatom ) {
1560  Vector jj_expected_coord = ii_res.residue_connection( jj ).icoor().build( ii_res, *this );
1561  jj_distance += jj_expected_coord.distance( neighb.xyz( kkatom ) );
1562  }
1563 
1564  if ( multiple_connections_for_kkatom ) {
1565  Vector kk_expected_coord = neighb.residue_connection( kk ).icoor().build( neighb, *this );
1566  kk_distance += kk_expected_coord.distance( ii_res.xyz( jjatom ));
1567  }
1568 
1569  if ( best_match_resid == 0 || best_match > kk_distance + jj_distance ) {
1570  best_match = kk_distance + jj_distance;
1571  best_jj = jj_distance; best_kk = kk_distance;
1572  best_match_resid = neighb_resid;
1573  best_match_connid = kk;
1574  }
1575  }
1576  }
1577 
1578  if ( best_match_resid == 0 ) {
1579  TR.Warning << "Failed to find a residue connection for residue " << ii_resid << " with connection point " << jj << std::endl;
1580  continue;
1581  }
1582 
1583  TR.Info << "Connecting residues: " << ii_resid << " ( " << ii_res.name();
1584  TR.Info << " ) and " << best_match_resid << " ( " << residue( best_match_resid ).name() << " )";
1585  TR.Info << " at atoms ";
1586  TR.Info << ii_res.type().atom_name( ii_res.type().residue_connection( jj ).atomno() );
1587  TR.Info << " and ";
1588  TR.Info << residue( best_match_resid ).type().atom_name( residue( best_match_resid ).type().residue_connection( best_match_connid ).atomno() );
1589  TR.Info << std::endl;
1590  TR.Info << " with mututal distances: " << best_jj << " and " << best_kk << std::endl;
1591 
1592  residues_[ ii_resid ]->residue_connection_partner( jj, best_match_resid, best_match_connid );
1593  residues_[ best_match_resid ]->residue_connection_partner( best_match_connid, ii_resid, jj );
1594  }
1595  }
1596 
1597 }
1598 
1599 void
1601 {
1602  for ( Size ii = 1; ii <= size(); ++ii ) {
1603  Residue const & ii_res( residue_( ii ) );
1604  if ( ii_res.is_coarse() ) continue;
1605  Size const ii_nresconn = ii_res.type().n_residue_connections();
1606  for ( Size jj = 1; jj <= ii_nresconn; ++jj ) {
1607  Size const jj_atid = ii_res.residue_connection( jj ).atomno();
1608  for ( Size kk = jj + 1; kk <= ii_nresconn; ++kk ) {
1609  Size const kk_atid = ii_res.residue_connection( kk ).atomno();
1610  if ( ii_res.path_distance( kk_atid, jj_atid ) < 2 ) {
1611  // found a through-1 pseudobond
1612  // add pseudobonds between the residues that connect
1613  // to connection points kk and jj
1614  Size const jj_conn_res( ii_res.residue_connection_partner( jj ));
1615  Size const jj_conn_id( ii_res.residue_connection_conn_id( jj ));
1616  Size const kk_conn_res( ii_res.residue_connection_partner( kk ));
1617  Size const kk_conn_id( ii_res.residue_connection_conn_id( kk ));
1618 
1619  Size const lr = jj_conn_res < kk_conn_res ? jj_conn_res : kk_conn_res;
1620  Size const lri = jj_conn_res < kk_conn_res ? jj_conn_id : kk_conn_id ;
1621  Size const ur = jj_conn_res < kk_conn_res ? kk_conn_res : jj_conn_res;
1622  Size const uri = jj_conn_res < kk_conn_res ? kk_conn_id : jj_conn_id ;
1623  if(! (lr && lri && ur && uri)) continue;
1624  add_pseudobond( lr, lri, ur, uri, ii_res.path_distance( kk_atid, jj_atid ));
1625 
1626  TR.Info << "Adding PseudoBond between residues " << lr << " " << ur << ", connecting atoms ";
1627  TR.Info << residue_( lr ).type().atom_name( residue_( lr ).type().residue_connection( lri ).atomno() ) << " and ";
1628  TR.Info << residue_( ur ).type().atom_name( residue_( ur ).type().residue_connection( uri ).atomno() );
1629  TR.Info << " through residue " << ii << " at atoms " << ii_res.type().atom_name( jj_atid );
1630  TR.Info << " & " << ii_res.type().atom_name( kk_atid );
1631  TR.Info << " which are separated by " << ii_res.path_distance(kk_atid, jj_atid );
1632  TR.Info << " bond"<< (ii_res.path_distance(kk_atid, jj_atid ) == 1 ? "" : "s") << std::endl;
1633  }
1634 
1635  if ( kk_atid == jj_atid ) {
1636  // two connections on the same atom. Look for through-2 pseudobonds.
1637  utility::vector1< chemical::ResConnID > two_neighbors(2);
1638  two_neighbors[1] = ii_res.actual_residue_connection( jj );
1639  two_neighbors[2] = ii_res.actual_residue_connection( kk );
1640  for ( Size ll = 1; ll <= 2; ++ll ) {
1641  Size const ll_resid = two_neighbors[ ll ].resid();
1642  if ( ll_resid < ii ) continue; // only add through-2 pseudobonds through upper residues to avoid duplication
1643 
1644  Size const ll_connid = two_neighbors[ ll ].connid();
1645  Residue const & ll_res = residue( ll_resid );
1646  Size const ll_atid = ll_res.residue_connection( ll_connid ).atomno();
1647  Size const ll_nconn = ll_res.type().n_residue_connections();
1648  for ( Size mm = 1; mm <= ll_nconn; ++mm ) {
1649  if ( mm == ll_connid ) continue;
1650  Size const mm_atid = ll_res.type().residue_connection( mm ).atomno();
1651  if ( mm_atid != ll_atid ) continue;
1652 
1653  // arriving here, we've now identified that kk_atid == jj_atid and that
1654  // mm_atid == ll_atid; in other words, we have two atoms that have two
1655  // connections each, and these two atoms are bound to each other; this pair of atoms
1656  // forms a through-2 connection.
1657 
1658  // add a psuedobond between the residue two_neighbors[ ll == 1 ? : 2, 1 ].resid()
1659  // and ll_res.residue_conections( mm ).resid()
1660 
1661  Size const ll_conn_res( ii_res.residue_connection_partner( ll == 1 ? kk : jj ));
1662  Size const ll_conn_id( ii_res.residue_connection_conn_id( ll == 1 ? kk : jj ));
1663  Size const mm_conn_res( ll_res.residue_connection_partner( mm ));
1664  Size const mm_conn_id( ll_res.residue_connection_conn_id( mm ));
1665 
1666  Size const lr = ll_conn_res < mm_conn_res ? ll_conn_res : mm_conn_res;
1667  Size const lri = ll_conn_res < mm_conn_res ? ll_conn_id : mm_conn_id ;
1668  Size const ur = ll_conn_res < mm_conn_res ? mm_conn_res : ll_conn_res;
1669  Size const uri = ll_conn_res < mm_conn_res ? mm_conn_id : ll_conn_id ;
1670 
1671  add_pseudobond( lr, lri, ur, uri, 3 /*nbonds*/ );
1672 
1673  TR.Info << "Adding PseudoBond between residues " << lr << " " << ur << ", connecting atoms ";
1674  TR.Info << residue_( lr ).type().atom_name( residue_( lr ).type().residue_connection( lri ).atomno() ) << " and ";
1675  TR.Info << residue_( ur ).type().atom_name( residue_( ur ).type().residue_connection( uri ).atomno() );
1676  TR.Info << " through two residues: " << ii << " and " << ll_resid << " at atoms " << ii_res.type().atom_name( jj_atid );
1677  TR.Info << " & " << ll_res.type().atom_name( mm_atid );
1678  TR.Info << " which are separated by 1 bond" << std::endl;
1679 
1680  }
1681  }
1682 
1683  }
1684  }
1685  }
1686  }
1687 
1688 
1689 }
1690 
1691 
1692 /** @brief Assigns disulfide bonds based on a pre-determined list
1693  * @note works in centroid and full-atom modes
1694  */
1695 void
1696 Conformation::fix_disulfides(utility::vector1< std::pair<Size, Size> > disulf_bonds) {
1697  typedef std::pair<Size,Size> SizePair;
1698  foreach(SizePair disulfide_bond, disulf_bonds){
1699  using utility::vector1;
1700 
1701  Size l_index = (disulfide_bond).first; //Lower residue
1702  Size u_index = (disulfide_bond).second; //Upper residue, usually l<u
1703 
1704  // Check that the residues exist
1705  if(l_index > size() ) {
1706  TR.Error << "[ERROR] Residue " << l_index << " is out of range." << std::endl;
1707  utility_exit();
1708  }
1709  if(u_index > size() ) {
1710  TR.Error << "[ERROR] Residue " << u_index << " is out of range." << std::endl;
1711  utility_exit();
1712  }
1713 
1714  //Swap the CYS for CYD
1715  bool replaced = conformation::change_cys_state(l_index, "CYD", *this);
1716  replaced = replaced && conformation::change_cys_state(u_index, "CYD", *this);
1717  if(! replaced) {
1718  TR.Error << "Failed to introduce CYD for disulfide ("
1719  << l_index <<", "<< u_index << ")." << std::endl;
1720  continue;
1721  }
1722 
1723  //Next, form a bond between the two residues.
1724  //This is a little messy since we don't know the residue types of l & u.
1725  Residue const& l_res( residue( l_index ));
1726  Residue const& u_res( residue( u_index ));
1727 
1728  // Determine which atom forms the disulfide bond
1729  // Prefer SG to SG (fullatom) or CEN to CEN (centroid) bonds
1730  // Allow SG to CEN bonds, but give a warning
1731  // If neither atom is found (neither fullatom nor centroid) throw an error.
1732  Size l_bond_atom, u_bond_atom;
1733 
1734  bool l_has_sg = l_res.type().has_atom_name("SG");
1735  bool u_has_sg = u_res.type().has_atom_name("SG");
1736  bool l_has_cen = l_res.type().has_atom_name("CEN");
1737  bool u_has_cen = u_res.type().has_atom_name("CEN");
1738 
1739  if( l_has_sg ) {
1740  l_bond_atom = l_res.atom_index( "SG" );
1741  if(! u_has_sg)
1742  TR.Warning << "Bonding SG of residue " << l_index
1743  << " to non-SG of residue "<< u_index << std::endl;
1744  }
1745  else if(l_has_cen) {
1746  l_bond_atom = l_res.atom_index( "CEN" );
1747  }
1748  else {
1749  TR.Error << "Cannot form disulfide bond with residue "<<l_index<< std::endl;
1750  continue;
1751  }
1752 
1753  if( u_has_sg ) {
1754  u_bond_atom = u_res.atom_index( "SG" );
1755  if(! l_has_sg)
1756  TR.Warning << "Bonding SG of residue " << u_index
1757  << " to non-SG of residue "<< l_index << std::endl;
1758  }
1759  else if(u_has_cen) {
1760  u_bond_atom = u_res.atom_index( "CEN" );
1761  // TR.Debug << "return index before res-type finalize " << u_bond_atom << std::endl;
1762  //residues_[ u_index ]->type().finalize();
1763  // u_bond_atom = u_res.atom_index( "CEN" );
1764  // TR.Debug << "return index after res-type finalize " << u_bond_atom << std::endl;
1765  }
1766  else {
1767  TR.Error << "Cannot form disulfide bond with residue "<<l_index<< std::endl;
1768  continue;
1769  }
1770 
1771 // if ( TR.Debug.visible() ) {
1772 // for ( Size i = 1; i<=u_res.type().natoms(); i++ ) {
1773 // TR.Debug << "upper residue: \n"
1774 // << "Atom: " << i << " " << u_res.type().atom_name( i ) << "\n"
1775 // << "n_residue_connections " << u_res.type().n_residue_connections() << "\n"
1776 // << "n_residue_connections_for_atom " << u_res.type().n_residue_connections_for_atom( i ) << "\n"
1777 // << std::endl;
1778 // }
1779 // }
1780 
1781  //Now have the correct atoms, so bond them
1782  Size l_connid = l_res.type().residue_connection_id_for_atom( l_bond_atom );
1783  Size u_connid = u_res.type().residue_connection_id_for_atom( u_bond_atom );
1784 
1785  residues_[ l_index ]->residue_connection_partner( l_connid, u_index, u_connid);
1786  residues_[ u_index ]->residue_connection_partner( u_connid, l_index, l_connid);
1787 
1788  assert( residue(l_index).has_variant_type( chemical::DISULFIDE ));
1789  assert( residue(u_index).has_variant_type( chemical::DISULFIDE ));
1790 
1791  } //done with this disulfide
1792 }
1793 
1794 /**
1795  * @brief Detect existing disulfides from the protein structure.
1796  * @details For full atom confomations, looks at SG-SG distance. If the SG-SG
1797  * are about 2.02 A apart, calls it a disulfide bond. For centroid and other
1798  * conformations, the less accurate CB-CB distance is used instead. In this
1799  * case a CB-CB distance of 3.72 A is optimal.
1800  */
1801 void
1803 {
1804  basic::ProfileThis doit( basic::CONFORMATION_DETECT_DISULF );
1805  using namespace graph;
1806  using namespace basic::options;
1807 
1808  // gather all cys, construct mapping from resid to cys index
1809  utility::vector1< Size > resid_2_cysid( size(), 0 );
1810  Size num_cys( 0 );
1811  for ( Size ii = 1; ii <= size(); ++ii ) {
1812  if ( residue(ii).aa() == chemical::aa_cys ) {
1813  ++num_cys;
1814  resid_2_cysid[ ii ] = num_cys;
1815  }
1816  }
1817  if ( num_cys == 0 ) return;
1818 
1819  // construct reverse mapping from cys index to resid
1820  utility::vector1< Size > cysid_2_resid( num_cys );
1821  for ( Size ii = 1; ii <= size(); ++ii ) {
1822  if ( resid_2_cysid[ ii ] != 0 ) {
1823  cysid_2_resid[ resid_2_cysid[ ii ]] = ii;
1824  }
1825  }
1826 
1827  // If all the cys are fullatom, use stricter criteria
1828  bool fullatom(true);
1829  for( Size ii = 1; ii <= num_cys; ++ii) {
1830  if( residue_type(cysid_2_resid[ii]).residue_type_set().name()
1832  {
1833  fullatom = false;
1834  break;
1835  }
1836  }
1837  // SG-SG distance for fullatom, CB-CB distance otherwise
1838  Real const typical_disulfide_distance = fullatom? 2.02 : 3.72;
1839  Real const tolerance = option[OptionKeys::in::detect_disulf_tolerance].user()
1840  ? option[OptionKeys::in::detect_disulf_tolerance]()
1841  : ( fullatom? 0.5 : 1.0 );
1842  std::string const distance_atom = fullatom? "SG" : "CB";
1843 
1844  // Create point graph
1845  PointGraphOP pg = new PointGraph;
1846  pg->set_num_vertices( num_cys );
1847  Distance maxrad( 0.0 );
1848  Distance maxd( typical_disulfide_distance + tolerance );
1849  for ( Size ii = 1; ii <= num_cys; ++ii ) {
1850  Residue const & ii_res = residue( cysid_2_resid[ ii ] );
1851  pg->get_vertex(ii).data().xyz() = ii_res.atoms()[ ii_res.nbr_atom() ].xyz();
1852  if ( ii_res.nbr_radius() > maxrad ) maxrad = ii_res.nbr_radius();
1853  }
1854  Distance neighbor_cutoff = maxrad + maxd;
1855  find_neighbors( pg, neighbor_cutoff );
1856 
1857  // Iterate across neighbors of cys residues; examine SG-SG distances.
1858  // Note that since graph only stores upper neighbors iterating through
1859  // the (upper) edge list will automatically prevent double counting.
1860  std::set< Size > processed_cys; // track cys that have already been processed
1861  for ( Size ii = 1; ii <= num_cys; ++ii ) {
1862  Size const ii_resid = cysid_2_resid[ ii ];
1863  //Size const ii_n_conn = residue( ii_resid ).type().n_residue_connections();
1864  Residue const & ii_res( residue( ii_resid ) );
1865 
1866  //if ii already processed, continue
1867  if( processed_cys.find( ii_resid) != processed_cys.end() ) {
1868  continue;
1869  }
1870 
1871  //Determine which atom makes the disulfide bond
1872  Size ii_sg_atomno(0);
1873  if(ii_res.type().has_atom_name("SG")) {
1874  ii_sg_atomno = residue( cysid_2_resid[ ii ] ).atom_index( "SG" );
1875  } else if(ii_res.type().has_atom_name("CEN")) {
1876  ii_sg_atomno = residue( cysid_2_resid[ ii ] ).atom_index( "CEN" );
1877  } else {
1878  TR.Error << "Error: Can't find an atom to disulfide bond from at residue "<< ii_resid <<std::endl;
1879  utility_exit();
1880  }
1881 
1882  Distance best_match( 0.0 );
1883  Size best_neighbor( 0 );
1884  //Size best_neighbor_cysid( 0 );
1885 
1887  ii_iter = pg->get_vertex( ii ).upper_edge_list_begin(),
1888  ii_end_iter = pg->get_vertex( ii ).upper_edge_list_end();
1889  ii_iter != ii_end_iter; ++ii_iter ) {
1890  Size const jj = ii_iter->upper_vertex();
1891 
1892  Size const jj_resid = cysid_2_resid[ jj ];
1893 
1894  Residue const & jj_res( residue( jj_resid ) );
1895 
1896  //if jj already processed, continue
1897  if( processed_cys.find( jj_resid) != processed_cys.end() ) {
1898  continue;
1899  }
1900 
1901  Distance dist = ii_res.atom( ii_sg_atomno ).xyz().distance(
1902  jj_res.atom( jj_res.atom_index( distance_atom )).xyz() );
1903  if ( best_neighbor == 0 || dist < best_match ) {
1904  best_neighbor = jj_resid;
1905  //best_neighbor_cysid = jj; // set but never used ~Labonte
1906  best_match = dist;
1907  }
1908  }
1909 
1910  if ( best_neighbor == 0 || best_match >= typical_disulfide_distance + tolerance ) {
1911 
1912  // handle case where old disulfide doesn't exist anymore and
1913  // needs to be cleared
1914  if ( processed_cys.find( ii_resid ) == processed_cys.end() && ii_res.has_variant_type( chemical::DISULFIDE ) ) {
1915  TR << "Reverting out-of-date disulfide CYD to CYS at resid " << ii_resid << std::endl;
1916 
1917  bool const successful_revert = conformation::change_cys_state( ii_resid, "CYS", *this ) && !residues_[ ii_resid ]->has_variant_type( chemical::DISULFIDE );
1918  if ( !successful_revert ) {
1919  TR.Error << "ERROR: unable to revert CYD to CYS for removal of disulfide at resid " << ii_resid << std::endl;
1920  }
1921  }
1922 
1923  // mark cys as processed
1924  processed_cys.insert( ii_resid );
1925 
1926  continue;
1927 
1928  } else { // found disulfide bond
1929 
1930  // Create disulfide bond using CYD residues. Note that this will
1931  // end up doing a dummy replace for already existing disulfides,
1932  // but it doesn't necessarily hurt just in case something weird
1933  // happened.
1934  TR << "Found "<< (fullatom?"":"CEN ") << "disulfide between residues " << ii_resid << " " << best_neighbor << std::endl;
1935  TR << "current variant for " << ii_resid << " " << ( residues_[ ii_resid ]->has_variant_type( chemical::DISULFIDE ) ? "CYD" : "CYS" ) << std::endl;
1936  TR << "current variant for " << best_neighbor << " " << ( residues_[ best_neighbor ]->has_variant_type( chemical::DISULFIDE ) ? "CYD" : "CYS" ) << std::endl;
1937 
1938  bool const success_at_ii = conformation::change_cys_state( ii_resid, "CYD", *this )
1939  && residues_[ ii_resid ]->has_variant_type( chemical::DISULFIDE );
1940  bool const success_at_best_neighbor = conformation::change_cys_state( best_neighbor, "CYD", *this )
1941  && residues_[ best_neighbor ]->has_variant_type( chemical::DISULFIDE );
1942 
1943  if ( !success_at_ii ) {
1944  TR.Error << "ERROR: unable to create residue type CYD for disulfide at resid " << ii_resid << std::endl;
1945  }
1946 
1947  if ( !success_at_best_neighbor ) {
1948  TR.Error << "ERROR: unable to create residue type CYD for disulfide at resid " << best_neighbor << std::endl;
1949  }
1950 
1951  TR << "current variant for " << ii_resid << " " << ( residues_[ ii_resid ]->has_variant_type( chemical::DISULFIDE ) ? "CYD" : "CYS" ) << std::endl;
1952  TR << "current variant for " << best_neighbor << " " << ( residues_[ best_neighbor ]->has_variant_type( chemical::DISULFIDE ) ? "CYD" : "CYS" ) << std::endl;
1953 
1954  // Record SG-SG connections.
1955  if ( success_at_ii && success_at_best_neighbor ) {
1956  Residue const & ii_new_res( residue( ii_resid ) );
1957  // ASSUMPTION Disulfide forming cystein SG atoms for exactly one inter-residue chemical bond.
1958  Size ii_connid = ii_new_res.type().residue_connection_id_for_atom( ii_sg_atomno );
1959  Size jj_resid = best_neighbor;
1960  Residue const & jj_res = residue( jj_resid );
1961  Size jj_sg_atomno(0);
1962  if(jj_res.type().has_atom_name("SG")) {
1963  jj_sg_atomno = jj_res.atom_index( "SG" );
1964  } else if(jj_res.type().has_atom_name("CEN")) {
1965  jj_sg_atomno = jj_res.atom_index( "CEN" );
1966  } else {
1967  TR.Error << "Error: Can't find an atom to disulfide bond from at residue "<< jj_resid <<std::endl;
1968  utility_exit();
1969  }
1970 
1971  Size jj_connid = jj_res.type().residue_connection_id_for_atom( jj_sg_atomno );
1972 
1973  residues_[ ii_resid ]->residue_connection_partner( ii_connid, jj_resid, jj_connid );
1974  residues_[ jj_resid ]->residue_connection_partner( jj_connid, ii_resid, ii_connid );
1975  }
1976 
1977  // mark both cys as processed
1978  processed_cys.insert( ii_resid );
1979  processed_cys.insert( best_neighbor );
1980 
1981  }
1982  }
1983 }
1984 
1985 
1986 
1987 void
1989  Size lr,
1990  Size lr_connid,
1991  Size ur,
1992  Size ur_connid,
1993  Size nbonds
1994 )
1995 {
1996  PseudoBondCollectionOP new_pbs;
1997  assert(residues_.size()>0);
1998  assert(lr>0);
1999  assert(lr_connid>0);//?
2000  assert(ur>0);
2001  assert(ur_connid>0);//?
2002 
2003  if ( residues_[ lr ]->is_pseudo_bonded( *residues_[ ur ] ) ) {
2004  PseudoBondCollectionCOP existing_pbs = residues_[ lr ]->get_pseudobonds_to_residue( ur );
2005  new_pbs = new PseudoBondCollection( *existing_pbs );
2006  } else {
2007  new_pbs = new PseudoBondCollection();
2008  }
2009  PseudoBond new_pb;
2010  new_pb.lr( lr ); new_pb.lr_conn_id( lr_connid );
2011  new_pb.ur( ur ); new_pb.ur_conn_id( ur_connid );
2012  new_pb.nbonds( 2 + nbonds );
2013  new_pbs->push_back( new_pb );
2014  residues_[ lr ]->set_pseudobonds_to_residue( ur, new_pbs );
2015  residues_[ ur ]->set_pseudobonds_to_residue( lr, new_pbs );
2016 }
2017 
2018 
2019 ///////////////////////////////////////////////////////////////////////////////
2020 ///////////////////////////////////////////////////////////////////////////////
2021 // private
2022 ///////////////////////////////////////////////////////////////////////////////
2023 ///////////////////////////////////////////////////////////////////////////////
2024 
2025 
2026 
2027 
2028 
2029 ///////////////////////////////////////////////////////////////////////////////
2030 // messy... could perhaps keep this cached if speed is an issue
2031 // but then have to keep sync'ed with changes in the residues
2032 //
2033 // I don't think this is going to be performance critical
2034 //
2035 // consider that in current rosetta we routinely re-evaluate all the
2036 // backbone and sidechain torsion angles from the xyz coordinates...
2037 //
2038 // This was hacky to begin with, but I feel that I have made it more hacky now.
2039 // I am currently working on a more elegent method to handle residue types that
2040 // have a a non-standard number of backbone torsions (ie. beta-peptides, beta-peptoids,
2041 // and the dipeptides ACE-X-NME I use for making rotamers) --Doug
2042 
2043 // returns TRUE for FAILURE
2044 //private
2045 bool
2047  TorsionID const & id,
2048  AtomID & id1,
2049  AtomID & id2,
2050  AtomID & id3,
2051  AtomID & id4
2052 ) const
2053 {
2054  using chemical::AtomIndices;
2055 
2056  bool fail( true ); // return value
2057 
2058  Size const seqpos( id.rsd() );
2059  Size const torsion( id.torsion() );
2060 
2061  Residue const & rsd( *residues_[ seqpos ] );
2062 
2063  AtomIndices const & mainchain( rsd.mainchain_atoms() );
2064 
2065  Size const ntorsions( mainchain.size() );
2066  assert( torsion >= 1 && torsion <= ntorsions );
2067 
2068  // this is hacky
2070  // set all id rsds to seqpos since they are all in the same residue
2071  id1.rsd() = id2.rsd() = id3.rsd() = id4.rsd() = seqpos;
2072 
2073  // torsion 1; epsilon
2074  if( torsion == 1 ){
2075  id1.atomno() = rsd.atom_index( "CP2" );
2076  id2.atomno() = mainchain[1];
2077  id3.atomno() = mainchain[2];
2078  id4.atomno() = mainchain[3];
2079  }
2080  // torsion 2; phi
2081  if( torsion == 2 ){
2082  id1.atomno() = mainchain[1];
2083  id2.atomno() = mainchain[2];
2084  id3.atomno() = mainchain[3];
2085  id4.atomno() = mainchain[4];
2086  }
2087  // torsion 3; psi
2088  if( torsion == 3 ){
2089  id1.atomno() = mainchain[2];
2090  id2.atomno() = mainchain[3];
2091  id3.atomno() = mainchain[4];
2092  id4.atomno() = rsd.atom_index( "NM" );
2093  }
2094  // torsion 4; omega
2095  if( torsion == 4 ){
2096  id1.atomno() = mainchain[3];
2097  id2.atomno() = mainchain[4];
2098  id3.atomno() = rsd.atom_index( "NM" );
2099  id4.atomno() = rsd.atom_index( "CN" );
2100  }
2101 
2102  } else {
2103 
2104 
2105  ///////////////////////////////////////////
2106  // first atom -- may be in seqpos-1
2107  if ( torsion > 1 ) {
2108  id1.rsd() = seqpos;
2109  id1.atomno() = mainchain[ torsion-1 ];
2110  } else {
2111  if ( fold_tree_->is_cutpoint( seqpos-1 ) ) { // seems like this should be a bug if seqpos==1
2113  id1.rsd() = seqpos;
2114  id1.atomno() = rsd.atom_index( "OVU1" );
2115  } else if ( rsd.has_variant_type( chemical::ACETYLATED_NTERMINUS ) ) {
2116  id1.rsd() = seqpos;
2117  id1.atomno() = rsd.atom_index( "CO" );
2118  } else if ( rsd.has_variant_type( "N_ACETYLATION" ) ) {
2119  id1.rsd() = seqpos;
2120  id1.atomno() = rsd.atom_index( " CP " );
2121  } else {
2122  // first bb-torsion is not well-defined
2123  return true; // FAILURE
2124  }
2125  } else {
2126  AtomIndices const & prev_mainchain
2127  ( residue_( seqpos-1 ).mainchain_atoms() );
2128  id1.rsd() = seqpos-1;
2129  id1.atomno() = prev_mainchain[ prev_mainchain.size() ];
2130  }
2131  }
2132 
2133  ///////////////////////////////////////////
2134  // second atom -- for sure in seqpos
2135  id2.rsd() = seqpos;
2136  id2.atomno() = mainchain[ torsion ];
2137 
2138  ///////////////////////////////////////////
2139  // third and fourth atoms, may be in seqpos+1
2140  if ( torsion+2 <= ntorsions ) {
2141  id3.rsd() = seqpos;
2142  id3.atomno() = mainchain[ torsion+1 ];
2143  id4.rsd() = seqpos;
2144  id4.atomno() = mainchain[ torsion+2 ];
2145 
2146  } else {
2147  if ( fold_tree_->is_cutpoint( seqpos ) ) {
2149  if ( torsion+1 == ntorsions ) {
2150  id3.rsd() = seqpos;
2151  id3.atomno() = mainchain[ torsion+1 ];
2152  id4.rsd() = seqpos;
2153  id4.atomno() = rsd.atom_index( "OVL1" );
2154  } else {
2155  assert( torsion == ntorsions );
2156  id3.rsd() = seqpos;
2157  id3.atomno() = rsd.atom_index( "OVL1" );
2158  id4.rsd() = seqpos;
2159  id4.atomno() = rsd.atom_index( "OVL2" );
2160  }
2161  } else if ( rsd.has_variant_type( chemical::METHYLATED_CTERMINUS ) ) {
2162  if ( torsion+1 == ntorsions ) {
2163  id3.rsd() = seqpos;
2164  id3.atomno() = mainchain[ torsion+1 ];
2165  id4.rsd() = seqpos;
2166  id4.atomno() = rsd.atom_index( "NM" );
2167  } else {
2168  assert( torsion == ntorsions );
2169  id3.rsd() = seqpos;
2170  id3.atomno() = rsd.atom_index( "NM" );
2171  id4.rsd() = seqpos;
2172  id4.atomno() = rsd.atom_index( "CN" );
2173  }
2174  } else if ( rsd.has_variant_type( "C_METHYLAMIDATION" ) ) {
2175  //ugly.
2176  id3.rsd() = seqpos;
2177  id4.rsd() = seqpos;
2178  if ( torsion == 2 ) /*psi*/ {
2179  id3.atomno() = rsd.atom_index( " C ");
2180  id4.atomno() = rsd.atom_index( " NR ");
2181  } else {
2182  assert( torsion == 3 );
2183  id3.atomno() = rsd.atom_index( " NR ");
2184  id4.atomno() = rsd.atom_index( " CS ");
2185  }
2186  } else {
2187  // last two bb-torsions not well-defined
2188  return true; // FAILURE
2189  }
2190  } else {
2191  AtomIndices const & next_mainchain
2192  ( residue_( seqpos+1 ).mainchain_atoms() );
2193  if ( torsion+1 == ntorsions ) {
2194  id3.rsd() = seqpos;
2195  id3.atomno() = mainchain[ torsion+1 ];
2196  id4.rsd() = seqpos+1;
2197  id4.atomno() = next_mainchain[ 1 ];
2198  } else {
2199  assert( torsion == ntorsions );
2200  id3.rsd() = seqpos+1;
2201  id3.atomno() = next_mainchain[ 1 ];
2202  if ( next_mainchain.size() >= 2 ) {
2203  id4.rsd() = seqpos+1;
2204  id4.atomno() = next_mainchain[ 2 ];
2205  } else {
2206  // tricky... a single-mainchain-atom polymer residue.
2207  if ( fold_tree_->is_cutpoint( seqpos+1 ) ) {
2208  if ( residue_( seqpos+1 ).has_variant_type( chemical::CUTPOINT_LOWER ) ) {
2209  id4.rsd() = seqpos+1;
2210  id4.atomno() = residue_( seqpos+1 ).atom_index( "OVL1" );
2211  } else {
2212  return true; // failure
2213  }
2214  } else {
2215  id4.rsd() = seqpos+2;
2216  id4.atomno() = residue_( seqpos+2 ).mainchain_atom(1);
2217  }
2218  } // next_mainchain has size>=2 ?
2219  } // torsion+1 == ntorsions?
2220  } // seqpos is a cutpoint
2221  } // torsion+2 <= ntorsions
2222 
2223  }
2224 
2225  fail = false;
2226 
2227  return fail;
2228 }
2229 
2230 
2231 ///////////////////////////////////////////////////////////////////////////////
2232 /// @details used when we want to copy torsions from the atomtree to the residues
2233 /// used when updating the torsion angles stashed in the Residues
2234 /// other torsion access calls look inside the residues since this
2235 /// will be faster than getting from the atomtree, at least in the
2236 /// current implementation of this routine
2237 Real
2239 {
2240  using numeric::conversions::degrees;
2241 
2242  if ( tor_id.type() == id::JUMP ) {
2243  // jump rigid-body offset
2244  return atom_tree_->dof( dof_id_from_torsion_id( tor_id ) );
2245 
2246  } else {
2247  // bb or chi
2248  // find out what are the four atoms that define this torsion angle
2249  AtomID id1, id2, id3, id4;
2250  bool const fail
2251  ( get_torsion_angle_atom_ids( tor_id, id1, id2, id3, id4 ) );
2252 
2253  if ( fail ) {
2254  return 0.0;
2255  }
2256 
2257  // atomtree works in radians
2258  return degrees( atom_tree_->torsion_angle( id1, id2, id3, id4 ) );
2259  }
2260 }
2261 
2262 
2263 ///////////////////////////////////////////////////////////////////////////////
2266 {
2267  // setup ResidueCAPs object
2268  conformation::ResidueCAPs const_rsds;
2269  for ( Size i=1; i<= size(); ++i ) {
2270  // pointer conversions are really annoying
2271  const_rsds.push_back( &( *residues_[i] ) );
2272  }
2273  return const_rsds;
2274 }
2275 
2276 ///////////////////////////////////////////////////////////////////////////////
2277 void
2279 {
2280  // this owns the tree
2281  kinematics::AtomPointer2D atom_pointer;
2282  build_tree( *fold_tree_, const_residues(), atom_pointer );
2283 
2284  // replace the current data in the atom_tree
2285  atom_tree_->replace_tree( atom_pointer );
2286 
2290 }
2291 
2292 
2293 ///////////////////////////////////////////////////////////////////////////////
2294 void
2296 {
2297  domain_map.dimension( size() );
2298  domain_map = 0;
2299  atom_tree_->update_domain_map( domain_map, dof_moved_, xyz_moved_ );
2300 }
2301 
2302 
2303 ///////////////////////////////////////////////////////////////////////////////
2304 /// @details The AtomTree is responsible for tracking the set of residues whose
2305 /// coordinates need updating, and informs the Conformation object of these residues.
2306 /// The Conformation only updates coordinates for this subset of residues.
2307 void
2309 {
2310  if ( !residue_coordinates_need_updating_ ) return;
2312 
2313  //std::cout << "Conformation:: updating coordinates START " << std::endl;
2314 
2315  // fill in the new xyz values in the pose's Residues
2316  // this could be made way faster...
2317  //
2318  // options: give the atomtree atoms links to the corresponding
2319  // atoms in the Residue
2320  //
2321 
2322  PROF_START( basic::UPDATE_RESIDUE_COORDINATES );
2323  for ( kinematics::ResidueListIterator iter = atom_tree_->residue_xyz_change_list_begin(),
2324  iter_end = atom_tree_->residue_xyz_change_list_end(); iter != iter_end; ++iter ) {
2325  update_residue_coordinates( *iter, false );
2326  }
2327  atom_tree_->note_coordinate_change_registered();
2328  PROF_STOP( basic::UPDATE_RESIDUE_COORDINATES );
2329 
2330  notify_xyz_obs( XYZEvent( this ) );
2331 }
2332 
2333 
2334 ///////////////////////////////////////////////////////////////////////////////
2335 void
2336 Conformation::update_residue_coordinates( Size const seqpos, bool const fire_signal ) const
2337 {
2338  //std::cout << "Conformation:: updating coordinates for " << seqpos << std::endl;
2339  Residue & rsd( *residues_[ seqpos ] );
2340  for ( Size j=1, j_end = rsd.natoms(); j<= j_end; ++j ) {
2341  rsd.set_xyz( j, atom_tree_->xyz( AtomID(j,seqpos) ) );
2342  }
2343  rsd.update_actcoord();
2344 
2345  //update orbital coords!
2346  this->update_orbital_coords(rsd);
2347 
2348 
2349 
2350 
2351  if ( fire_signal ) {
2352  notify_xyz_obs( XYZEvent( this ) );
2353  }
2354 }
2355 
2356 
2357 ///////////////////////////////////////////////////////////////////////////////
2358 void
2360 {
2361  if ( !residue_torsions_need_updating_ ) return;
2363 
2364  // fill in the new torsion angles in the pose's Residues
2365  // this could be made way faster...
2366  //
2367  // eg by keeping track of the subset of torsions that could have changed
2368  //
2369  PROF_START( basic::UPDATE_RESIDUE_TORSIONS );
2370  for ( Size i=1, i_end = size(); i<= i_end; ++i ) {
2371  update_residue_torsions( i, false );
2372  residues_[ i ]->update_actcoord();
2373  }
2374  PROF_STOP( basic::UPDATE_RESIDUE_TORSIONS );
2375 
2376  notify_xyz_obs( XYZEvent( this ) );
2377 }
2378 
2379 
2380 ///////////////////////////////////////////////////////////////////////////////
2381 // private
2382 void
2383 Conformation::update_residue_torsions( Size const seqpos, bool const fire_signal ) const
2384 {
2385  using id::BB;
2386  using id::CHI;
2387 
2388  Residue & rsd( *residues_[seqpos] );
2389 
2390  // mainchain
2391  for ( Size j=1, j_end = rsd.mainchain_torsions().size(); j<= j_end; ++j ) {
2392  rsd.mainchain_torsions()[ j ] = atom_tree_torsion( TorsionID(seqpos,BB,j) );
2393  }
2394 
2395  // chi
2396  for ( Size j=1, j_end = rsd.nchi(); j<= j_end; ++j ) {
2397  rsd.chi()[ j ] = atom_tree_torsion( TorsionID( seqpos, CHI, j ) );
2398  }
2399 
2400  //update orbital coords!
2401  this->update_orbital_coords(rsd);
2402 
2403  if ( fire_signal ) {
2404  notify_xyz_obs( XYZEvent( this ) );
2405  }
2406 }
2407 
2408 ///////////////////////////////////////////////////////////////////////////////
2409 void
2411  foreach(core::Size atom_with_orbitals, rsd.atoms_with_orb_index()){
2412  utility::vector1<core::Size> const & orbital_indices(rsd.bonded_orbitals(atom_with_orbitals));
2413  foreach(core::Size orbital_index, orbital_indices){
2414  Vector orb_xyz(rsd.build_orbital_xyz(orbital_index));
2415  rsd.set_orbital_xyz(orbital_index, orb_xyz );
2416  }
2417  }
2418 }
2419 
2420 
2421 
2422 
2423 ///////////////////////////////////////////////////////////////////////////////
2424 /// @details check that the residue torsions are in sync with the residue coords and
2425 /// atomtree coords
2426 void
2428 {
2429  using namespace ObjexxFCL::fmt;
2430  using basic::subtract_degree_angles;
2431 
2434  basic::Tracer my_tracer( "core.conformation", basic::t_warning );
2435 
2436  // std::string const tag( "Conformation::debug_torsions():" );
2437 
2438  if ( verbose ) {
2439  int width = 14;
2440  my_tracer
2441  // << A( width, "torsion_id" )
2442  << A( width, "rsd_dihedral" )
2443  << A( width, "atr_dihedral" )
2444  << A( width, "rsd_torsion" )
2445  << A( width, "torsion" )
2446  << A( width, "atr_torsion" )
2447  << std::endl;
2448  }
2449  for ( Size i=1; i<= size(); ++i ) {
2450  Residue const & rsd( residue(i) );
2451 
2452  for ( Size r=1; r<= 2; ++r ) {
2453  id::TorsionType const type( r == 1 ? id::BB :
2454  id::CHI );
2455  Size const n( r == 1 ? rsd.mainchain_atoms().size() : rsd.nchi() );
2456 
2457 
2458  for ( Size j=1; j<= n; ++j ) {
2459  TorsionID const tor_id( i, type, j );
2460  AtomID atom1,atom2,atom3,atom4;
2461  bool const fail
2462  ( get_torsion_angle_atom_ids( tor_id, atom1, atom2, atom3, atom4 ) );
2463  if ( fail ) {
2464  if ( ( r == 1 ) &&
2465  ( ( j == 1 && fold_tree_->is_cutpoint( i-1 ) ) ||
2466  ( j >= n-1 && fold_tree_->is_cutpoint( i ) ) ) ) continue;
2467 
2468  my_tracer << " missed torsion: " << tor_id << std::endl;
2469  continue;
2470  }
2471 
2472  Real const rsd_dihedral
2473  (numeric::dihedral(residue(atom1.rsd()).atom(atom1.atomno()).xyz(),
2474  residue(atom2.rsd()).atom(atom2.atomno()).xyz(),
2475  residue(atom3.rsd()).atom(atom3.atomno()).xyz(),
2476  residue(atom4.rsd()).atom(atom4.atomno()).xyz()));
2477 
2478  Real const atom_tree_dihedral
2479  ( numeric::dihedral( atom_tree_->xyz( atom1 ),
2480  atom_tree_->xyz( atom2 ),
2481  atom_tree_->xyz( atom3 ),
2482  atom_tree_->xyz( atom4 ) ) );
2483 
2484  Real const rsd_torsion
2485  ( r == 1 ? rsd.mainchain_torsion(j) : rsd.chi(j) );
2486 
2487  ASSERT_ONLY(Real const dev
2488  ( std::abs( subtract_degree_angles(rsd_dihedral,atom_tree_dihedral))+
2489  std::abs( subtract_degree_angles(rsd_dihedral,rsd_torsion))+
2490  std::abs( subtract_degree_angles(rsd_dihedral,torsion(tor_id)))+
2491  std::abs( subtract_degree_angles(rsd_dihedral,
2492  atom_tree_torsion(tor_id))));)
2493 
2494  assert( dev < 1e-3 );
2495 
2496  if ( verbose ) {
2497  int width = 14;
2498  int precision = 4;
2499  my_tracer
2500  // << F( width, precision, tor_id )
2501  << F( width, precision, rsd_dihedral )
2502  << F( width, precision, atom_tree_dihedral )
2503  << F( width, precision, rsd_torsion )
2504  << F( width, precision, torsion(tor_id) )
2505  << F( width, precision, atom_tree_torsion(tor_id) )
2506  << std::endl;
2507 
2508  // my_tracer << ' ' << tor_id << ' ' <<
2509  // rsd_dihedral << ' ' <<
2510  // atom_tree_dihedral << ' ' <<
2511  // rsd_torsion << ' ' <<
2512  // torsion( tor_id ) << ' ' <<
2513  // atom_tree_torsion( tor_id ) << std::endl;
2514  }
2515  } // j = torsionID
2516  } // r = torsiontype
2517  } // i = seqpos
2518 
2519 }
2520 
2521 
2522 ///////////////////////////////////////////////////////////////////////////////
2523 void
2525 {
2526  for ( Size ii = 1; ii <= size(); ++ii )
2527  {
2528  if ( residues_[ ii ]->requires_actcoord() )
2529  {
2530  residues_[ ii ]->update_actcoord();
2531  }
2532  }
2533 }
2534 
2535 void
2537 {
2538  if ( residues_[ resid ]->requires_actcoord() ) {
2539  residues_[ resid ]->update_actcoord();
2540  }
2541 }
2542 
2543 void
2545 {
2546  residues_[ resid ]->update_orbital_coords();
2547 }
2548 
2549 
2550 
2551 /////////////////////////////////////////////////////////////////////////////
2552 /// @brief clear data
2553 void
2555 {
2556  pre_nresidue_change(); // nuke old atom tree update-data before destroying coordinates.
2557 
2558  fold_tree_->clear();
2559  atom_tree_->clear();
2560  residues_.clear();
2561  dof_moved_.clear();
2562  xyz_moved_.clear();
2563  chain_endings_.clear();
2564 }
2565 
2566 ///////////////////////////////////////////////////////////////////////////////
2567 /// @brief Show each residue in the conformation and its connections.
2568 void
2570 {
2572 }
2573 
2574 
2575 // This method is a rewrite of an earlier version to include an argument
2576 // for desired output stream. This is to be more consistent with typical
2577 // show() methods and allows for simple << operator overloading for use in
2578 // PyRosetta. ~ Labonte
2579 /// @brief Show each residue in the conformation and its connections.
2580 void
2582 {
2583  for (Size i = 1; i <= size(); ++i) {
2584  Residue const &res(*(residues_[i]));
2585  Size const nconn(res.n_residue_connections());
2586  os << "RESCON: " << i << ' ' << res.name() << " n-conn= " << nconn <<
2587  " n-poly= " << res.n_polymeric_residue_connections() <<
2588  " n-nonpoly= " << res.n_non_polymeric_residue_connections();
2589  for (Size j = 1; j <= nconn; ++j) {
2590  os << " conn# " << j << ' ' << res.residue_connect_atom_index( j )
2591  << ' ' << res.connect_map(j).resid() << ' ' <<
2592  res.connect_map(j).connid();
2593  }
2594  os << std::endl;
2595  }
2596 }
2597 
2598 id::AtomID
2600  Size const seqpos,
2601  int const connection_index
2602 ) const
2603 {
2604  Residue const & rsd( *residues_[ seqpos ] );
2605  return id::AtomID( rsd.residue_connection ( connection_index ).atomno(),
2606  rsd.residue_connection_partner( connection_index ) );
2607  //utility_exit_with_message( "Conformation::inter_residue_connection_partner is undefined!" );
2608  //return id::BOGUS_ATOM_ID;
2609 }
2610 
2611 /// @detailed
2612 /// virtual atoms are excluded by default
2615  id::AtomID atomid,
2616  bool virt // = false
2617 ) const
2618 {
2619  conformation::Residue const & primary_residue(residue(atomid.rsd()));
2620 
2621  utility::vector1<id::AtomID> neighbors;
2622 
2623  // add all the atoms in the same residue
2624  chemical::AtomIndices const & intrares_atomnos(primary_residue.bonded_neighbor(atomid.atomno()));
2625  for (Size i = 1; i <= intrares_atomnos.size(); ++i) {
2626  if (virt || ! primary_residue.is_virtual(intrares_atomnos[i]) ) {
2627  neighbors.push_back(id::AtomID(intrares_atomnos[i], atomid.rsd()));
2628  }
2629  }
2630 
2631  // add all the atoms in other residues
2632  Size const num_connections(primary_residue.n_residue_connections());
2633  for (Size i = 1; i <= num_connections; ++i) {
2634  if (primary_residue.residue_connect_atom_index(i) == atomid.atomno() &&
2635  !primary_residue.connection_incomplete(i)) {
2636  chemical::ResConnID resconid(primary_residue.actual_residue_connection(i));
2637  Size connected_atomno(residue(resconid.resid()).residue_connect_atom_index(resconid.connid()));
2638  if (virt || ! residue(resconid.resid()).is_virtual(connected_atomno)) {
2639  neighbors.push_back(id::AtomID(connected_atomno, resconid.resid()));
2640  }
2641  }
2642  }
2643 
2644  return neighbors;
2645 }
2646 
2647 ///////////////////////////////////////////////////////////////////////////////
2648 void
2650  id::AtomID_Mask missing // make local copy
2651 )
2652 {
2653  using namespace basic;
2654 
2655  update_residue_coordinates(); //since we will be using residue_(seqpos) below
2656 
2657  for ( Size i=1; i<= size(); ++i ) {
2658  Residue const & rsd( residue_(i) ); // prevent many many calls to update_residue_torsions()
2659  Size const natoms( rsd.natoms() );
2660  Size tries(0);
2661  while ( true ) {
2662  ++tries;
2663  if ( tries > 10000 ) {
2664  utility_exit_with_message("too many tries in fill_missing_atoms!");
2665  }
2666  bool any_missing( false );
2667  Size num_present = 0;
2668  for ( Size j=1; j<= natoms; ++j ) {
2669  if ( !missing[ AtomID( j, i ) ] ) num_present += 1;
2670  }
2671  for ( Size j=1; j<= natoms; ++j ) {
2672  AtomID const id( j, i );
2673  if ( missing[ id ] ) {
2674  // Virtual atoms don't get written to the PDB file, so we shouldn't expect them in input.
2675  if ( rsd.atom_type(j).is_heavyatom() && ! rsd.is_virtual(j)) {
2676  TR.Warning << "[ WARNING ] missing heavyatom: " << rsd.atom_name(j) <<
2677  " on residue " << rsd.name() << ' ' << i << std::endl;
2678  }
2679  any_missing = true;
2680 
2681  // check if our stub atoms are all present
2682  AtomID const
2683  stub_atom1( rsd.icoor( j ).stub_atom1().atom_id( i, *this ) ),
2684  stub_atom2( rsd.icoor( j ).stub_atom2().atom_id( i, *this ) ),
2685  stub_atom3( rsd.icoor( j ).stub_atom3().atom_id( i, *this ) );
2686 
2687  //std::cout << "Still missing: " << id << ' ' <<
2688  // stub_atom1 << ' ' << missing[ stub_atom1 ] << ' ' <<
2689  // stub_atom2 << ' ' << missing[ stub_atom2 ] << ' ' <<
2690  // stub_atom3 << ' ' << missing[ stub_atom3 ] << std::endl;
2691 
2692  if ( num_present < 3 && !missing[ stub_atom1 ] ) {
2693  // with < 3 atoms, we can't build any stubs, so we're stuck forever unless we punt:
2694  //if ( rsd.natoms() == 3 && !missing[ stub_atom1 ] ) {
2695  // special case, eg HOH water, O is present H's missing
2696  using numeric::random::uniform;
2697  Vector xyz1( xyz( stub_atom1 ) ), xyz2( xyz( stub_atom2 ) ), xyz3( xyz( stub_atom3 ) );
2698  if ( missing[ stub_atom2 ] ) xyz2 = Vector( uniform(), uniform(), uniform() );
2699  if ( missing[ stub_atom3 ] ) xyz3 = Vector( uniform(), uniform(), uniform() );
2700  kinematics::Stub const stub( xyz1, xyz2, xyz3 );
2701  set_xyz( id, stub.spherical( rsd.icoor(j).phi(), rsd.icoor(j).theta(), rsd.icoor(j).d() ) );
2702  missing[id] = false;
2703  num_present += 1;
2704 
2705  } else if ( id == stub_atom1 || id == stub_atom2 || id == stub_atom3 ) {
2706  // the root atom of the default residue tree or one of it's stub_atoms...
2707  // special case requires careful handling:
2708  // build new residue trees for the ideal-coordinates residue, look for one
2709  // that doesn't have this problem...
2710 
2711 
2712  ResidueOP tmp_rsd( new Residue( rsd.type(), false /*dummy arg*/ ) );
2713  tmp_rsd->seqpos( i );
2714 
2715  for ( Size root_atomno=1; root_atomno<= natoms; ++root_atomno ) {
2716  if ( root_atomno == j ) continue;
2717 
2718  kinematics::AtomPointer2D atom_pointer( i );
2719  build_residue_tree( root_atomno, *tmp_rsd, atom_pointer[i], true/*root is jump*/ );
2720  AtomTree rsd_tree( atom_pointer );
2721 
2722  AtomID const
2723  new_stub_atom1( rsd_tree.atom( id ).input_stub_atom1_id() ),
2724  new_stub_atom2( rsd_tree.atom( id ).input_stub_atom2_id() ),
2725  new_stub_atom3( rsd_tree.atom( id ).input_stub_atom3_id() );
2726 
2727  if ( !missing[ new_stub_atom1 ] && !missing[ new_stub_atom2 ] && !missing[ new_stub_atom3 ] ) {
2728  TR.Warning << "[ WARNING ] Building missing atom (" << rsd.atom_name( j ) <<
2729  ") at root of residue tree, using stubs: " <<
2730  rsd.atom_name( new_stub_atom1.atomno() ) << ' ' <<
2731  rsd.atom_name( new_stub_atom2.atomno() ) << ' ' <<
2732  rsd.atom_name( new_stub_atom3.atomno() ) <<
2733  "\nThis probably means that a torsion angle is being taken from the ideal residue and"
2734  "\nshould be further optimized..." << std::endl;
2735  kinematics::Stub stub
2736  ( rsd.xyz( new_stub_atom1.atomno() ),
2737  rsd.xyz( new_stub_atom2.atomno() ),
2738  rsd.xyz( new_stub_atom3.atomno() ) );
2739  set_xyz( id, stub.spherical( rsd_tree.dof( DOF_ID( id, id::PHI ) ),
2740  rsd_tree.dof( DOF_ID( id, id::THETA ) ),
2741  rsd_tree.dof( DOF_ID( id, id::D ) ) ) );
2742  missing[ id ] = false;
2743  num_present += 1;
2744  break;
2745  }
2746  if ( root_atomno == natoms ) {
2747  //std::cout << "[ ERROR ] too many missing atoms: " << rsd.name() << ' ' << rsd.seqpos() << std::endl;
2748  //for ( int k=1; k<= natoms; ++k ) {
2749  // std::cout << rsd.atom_name(k) << ' ' << missing[ AtomID( k, i ) ] << std::endl;
2750  //}
2751  //utility_exit_with_message( "unable to build missing atom!");
2752  }
2753  } // root_atomno = 1,natoms
2754  } else {
2755  // typical case
2756  if ( !missing[ stub_atom1 ] && !missing[ stub_atom2 ] && !missing[ stub_atom3 ] ) {
2757  set_xyz( id , rsd.build_atom_ideal( j, *this ) );
2758  missing[ id ] = false;
2759  num_present += 1;
2760  }
2761  }
2762  }
2763  }
2764  if ( !any_missing ) break;
2765  }
2766  } // i = 1..size()
2767 
2768 }
2769 
2770 // @brief returns true if atom is part of backbone. There is a version of this in Residue.hh
2771 // The problem with that function is that accessing a residue in the pose triggers a refold
2772 // which is really slow. We do not need a correctly folded residue to makethis check
2773 bool
2774 Conformation::atom_is_backbone_norefold( Size const pos, Size const atomno ) const
2775 {
2776  return ( ( *residues_[ pos ] ).atom_is_backbone( atomno ) );
2777 }
2778 
2779 
2780 ///////////////////////////////////////////////////////////////////////////////
2781 void
2783 {
2784 
2785  chain_endings_.clear();
2786 
2787  for ( Size i=1; i< size(); ++i ) {
2788  // should there be a chain ending between i and i+1 ?
2789  if ( residues_[i]->is_polymer() && residues_[i]->is_upper_terminus() ) {
2790  chain_endings_.push_back( i );
2791  }
2792  }
2793 
2795 }
2796 
2797 ///////////////////////////////////////////////////////////////////////////////
2798 void
2800 {
2801  Size chain(1);
2802  for ( Size i=1; i<= size(); ++i ) {
2803  residues_[i]->chain( chain );
2804  if ( chain <= chain_endings_.size() && (Size) chain_endings_[chain] == i ) {
2805  ++chain;
2806  }
2807  }
2808 
2809 }
2810 
2811 ///////////////////////////////////////////////////////////////////////////////
2814 {
2815  return chain_endings_;
2816 }
2817 
2818 ///////////////////////////////////////////////////////////////////////////////
2819 void
2821 {
2822  // make sure that all positions in the new endings list < the size of
2823  // the Conformation
2824  for ( utility::vector1< Size >::const_iterator i = endings.begin(), ie = endings.end(); i != ie; ++i ) {
2825  if ( (*i) >= size() ) {
2826  utility_exit_with_message("new chain endings list contains positions >= Conformation::size()");
2827  }
2828  }
2829 
2830  chain_endings_ = endings;
2831  std::sort( chain_endings_.begin(), chain_endings_.end() );
2833 }
2834 
2835 ///////////////////////////////////////////////////////////////////////////////
2836 
2837 void
2839 {
2840  assert( seqpos >= 1 && seqpos < size() ); // dont count last residue as chain ending
2841 
2842  chain_endings_.push_back( seqpos );
2843  std::sort( chain_endings_.begin(), chain_endings_.end() );
2844 
2846 }
2847 
2848 ///////////////////////////////////////////////////////////////////////////////
2849 void
2851 {
2852  utility::vector1< Size >::iterator it( std::find( chain_endings_.begin(), chain_endings_.end(), seqpos ) );
2853  if ( it == chain_endings_.end() ) {
2854  utility_exit_with_message("tried to delete nonexistent chain ending");
2855  }
2856  chain_endings_.erase( it );
2858 }
2859 
2860 ///////////////////////////////////////////////////////////////////////////////
2861 void
2863  chain_endings_.clear();
2865 }
2866 
2867 ///////////////////////////////////////////////////////////////////////////////
2868 void
2870 {
2871  chain_endings_.clear();
2872  for ( Size i=1, ie=size()-1; i<=ie; ++i ) {
2873  if ( residues_[i+1]->chain() != residues_[i]->chain() ) {
2874  assert( residues_[i+1]->chain() > residues_[i]->chain() );
2875  // assert( residues_[i+1]->chain() == residues_[i]->chain() + 1 );
2876  chain_endings_.push_back( i );
2877  }
2878  }
2879 }
2880 
2881 ///////////////////////////////////////////////////////////////////////////////
2882 /// @details PRIVATE: wrap direct access to the Residues container for replacement
2883 /// also handles redimensioning and setting of the _moved arrays
2884 /// @warning Since this is the innermost routine when replacing a residue, it does not
2885 /// fire any signals to ensure that observer access to the residues container does not
2886 /// trigger an atom tree refold prematurely.
2887 void
2889  Size const seqpos,
2890  Residue const & new_rsd
2891 )
2892 {
2893 
2894  int const old_chain = residues_[ seqpos ]->chain();
2895  ResidueOP old_residue = residues_[ seqpos ];
2896  residues_[ seqpos ] = new_rsd.clone();
2897  residues_[ seqpos ]->seqpos( seqpos );
2898  residues_[ seqpos ]->chain( old_chain );
2899 
2900  residues_[ seqpos ]->copy_residue_connections( *old_residue );
2901 
2902  //residues_[ seqpos ]->clear_residue_connections();
2903  // rederive polymeric connection status from chain id's or termini status
2904  //update_polymeric_connection( seqpos-1 );
2905  //update_polymeric_connection( seqpos );
2906 
2907  // mark this position as having changed, resize the _moved arrays
2908  structure_moved_ = true;
2909 
2910  utility::vector1< bool > & xyz_m( xyz_moved_[seqpos] );
2911  utility::vector1< bool > & dof_m( dof_moved_[seqpos] );
2912  xyz_m.clear(); // guarantee that they're all set to true
2913  xyz_m.resize( new_rsd.natoms(), true );
2914  { // this is a little tricky:
2915  // on the one hand, we dont want to obliterate any existing dof_moved info
2916  // on the other, if we are just replacing a residue, setting dof_moved to TRUE for this position
2917  // would likely lead to a massive score recalculation. So here's a compromise
2918  bool any_dof_moved( false );
2919  for ( Size i=1; i<= dof_m.size(); ++i ) {
2920  if ( dof_m[ i ] ) {
2921  any_dof_moved = true;
2922  break;
2923  }
2924  }
2925  dof_m.clear();
2926  dof_m.resize( new_rsd.natoms(), any_dof_moved );
2927  }
2928 
2929 }
2930 
2931 
2932 ///////////////////////////////////////////////////////////////////////////////
2933 /// @details PRIVATE: wrap direct access to the Residues container for replacement
2934 /// also handles redimensioning and setting of the _moved arrays and updating of sequence numbers
2935 /// @warning Since this is the innermost routine when replacing a residue, it does not
2936 /// fire any signals to ensure that observer access to the residues container does not
2937 /// trigger an atom tree refold prematurely.
2938 void
2940  Size const seqpos,
2941  Residue const & new_rsd,
2942  bool const use_lower_chain, // = false,
2943  bool const new_chain // = false
2944 )
2945 {
2946  assert( ! new_chain || residues_[ seqpos-1 ]->chain() != residues_[ seqpos ]->chain() );
2947 
2948  Size const old_size( residues_.size() ), new_size( old_size+1 );
2949 
2950  // first renumber things
2951  utility::vector1< Size > old2new( old_size, 0 );
2952  for ( Size i=1; i<= old_size; ++i ) {
2953  if ( i< seqpos ) old2new[i] = i;
2954  else old2new[i] = i+1;
2955  }
2956  update_sequence_numbering( new_size, old2new ); // numbering in residues_ and *_moved
2957 
2958  Size const old_chain( ( new_chain || use_lower_chain || Size(seqpos) == new_size ) ?
2959  residues_[ seqpos-1 ]->chain() :
2960  residues_[ seqpos ]->chain() );
2961 
2962  Size const newrsd_chain( new_chain ? old_chain + 1 :old_chain );
2963 
2964  residues_.insert( residues_.begin() + (seqpos-1), new_rsd.clone() );
2965  assert( residues_[seqpos]->name() == new_rsd.name() );
2966  residues_[ seqpos ]->seqpos( seqpos );
2967  residues_[ seqpos ]->chain( newrsd_chain );
2968  if ( new_chain ) {
2969  for ( Size ii = seqpos+1; ii <= new_size; ++ii ) {
2970  residues_[ ii ]->chain( residues_[ ii ]->chain() + 1 );
2971  }
2972  }
2973  // wipe residue connection data that may have been cloned from the original residue
2974  residues_[ seqpos ]->clear_residue_connections();
2975 
2976  // rederive polymeric connection status from chain id's or termini status
2977  update_polymeric_connection( seqpos-1 );
2978  update_polymeric_connection( seqpos );
2979 
2980  // recompute the chain_endings_ array from residues_[]->chain()
2982 
2983  // mark this position as having changed, resize the _moved arrays
2984  structure_moved_ = true;
2985 
2986  utility::vector1< bool > & xyz_m( xyz_moved_[seqpos] );
2987  utility::vector1< bool > & dof_m( dof_moved_[seqpos] );
2988  assert( xyz_m.empty() && dof_m.empty() );
2989  xyz_m.resize( new_rsd.natoms(), true );
2990  dof_m.resize( new_rsd.natoms(), false );
2991 
2992  secstruct_.insert( secstruct_.begin() + ( seqpos - 1 ), 'L' );
2993 }
2994 
2995 
2996 ///////////////////////////////////////////////////////////////////////////////
2997 /// @details PRIVATE: wrap direct access to the Residues container for replacement
2998 /// also handles redimensioning and setting of the _moved arrays and updating of sequence numbers
2999 /// @warning Since this is the innermost routine when replacing a residue, it does not
3000 /// fire any signals to ensure that observer access to the residues container does not
3001 /// trigger an atom tree refold prematurely.
3002 void
3004  Size const seqpos
3005 )
3006 {
3007  Size const old_size( residues_.size() ), new_size( old_size-1 );
3008 
3009  // delete from residues_
3010  residues_.erase( residues_.begin()+seqpos-1 );
3011 
3012  // now renumber things
3013  utility::vector1< Size > old2new( old_size, 0 );
3014  for ( Size i=1; i<= old_size; ++i ) {
3015  if ( i < seqpos ) old2new[i] = i;
3016  else if ( i > seqpos ) old2new[i] = i-1;
3017  }
3018  update_sequence_numbering( new_size, old2new ); // numbering in residues_ and *_moved
3019 
3020  // rederive polymeric connection status from chain id's or termini status
3021  if ( seqpos>1 ) update_polymeric_connection( seqpos-1 );
3022 
3023  // recompute the chain_endings_ array from residues_[]->chain()
3025  rederive_chain_ids(); // necessary if we deleted an entire, single-residue chain
3026 
3027  // update arrays
3028  secstruct_.erase( secstruct_.begin() + ( seqpos - 1 ) );
3029 }
3030 
3031 
3032 ///////////////////////////////////////////////////////////////////////////////
3033 /// @details PRIVATE: wrap direct access to the Residues container for appending
3034 /// @warning Since this is the innermost routine when replacing a residue, it does not
3035 /// fire any signals to ensure that observer access to the residues container does not
3036 /// trigger an atom tree refold prematurely.
3037 void
3038 Conformation::residues_append( Residue const & new_rsd, bool const start_new_chain )
3039 {
3040  residues_.push_back( new_rsd.clone() );
3041  // ensure that the residue number is set
3042  Size const nres( residues_.size() );
3043  residues_[ nres ]->seqpos( nres );
3044 
3045  // apl If this is the first residue overall, set the chain id to 1.
3046  // Otherwise, set the chain id based on whether this a new chain or not.
3047  if ( nres > 1 ) {
3048  if ( start_new_chain ) {
3049  residues_[ nres ]->chain( residues_[ nres - 1 ]->chain() + 1 );
3050  TR.Debug << "Starting a new chain: chain " << residues_[nres - 1]->chain() << std::endl;
3051  } else {
3052  residues_[ nres ]->chain( residues_[ nres - 1 ]->chain() );
3053  }
3056  } else {
3057  residues_[ nres ]->chain( 1 );
3058  }
3059  // wipe residue connection data that may have been cloned from the original residue
3060  residues_[ nres ]->clear_residue_connections();
3061 
3062  // update polymeric connection status from chain id's and termini status
3063  if ( nres > 1 ) update_polymeric_connection( nres-1 );
3064 
3065  // have to calculate scores with this guy
3066  structure_moved_ = true;
3067  xyz_moved_.resize( nres );
3068  dof_moved_.resize( nres );
3069  xyz_moved_.resize( nres, new_rsd.natoms(), true );
3070  dof_moved_.resize( nres, new_rsd.natoms(), false );
3071 
3072  secstruct_.resize( nres, 'L' );
3073 
3074 }
3075 
3076 
3077 ///////////////////////////////////////////////////////////////////////////////
3078 /// @details Returns a mask of residues over which scoring is restricted.
3079 /// Only these residues will be used in constructing the neighbor list.
3082  Size const nres( residues_.size() );
3083  return utility::vector1<bool>(nres, true);
3084 }
3085 
3086 ///////////////////////////////////////////////////////////////////////////////
3087 /// @details Returns a weight to be used when scoring this residue.
3088 Real
3090  return 1.0;
3091 }
3092 
3093 
3094 /// @brief clear all observers
3095 /// @remarks ConnectionEvent::DISCONNECT will be sent to all observers
3097  // send the signal first
3099 
3100  // clear all hubs
3101  xyz_obs_hub_.clear();
3102  length_obs_hub_.clear();
3103  identity_obs_hub_.clear();
3104  general_obs_hub_.clear();
3105  connection_obs_hub_.clear();
3106 }
3107 
3108 
3109 /// @brief fire a ConnectionEvent::TRANSFER to transfer observers from some
3110 /// source Conformation
3111 /// @param src Take observers from this source Conformation.
3112 /// @remarks Only observers that properly honor the TRANSFER event by
3113 /// re-attaching themselves to 'this' Conformation will be transferred.
3115  // tell the observers in source Conformation that a transfer is
3116  // occurring and they need to re-register themselves with 'this'
3117  // conformation
3118  if ( this == &src ) return; // do not transfer observers from yourself
3120 }
3121 
3122 
3123 /// @brief wait for stdin after sending a GeneralEvent signal
3124 void
3125 Conformation::debug_pause( bool const flag ) const
3126 {
3127  if ( flag ) {
3128  general_obs_hub_.pause();
3129  } else {
3130  general_obs_hub_.unpause();
3131  }
3132 }
3133 
3134 
3135 /// @brief waiting for stdin after sending a GeneralEvent signal?
3136 bool
3138 {
3139  return general_obs_hub_.pausing();
3140 }
3141 
3142 
3143 /// @brief block signals from being sent and buffer them to be
3144 /// sent after unblocking
3145 void
3147 {
3148  general_obs_hub_.buffer();
3149  identity_obs_hub_.buffer();
3150  length_obs_hub_.buffer();
3151  xyz_obs_hub_.buffer();
3152 }
3153 
3154 
3155 /// @brief block signals from being sent
3156 /// @warning for safety, ConnectionEvents are never blocked
3157 void
3159 {
3160  general_obs_hub_.block();
3161  identity_obs_hub_.block();
3162  length_obs_hub_.block();
3163  xyz_obs_hub_.block();
3164 }
3165 
3166 
3167 /// @brief allow signals to be sent
3168 /// @details If unblocking after buffering, buffered/held signals will be sent.
3169 void
3171 {
3172  general_obs_hub_.unblock();
3173  identity_obs_hub_.unblock();
3174  length_obs_hub_.unblock();
3175  xyz_obs_hub_.unblock();
3176 }
3177 
3178 
3179 /// @brief are signals being blocked and buffered?
3180 bool
3182 {
3183  return general_obs_hub_.buffering();
3184 }
3185 
3186 
3187 /// @brief are signals being blocked?
3188 bool
3190 {
3191  return general_obs_hub_.blocked();
3192 }
3193 
3194 
3195 
3196 /// @brief Optimizing the common case of assigning a conformation to another with
3197 /// the same sequence.
3198 void
3200  Conformation const & src
3201 )
3202 {
3203  assert( src.size() == size() );
3204 
3205  /// BEGIN IN PLACE OPTIMIZATION
3206 
3207  // Do not allocate new residue objects, just reuse the old ones
3208  for ( Size ii = 1; ii <= size(); ++ii ) {
3209  assert( & residues_[ ii ]->type() == & src.residues_[ ii ]->type() );
3210  assert( residues_[ ii ]->seqpos() == src.residues_[ ii ]->seqpos() );
3211  assert( residues_[ ii ]->chain() == src.residues_[ ii ]->chain() );
3212  assert( residues_[ ii ]->connections_match( *src.residues_[ ii ] ));
3213  for ( Size jj = 1; jj <= residues_[ ii ]->natoms(); ++jj ) {
3214  residues_[ ii ]->set_xyz( jj, src.residues_[ ii ]->xyz( jj ) );
3215  }
3216  residues_[ ii ]->mainchain_torsions( src.residues_[ ii ]->mainchain_torsions() );
3217  residues_[ ii ]->chi( src.residues_[ ii ]->chi() );
3218  residues_[ ii ]->actcoord() = src.residues_[ ii ]->actcoord();
3219  }
3220 
3221  /// END IN PLACE OPTIMIZATION
3222 
3223  // kinematics
3224  (*fold_tree_) = (*src.fold_tree_);
3225  (*atom_tree_) = (*src.atom_tree_); // internally performs an in-place copy if it can
3226 
3227  // chain info
3229  // secstruct
3230  secstruct_ = src.secstruct_;
3231 
3232  // bookkeeping
3235 
3236  dof_moved_ = src.dof_moved_;
3237  xyz_moved_ = src.xyz_moved_;
3238 
3240 }
3241 
3242 
3243 /// @brief notify ConnectionEvent observers
3244 /// @remarks called upon a change in the state of connection between
3245 /// the Conformation and the observer (e.g. destruction of Conformation
3246 /// or transfer of connection)
3247 void
3249  connection_obs_hub_( e );
3250 }
3251 
3252 
3253 /// @brief notify GeneralEvent observers
3254 /// @remarks should only be called when there are no other suitable event types
3255 /// since specific event notifications will automatically fire a GeneralEvent signal
3256 void
3258  general_obs_hub_( e );
3259 }
3260 
3261 
3262 /// @brief notify IdentityEvent observers
3263 /// @param e the event
3264 /// @param fire_general fire a GeneralEvent afterwards? default true
3265 void
3266 Conformation::notify_identity_obs( IdentityEvent const & e, bool const fire_general ) const {
3267  identity_obs_hub_( e );
3268  if ( fire_general ) {
3269  notify_general_obs( e );
3270  }
3271 }
3272 
3273 
3274 /// @brief notify LengthEvent observers
3275 /// @param e the event
3276 /// @param fire_general fire a GeneralEvent afterwards? default true
3277 void
3278 Conformation::notify_length_obs( LengthEvent const & e, bool const fire_general ) const {
3279  length_obs_hub_( e );
3280  if ( fire_general ) {
3281  notify_general_obs( e );
3282  }
3283 }
3284 
3285 
3286 /// @brief notify XYZEvent observers
3287 /// @param e the event
3288 /// @param fire_general fire a GeneralEvent afterwards? default true
3289 void
3290 Conformation::notify_xyz_obs( XYZEvent const & e, bool const fire_general ) const {
3291  xyz_obs_hub_( e );
3292  if ( fire_general ) {
3293  notify_general_obs( e );
3294  }
3295 }
3296 
3297 bool
3300 }
3301 
3302 bool
3305 }
3306 
3307 bool
3309  Size const seqpos1( std::max( 1, (int) size() / 2 ) );
3310  Size const seqpos2( std::min( (int) size(), (int) size() / 2 + 2 ) );
3311 
3312  // if one of them is correct we are happy!
3313  bool correct = residue_type( seqpos1 ).residue_type_set().name() == tag;
3314  correct = correct || residue_type( seqpos2 ).residue_type_set().name() == tag;
3315  return correct;
3316 }
3317 
3318  void
3320  id::StubID const & stub_id1,
3321  id::StubID const & stub_id2,
3322  kinematics::RT const & target_rt
3323  )
3324  {
3325  set_dof_moved( atom_tree_->set_stub_transform( stub_id1, stub_id2, target_rt ) );
3326  }
3327 
3328 /// @brief get the transform between two stubs
3331  id::StubID const & stub_id1,
3332  id::StubID const & stub_id2
3333 ) const
3334 {
3335  return atom_tree_->get_stub_transform( stub_id1, stub_id2 );
3336 }
3337 
3338 
3339  void
3341  {
3342  atom_tree_->set_jump_atom_stub_id( id );
3343  }
3344 
3347  return atom_tree_->stub_from_id( id );
3348 }
3349 
3350 /// @brief Returns the AtomTree degree of freedom (DOF) <id>
3351  Real
3352  Conformation::dof( DOF_ID const & id ) const
3353  {
3354  return atom_tree_->dof( id );
3355  }
3356 
3357 /// @brief Sets the AtomTree degree of freedom (DOF) <id> to <setting>
3358  void
3359  Conformation::set_dof( DOF_ID const & id, Real const setting )
3360  {
3361  set_dof_moved( id );
3362  residue_torsions_need_updating_ = true; // might have been a torsion angle
3363  atom_tree_->set_dof( id, setting );
3364  }
3365 
3366 /// @brief Returns the torsion angle defined by <atom[1-4]>
3367  Real
3369  AtomID const & atom1,
3370  AtomID const & atom2,
3371  AtomID const & atom3,
3372  AtomID const & atom4
3373  ) const
3374  {
3375  return atom_tree_->torsion_angle( atom1, atom2, atom3, atom4 );
3376  }
3377 
3378 /// @brief Returns the bond angle defined by <atom[1-3]>
3379  Real
3381  AtomID const & atom1,
3382  AtomID const & atom2,
3383  AtomID const & atom3
3384  ) const
3385  {
3386  return atom_tree_->bond_angle( atom1, atom2, atom3 );
3387  }
3388 
3389 /// @brief Returns the bond length between <atom1> and <atom2>
3390  Real
3392  AtomID const & atom1,
3393  AtomID const & atom2
3394  ) const
3395  {
3396  return atom_tree_->bond_length( atom1, atom2 );
3397  }
3398 
3399  Conformation::Jump const &
3400  Conformation::jump( int const jump_number ) const
3401  {
3402  return atom_tree_->jump( jump_atom_id( jump_number ) );
3403  }
3404 
3405 /// @brief Sets the jump <jump_number> to <new_jump>
3406  void
3408  int const jump_number,
3409  Jump const & new_jump
3410  )
3411  {
3412  assert( new_jump.ortho_check() );
3413  AtomID const id( jump_atom_id( jump_number ) );
3414  atom_tree_->set_jump( id, new_jump );
3415  set_dof_moved( id );
3416  }
3417 
3418 /// @brief Sets a jump and forces immediate calculation of affected XYZ coords
3419  void
3421  int const jump_number,
3422  Jump const & new_jump
3423  )
3424  {
3425  AtomID const id( jump_atom_id( jump_number ) );
3426  assert( new_jump.ortho_check() );
3427  atom_tree_->set_jump_now( id, new_jump );
3428  set_dof_moved( id );
3429  }
3430 
3431 /// @brief access a jump
3432  Conformation::Jump const &
3433  Conformation::jump( AtomID const & id ) const
3434  {
3435  return atom_tree_->jump( id );
3436  }
3437 
3438  void
3440  AtomID const & id,
3441  Jump const & new_jump
3442  )
3443  {
3444  assert( new_jump.ortho_check() );
3445  atom_tree_->set_jump( id, new_jump );
3446  set_dof_moved( id );
3447  }
3448 
3449 /// @brief The upstream and downstream Stubs are the coordinate frames between which this jump is transforming
3451 Conformation::upstream_jump_stub( int const jump_number ) const
3452 {
3453  return atom_tree_->atom( jump_atom_id( jump_number ) ).get_input_stub();
3454 }
3455 
3456 /// @brief The upstream and downstream Stubs are the coordinate frames between which this jump is transforming
3458 Conformation::downstream_jump_stub( int const jump_number ) const
3459 {
3460  return atom_tree_->atom( jump_atom_id( jump_number ) ).get_stub();
3461 }
3462 
3463 /// @brief access xyz coordinates of an atom
3464  PointPosition const &
3465  Conformation::xyz( AtomID const & id ) const
3466  {
3467  return atom_tree_->xyz( id );
3468  }
3469 
3470  void
3472  {
3473  structure_moved_ = false;
3474  dof_moved_.fill_with( false );
3475  xyz_moved_.fill_with( false );
3476  }
3477 
3478 
3479 std::ostream &operator<< (std::ostream &os, Conformation const &conf)
3480 {
3481  conf.show_residue_connections(os);
3482  return os;
3483 }
3484 
3485 } // namespace kinematics
3486 } // namespace core
3487 /**
3488 
3489 // returns TRUE for FAILURE
3490 //private
3491 bool
3492 Conformation::backbone_bond_angle_atoms(
3493  TorsionID const & id,
3494  AtomID & id1,
3495  AtomID & id2,
3496  AtomID & id3
3497 ) const
3498 {
3499  using chemical::AtomIndices;
3500 
3501  int const seqpos( id.rsd() );
3502  int const torsion( id.torsion() );
3503 
3504  Residue const & rsd( *residues_[ seqpos ] );
3505 
3506  AtomIndices const & mainchain( rsd.mainchain_atoms() );
3507 
3508  int const ntorsions( mainchain.size() );
3509  assert( torsion >= 1 && torsion <= ntorsions );
3510 
3511  ///////////////////////////////////////////
3512  // first atom -- may be in seqpos-1
3513  if ( torsion > 1 ) {
3514  id1.rsd() = seqpos;
3515  id1.atomno() = mainchain[ torsion-1 ];
3516  } else {
3517  if ( fold_tree_->is_cutpoint( seqpos-1 ) ) {
3518  if ( rsd.has_variant_type( chemical::CUTPOINT_UPPER ) ) {
3519  id1.rsd() = seqpos;
3520  id1.atomno() = rsd.atom_index( "OVU1" );
3521  } else {
3522  // first bb-torsion is not well-defined
3523  return true; // FAILURE
3524  }
3525  } else {
3526  AtomIndices const & prev_mainchain
3527  ( residue_( seqpos-1 ).mainchain_atoms() );
3528  id1.rsd() = seqpos-1;
3529  id1.atomno() = prev_mainchain[ prev_mainchain.size() ];
3530  }
3531  }
3532 
3533  ///////////////////////////////////////////
3534  // second atom -- for sure in seqpos
3535  id2.rsd() = seqpos;
3536  id2.atomno() = mainchain[ torsion ];
3537 
3538  ///////////////////////////////////////////
3539  // third and fourth atoms, may be in seqpos+1
3540  if ( torsion+1 <= ntorsions ) {
3541  id3.rsd() = seqpos;
3542  id3.atomno() = mainchain[ torsion+1 ];
3543 
3544  } else {
3545  assert( torsion == ntorsions );
3546  if ( fold_tree_->is_cutpoint( seqpos ) ) {
3547  if ( rsd.has_variant_type( chemical::CUTPOINT_LOWER ) ) {
3548  id3.rsd() = seqpos;
3549  id3.atomno() = rsd.atom_index( "OVL1" );
3550  } else {
3551  // last bb-bond angle not well defined
3552  return true; // FAILURE
3553  }
3554  } else {
3555  AtomIndices const & next_mainchain
3556  ( residue_( seqpos+1 ).mainchain_atoms() );
3557  id3.rsd() = seqpos+1;
3558  id3.atomno() = next_mainchain[ 1 ];
3559  } // seqpos is a cutpoint
3560  } // torsion+1 <= ntorsions
3561 
3562  return false;
3563 }
3564 
3565 // returns TRUE for FAILURE
3566 //private
3567 bool
3568 Conformation::backbone_bond_length_atoms(
3569  TorsionID const & id,
3570  AtomID & id1,
3571  AtomID & id2,
3572 ) const
3573 {
3574  using chemical::AtomIndices;
3575 
3576  int const seqpos( id.rsd() );
3577  int const torsion( id.torsion() );
3578 
3579  Residue const & rsd( *residues_[ seqpos ] );
3580 
3581  AtomIndices const & mainchain( rsd.mainchain_atoms() );
3582 
3583  int const ntorsions( mainchain.size() );
3584  assert( torsion >= 1 && torsion <= ntorsions );
3585 
3586  ///////////////////////////////////////////
3587  // first atom -- may be in seqpos-1
3588  if ( torsion > 1 ) {
3589  id1.rsd() = seqpos;
3590  id1.atomno() = mainchain[ torsion-1 ];
3591  } else {
3592  if ( fold_tree_->is_cutpoint( seqpos-1 ) ) {
3593  if ( rsd.has_variant_type( chemical::CUTPOINT_UPPER ) ) {
3594  id1.rsd() = seqpos;
3595  id1.atomno() = rsd.atom_index( "OVU1" );
3596  } else {
3597  // first bb-torsion is not well-defined
3598  return true; // FAILURE
3599  }
3600  } else {
3601  AtomIndices const & prev_mainchain
3602  ( residue_( seqpos-1 ).mainchain_atoms() );
3603  id1.rsd() = seqpos-1;
3604  id1.atomno() = prev_mainchain[ prev_mainchain.size() ];
3605  }
3606  }
3607 
3608  ///////////////////////////////////////////
3609  // second atom -- for sure in seqpos
3610  id2.rsd() = seqpos;
3611  id2.atomno() = mainchain[ torsion ];
3612 
3613  return false; // no failure
3614 }
3615 **/