Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Residue.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 Residue.cc
11 /// @brief
12 /// @author Phil Bradley
13 
14 // Package headers
18 //#include <basic/options/keys/orbitals.OptionKeys.gen.hh>
19 //#include <basic/options/option.hh>
21 #ifdef USEBOOSTSERIALIZE
23 #endif
24 
25 // Project headers
26 #include <core/kinematics/Stub.hh>
27 #include <basic/basic.hh>
28 #include <basic/Tracer.hh>
30 #include <core/chemical/Atom.hh>
33 
34 // ObjexxFCL headers
35 // AUTO-REMOVED #include <ObjexxFCL/ObjexxFCL.hh>
36 // AUTO-REMOVED #include <ObjexxFCL/string.functions.hh>
37 
38 // Numeric headers
39 #include <numeric/xyz.functions.hh>
40 
41 // Utility Headers
42 #include <utility/assert.hh>
43 #include <utility/PyAssert.hh>
44 
45 // C++ Headers
46 #include <iostream>
47 
48 // AUTO-REMOVED #include <core/chemical/AtomTypeSet.hh>
49 #include <utility/vector1.hh>
50 #include <boost/foreach.hpp>
51 
52 //Auto Headers
53 #define foreach BOOST_FOREACH
54 namespace core {
55 namespace conformation {
56 
57 static basic::Tracer TR("core.conformation.Residue");
58 
59 /// @details Constructor from residue type; sets coords to ideal values
60 /// create a residue of type residue_type_in.
61 /// @note Dummmy arg to prevent secret type conversions from ResidueType to Residue
62 Residue::Residue( ResidueType const & rsd_type_in, bool const /*dummy_arg*/ ):
63  utility::pointer::ReferenceCount(),
64  rsd_type_( rsd_type_in ),
65  seqpos_( 0 ),
66  chain_( 0 ),
67  chi_( rsd_type_.nchi(), 0.0 ), // uninit
68  mainchain_torsions_( rsd_type_.mainchain_atoms().size(), 0.0 ),
69  actcoord_( 0.0 ),
70  nonstandard_polymer_( false ),
71  connect_map_( rsd_type_in.n_residue_connections() )
72 {
73 
74  for ( Size i=1; i<= rsd_type_.natoms(); ++i ) {
76  //std::cout << this->atom_name(i) << std::endl;
77  }
78 
79 
80  foreach(core::Size atom_with_orbitals, rsd_type_.atoms_with_orb_index()){
81  utility::vector1<core::Size> const & orbital_indices(rsd_type_.bonded_orbitals(atom_with_orbitals));
82  foreach(core::Size orbital_index, orbital_indices){
83  Vector orb_xyz(this->build_orbital_xyz(orbital_index));
85  orbitals_.push_back(orbitals::OrbitalXYZCoords(orb_xyz, type));
86  }
87  }
88 
89 
90 
91 }
92 
93 /// @details Create a residue/rotamer of type rsd_type_in placed at the position occupied by current_rsd
94 /// Used primarily in rotamer building. The newly created Residue has the same sequence postion, chain id
95 /// and mainchain torsion angles as current_rsd. It has a ResidueType as defined by rsd_type_in. Its sidechain
96 /// chi angles are uninitialized as all 0.0 and sidechain atom coords are from ideal coords. Its backbone is aligned
97 /// with that of current_rsd.
98 /// Its residue connections and its pseudobonds must be initialized from the original residue.
100  ResidueType const & rsd_type_in,
101  Residue const & current_rsd,
102  Conformation const & conformation,
103  bool preserve_c_beta
104 ):
105  utility::pointer::ReferenceCount(),
106  rsd_type_( rsd_type_in ),
107  seqpos_( current_rsd.seqpos() ),
108  chain_( current_rsd.chain() ),
109  chi_( rsd_type_.nchi(), 0.0 ), // uninit
110  mainchain_torsions_( current_rsd.mainchain_torsions() ),
111  actcoord_( 0.0 ),
112  nonstandard_polymer_( current_rsd.nonstandard_polymer_ ),
113  connect_map_( current_rsd.connect_map_ ),
114  connections_to_residues_( current_rsd.connections_to_residues_ ),
115  pseudobonds_( current_rsd.pseudobonds_ )
116 {
117 
118 
119 
120  for ( Size i=1; i<= rsd_type_.natoms(); ++i ) {
122  }
123 
124  assert( current_rsd.mainchain_torsions().size() == rsd_type_.mainchain_atoms().size() );
125 
126  // now orient
127  place( current_rsd, conformation, preserve_c_beta );
128 
129  // Assumption: if two residue types have the same number of residue connections,
130  // then their residue connections are "the same" residue connections.
131  // This assumption works perfectly for all amino acids, except CYD.
132  //
133  // THIS REALLY NEEDS TO BE FIXED AT SOME POINT
134  //
135 
136  if ( rsd_type_in.n_residue_connections() != current_rsd.type().n_residue_connections() ) {
137  if ( ! current_rsd.pseudobonds_.empty() ) {
138  std::cerr << "Unable to handle change in the number of residue connections in the presence of pseudobonds!" <<
139  std::endl;
140  utility_exit();
141  }
142 
143  copy_residue_connections( current_rsd );
144 
145  }
146 
147  // This seems a little silly, but the update of chi's doesn't seem to occur automatically in
148  // any of the functions above.
149  for ( Size chino = 1; chino <= rsd_type_.nchi(); chino++ ) {
150  AtomIndices const & chi_atoms( rsd_type_.chi_atoms( chino ) );
151 
152  // get the current chi angle
153  Real const current_chi
154  (
155  numeric::dihedral_degrees(
156  atom( chi_atoms[1] ).xyz(),
157  atom( chi_atoms[2] ).xyz(),
158  atom( chi_atoms[3] ).xyz(),
159  atom( chi_atoms[4] ).xyz()
160  )
161  );
162  chi_[ chino ] = current_chi;
163  }
164 
165  foreach(core::Size atom_with_orbitals, rsd_type_.atoms_with_orb_index()){
166  utility::vector1<core::Size> const & orbital_indices(rsd_type_.bonded_orbitals(atom_with_orbitals));
167  foreach(core::Size orbital_index, orbital_indices){
168  Vector orb_xyz(this->build_orbital_xyz(orbital_index));
170  orbitals_.push_back(orbitals::OrbitalXYZCoords(orb_xyz, type));
171  }
172  }
173 
174 }
175 
176 
177 
178 Residue::Residue( Residue const & src )
179 :
180  utility::pointer::ReferenceCount(),
181  rsd_type_(src.rsd_type_),
182  atoms_(src.atoms_),
183  orbitals_(src.orbitals_),
184  seqpos_(src.seqpos_),
185  chain_(src.chain_),
186  chi_(src.chi_),
187  mainchain_torsions_(src.mainchain_torsions_),
188  actcoord_(src.actcoord_),
189  nonstandard_polymer_(src.nonstandard_polymer_),
190  connect_map_(src.connect_map_),
191  connections_to_residues_(src.connections_to_residues_),
192  pseudobonds_(src.pseudobonds_)
193 {
194 
195 }
196 
198 
199 
200 ///@details make a copy of this residue( allocate actual memory for it )
201 ResidueOP
203 {
204  return new Residue( *this );
205 }
206 
207 
208 Size
209 Residue::atom_type_index( Size const atomno ) const
210 {
211  return atoms_[ atomno ].type();
212 }
213 
214 Real
215 Residue::atomic_charge( int const atomno ) const
216 {
217  return rsd_type_.atom( atomno ).charge();
218 }
219 
220 Vector const &
221 Residue::xyz( Size const atm_index ) const
222 {
223  return atoms_[ atm_index ].xyz();
224 }
225 
226 Vector const &
227 Residue::xyz( std::string const & atm_name ) const
228 {
229  return atom( atm_name ).xyz();
230 }
231 
232 void
233 Residue::set_xyz( core::Size const atm_index, Vector const & xyz_in )
234 {
235  atoms_[ atm_index ].xyz( xyz_in );
236 }
237 
238 void
239 Residue::set_xyz( std::string const & atm_name, Vector const & xyz_in )
240 {
241  atom( atm_name ).xyz( xyz_in );
242 
243 }
244 
245 
246 // Return the CarbohydrateInfo object containing sugar-specific properties for this residue.
249 {
250  assert(rsd_type_.is_carbohydrate());
251  PyAssert(rsd_type_.is_carbohydrate(), "Residue::carbohydrate_info(): This residue is not a carbohydrate!");
252 
253  return rsd_type_.carbohydrate_info();
254 }
255 
256 
257 bool Residue::connections_match( Residue const & other ) const
258 {
259  if ( connect_map_.size() != other.connect_map_.size() ) return false;
260  //if ( connections_to_residues_.size() != other.connections_to_residues_.size()) return false; // duplicate data
261  if ( pseudobonds_.size() != other.pseudobonds_.size() ) return false;
262 
263  for ( Size ii = 1; ii <= connect_map_.size(); ++ii ) {
264  if ( connect_map_[ ii ] != other.connect_map_[ ii ] ) return false;
265  }
266  for ( std::map< Size, PseudoBondCollectionCOP >::const_iterator
267  iter = pseudobonds_.begin(), iter_end = pseudobonds_.end(),
268  other_iter_end = other.pseudobonds_.end();
269  iter != iter_end; ++iter ) {
270  std::map< Size, PseudoBondCollectionCOP >::const_iterator other_iter = other.pseudobonds_.find( iter->first );
271  if ( other_iter == other_iter_end ) return false;
272  if ( iter->second != other_iter->second ) return false; // pointer comparison
273  //if ( ! (*(iter->second) == *(other_iter->second) ) ) return false;
274  }
275  return true;
276 }
277 
278 bool
279 Residue::is_similar_rotamer( Residue const & other ) const
280 
281 {
282 
283  utility::vector1< Real > this_chi = chi_;
284  utility::vector1< Real > other_chi = other.chi();
285  bool match = true;
286  if (chi_.size() != other_chi.size() || rsd_type_.aa() != other.aa() || rsd_type_.name3() != other.name3() ){
287  return false;
288  }
289  else {
290  for (Size i = 1; i<= chi_.size(); i++){
291  if ( std::abs( this_chi[i] - other_chi[i]) >= 5){
292  match = false;
293  }
294  }
295  }
296  return match;
297 }
298 
299 
300 
301 void
303 {
304 
305  /// ASSUMPTION: if two residue types have the same number of residue connections,
306  // then their residue connections are "the same" residue connections.
307  // This assumption works perfectly for typical polymeric residues, but the following
308  // assignment would produce unexpected behavior: take a CYD residue i that's disulfide
309  // partner is residue j and replace it with a catalytic glutamate GLC that's bound
310  // to ligand residue k. Connection #3 for cyd will be confused with connection #3 on
311  // GLC. Such weird cases will have to be explicitly detected and handled.
312  //
313  // THIS REALLY NEEDS TO BE FIXED AT SOME POINT
314  //
315 
316  if ( type().n_residue_connections() == src_rsd.type().n_residue_connections() ) {
317 
318  connect_map_ = src_rsd.connect_map_;
320  pseudobonds_ = src_rsd.pseudobonds_;
321 
322  } else {
323 
324  if ( ! src_rsd.pseudobonds_.empty() ) {
325  std::cerr << "Unable to handle change in the number of residue connections in the presence of pseudobonds!" <<
326  std::endl;
327  utility_exit();
328  }
329 
330  connect_map_.clear();
331  connections_to_residues_.clear();
332  pseudobonds_.clear();
333 
335 
336  // Find correspondence between src_rsd's connection atoms and atoms on *this.
337  for ( Size ii = 1; ii <= src_rsd.type().n_residue_connections(); ++ii ) {
338  Size const ii_connatom = src_rsd.type().residue_connection( ii ).atomno();
339  if ( has( src_rsd.atom_name( ii_connatom ) )) {
340 
341  Size const this_connatom = atom_index( src_rsd.atom_name( ii_connatom ));
342 
343  /// Simple case: this atom on both residues is connected to only a single other residue.
344  if ( type().n_residue_connections_for_atom( this_connatom ) == 1 &&
345  src_rsd.type().n_residue_connections_for_atom( ii_connatom ) == 1 ) {
346  Size const this_connid = type().residue_connection_id_for_atom( this_connatom );
347 
348  // note that we might have the same atom name, but in src_rsd it's connected to something
349  // and in our rsd it's not. So check for that now:
350  if ( this_connid ) {
352  this_connid,
353  src_rsd.connect_map( ii ).resid(),
354  src_rsd.connect_map( ii ).connid() );
355 #ifndef BOINC
356  if ( this_connid != ii ) {
357  TR.Error << "WARNING: Residue connection id changed when creating a new residue at seqpos " << seqpos() <<
358  std::endl;
359  TR.Error << "WARNING: ResConnID info stored on residue " << src_rsd.connect_map( ii ).resid();
360  TR.Error << " is now out of date!" << std::endl;
361  }
362 #endif
363  }
364  } else {
365  /// Preserve residue connections in their input order.
366  /// Figure out which residue connection for this atom on the source residue we're looking at.
367  /// This *could* lead to weird behavior if you were to remove the middle of three residue connections
368  /// for a single atom; e.g. if you had a Zn coordinated to three residues and wanted to replace it
369  /// with a Zn coordinated to two residues -- then the question should be, which two residue connections
370  /// from the original Zn should you copy. At that point, in fact, you would have a weird situation
371  /// where the residues coordinating the Zn would have out-of-date information about which residue connection
372  /// on Zn they're coordinated to.
373  /// The logic for altering residue connections in any way besides first building up a molecule
374  /// is terribly incomplete.
375  /// Fortunately, once a molecule is built and its residue connection topology is finalized, then all
376  /// downstream operations are a sinch.
377  Size which_connection_on_this_atom( 0 );
378  for ( Size jj = 1; jj <= src_rsd.type().residue_connections_for_atom( ii_connatom ).size(); ++jj ) {
379  if ( src_rsd.type().residue_connections_for_atom( ii_connatom )[ jj ] == ii ) {
380  which_connection_on_this_atom = jj;
381  break;
382  }
383  }
384  if ( which_connection_on_this_atom == 0 ) {
385  utility_exit_with_message("CATASTROPHIC ERROR in Residue::copy_residue_connections. ResidueType connection map integrity error");
386  }
387  if ( which_connection_on_this_atom <= type().residue_connections_for_atom( this_connatom ).size() ) {
389  type().residue_connections_for_atom( this_connatom )[ which_connection_on_this_atom ],
390  src_rsd.connect_map( ii ).resid(),
391  src_rsd.connect_map( ii ).connid() );
392  } else {
393  /// Warn, we've just dropped a residue connection. Was that intentional?
394  /// Actually -- common occurrence when converting a mid-residue to a terminal residue.
395  /// std::cerr << "WARNING: Not copying residue connection " << ii << " from " << src_rsd.name()
396  /// << " to " << name() << " at position " << seqpos() << std::endl;
397  }
398  }
399  }
400  }
401  }
402 }
403 
404 
405 
406 /// @details loop over all actcoord atoms for this ResidueType,
407 /// average their actual positions in this residue.
408 void
410 {
411  rsd_type_.update_actcoord( *this );
412 }
413 
414 void Residue::select_orient_atoms(Size & center, Size & nbr1, Size & nbr2) const
415 {
416  rsd_type_.select_orient_atoms(center, nbr1, nbr2);
417 }
418 
419 /// @details Helper function: selects atoms to orient on and transforms all of my atoms to
420 /// orient onto another residue. Used by place(). Need to think a bit more about the
421 /// restrictions on src...
422 ///
423 void
425 {
426  using kinematics::Stub;
427 
428  Size center, nbr1, nbr2;
429  select_orient_atoms( center, nbr1, nbr2 );
430  // std::cout << " CENTER " << atom_name( center ) << " NBR1 " << atom_name( nbr1 ) << " NBR2 " << atom_name( nbr2 ) << std::endl;
431 
432  assert( center && nbr1 && nbr2 );
433  // this will fail if src doesnt have these atoms -- think more about this!
434  //
436  src,
437  center,
438  nbr1,
439  nbr2,
440  src.atom_index( rsd_type_.atom_name( center )),
441  src.atom_index( rsd_type_.atom_name( nbr1 )),
442  src.atom_index( rsd_type_.atom_name( nbr2 )));
443 
444 } // orient_onto_residue( Residue const & src)
445 
446 
447 void
449  Residue const & src,
450  utility::vector1< std::pair< std::string, std::string > > const & atom_pairs
451 )
452 {
453  using kinematics::Stub;
454 
455  // Verify that three atom pairs have been provided
456  if( atom_pairs.size() != 3 ){
457  utility_exit_with_message( "Three atom pairs must be provided in Residue::orient_onto_residue.");
458  }
459 
461  src,
462  atom_index( atom_pairs[1].second ),
463  atom_index( atom_pairs[2].second ),
464  atom_index( atom_pairs[3].second ),
465  src.atom_index( atom_pairs[1].first ),
466  src.atom_index( atom_pairs[2].first ),
467  src.atom_index( atom_pairs[3].first ));
468 } //orient_onto_residue( Residue src, atom_pairs )
469 
471  Residue const & src,
472  Size center, Size nbr1, Size nbr2,
473  Size src_center, Size src_nbr1, Size src_nbr2)
474 {
475  using kinematics::Stub;
476 
477  //NOTE: the implementation of this function might change in the future
478  //from strictly superimposing on three atoms to superposition along the lines
479  //of what is in numeric::model_quality::findUU()
480 
481  // explanation for taking the midpoint...?
482  Vector const
483  rot_midpoint ( 0.5 * ( atom( nbr1 ).xyz() + atom( nbr2 ).xyz() ) ),
484  src_midpoint ( 0.5 * ( src.atom( src_nbr1 ).xyz() + src.atom( src_nbr2 ).xyz() ) );
485 
486  Stub rot_stub( atom( center ).xyz(),
487  rot_midpoint,
488  atom( nbr1 ).xyz() );
489 
490  Stub src_stub( src.atom( src_center ).xyz(),
491  src_midpoint,
492  src.atom( src_nbr1 ).xyz() );
493 
494  // this could be made faster by getting the composite rotation and translation
495 
496  for ( Size i=1; i<= rsd_type_.natoms(); ++i ) {
497  Vector const old_xyz( atoms()[i].xyz() );
498  Vector const new_xyz( src_stub.local2global( rot_stub.global2local( old_xyz ) ) );
499  atoms()[i].xyz( new_xyz );
500  }
501 }
502 
503 
504 /// @details place/orient "this" Residue onto "src" Residue by backbone superimposition
505 /// Since rotamer is represented by Residue in mini now, this function is mainly used to place a rotamer
506 /// onto the backbone of "src" residue. Meanwhile, it can also be used to add sidechains to one pose/conformation
507 /// from another pose/conformation.\n
508 /// current logic: find backbone atom with bonded neighbors in sidechain,
509 /// and which is the base_atom of those neighbors. Take that backbone atom
510 /// and find two neighboring backbone heavyatoms. The three atoms to be superimposed with
511 /// are the center/base atom, the backbone neighbor 1 and the mid-point of backbone neighbor 1 and 2. This way,
512 /// we can avoid large perturbation on backbone neighbor 2 after superimpostion if the two sets of backbone atoms
513 /// are not perfectly superimposable ( e.g., with slightly different backbone geometry).\n
514 /// after all atoms in "this" Residue is oriented, copy any corresponding backbone atom coords from "src" and if
515 /// there are any backbone atom missing from "src" (for example, src is a proline with HN missing), build them using
516 /// ideal internal coords (that is why "conformation" is needed as an input argument).
517 /// For residues without any backbone atoms (e.g. some ligands), center on nbr_atom instead
518 /// and two of its bonded neighbors (preferring heavy atoms to hydrogens if possible).
519 
520 void
521 Residue::place( Residue const & src, Conformation const & conformation, bool preserve_c_beta )
522 {
523  using kinematics::Stub;
524  Size first_scatom( rsd_type_.first_sidechain_atom() );
525  if ( first_scatom >= 1 && first_scatom <= rsd_type_.nheavyatoms() ) {
526  // not all backbone -- need to do some orienting
527  orient_onto_residue( src );
528  } // does the residue have any sidechain atoms?
529 
530  // now copy the backbone atoms
531  //
532  utility::vector1< bool > missing( natoms(), false );
533  bool any_missing( false );
534  for ( Size i=1; i<= natoms(); ++i ) {
535 
536  //The O2* is a special case for RNA, because it is a "sidechain" atom that
537  // branches off the backbone separately from the base. This could be
538  // coded more robustly by modifying orient_onto_residue() properly.
539 
540  if ( !rsd_type_.atom_is_backbone(i) && !(rsd_type_.atom_name(i) == " O2*") && !(rsd_type_.atom_name(i) == "2HO*") ) continue;
541  if ( src.has( rsd_type_.atom_name(i) ) ) {
542  atoms()[i].xyz( src.atom( src.atom_index( rsd_type_.atom_name(i) ) ).xyz() );
543  } else {
544  missing[i] = true;
545  any_missing = true;
546  }
547  }
548 
549  if ( any_missing ) fill_missing_atoms( missing, conformation );
550 
551  if ( preserve_c_beta ) {
552  // after superposition, adjust the sidechain atoms by aligning the CA-CB bond
553  // std::cout << "preserving c-beta... " << std::endl;
554  std::string root("CA"), mobile_new("CB"), mobile_src("CB");
555 
556  if ( is_RNA() ){
557  root = " C1*";
558  mobile_new = atom_name( chi_atoms( 1 )[ 3 ] ); //First atom in base...
559  mobile_src = src.atom_name( src.chi_atoms( 1 )[ 3 ] ); //First atom in base...
560  }
561 
562  // only try this when both the src and the new residue types contain both atom types
563  if ( type().has( root ) && type().has( mobile_new ) &&
564  src.type().has( root ) && src.type().has( mobile_src ) ) {
565  assert( xyz( root ) == src.xyz( root ) ); // roots should be aligned by now
566  // common 'pseudoatom' vector, perpendicular to the plane defined by the two bonds
567  Vector const pseudoatom(
568  cross( xyz( mobile_new ) - xyz( root ), src.xyz( mobile_src ) - src.xyz( root ) ) + xyz( root )
569  );
570  Stub new_stub( xyz( root ), pseudoatom, xyz( mobile_new ) ),
571  src_stub( src.xyz( root ), pseudoatom, src.xyz( mobile_src ) );
572  // adjust sidechain coordinates by superposition of the bond 'stubs'
573  // would need a smarter way to propagate through all child atoms of 'root' to generalize this
574  for ( Size atom_index(1); atom_index <= type().natoms(); ++atom_index ) {
575  if ( type().atom_is_backbone( atom_index ) ) continue;
576  //special case for RNA
577  if ( type().atom_name( atom_index ) == " O2*" || type().atom_name( atom_index ) == "2HO*" ) continue;
578  Vector const old_xyz( atoms()[ atom_index ].xyz() );
579  Vector const new_xyz( src_stub.local2global( new_stub.global2local( old_xyz ) ) );
580  atoms()[ atom_index ].xyz( new_xyz );
581  }
582  }
583  }
584 
585 }
586 
587 
588 /////////////////////////////////////////////////////////////////////////////
589 /// @details
590 /// this uses ideal internal coords to build any missing atom from its three
591 /// stub atoms. If any of the stub atoms are missing, build them first.
592 /// Unable to build a missing atom whose stub atoms are from non-existing
593 /// polymer connection and its input bogus value will not be changed.
594 ///
595 void
597  utility::vector1< bool > missing, // make local copy
598  Conformation const & conformation
599 )
600 {
601  bool still_missing( true );
602  while ( still_missing ) {
603  still_missing = false;
604  for ( Size i=1; i<= natoms(); ++i ) {
605  if ( missing[i] ) {
606  chemical::AtomICoor const & ic( icoor(i) );
607  if ( (seqpos_ == 1 && ic.depends_on_polymer_lower()) ||
608  (Size(seqpos_) == conformation.size() && ic.depends_on_polymer_upper()) ) {
609  missing[i] = false;
610  TR.Warning << "[ WARNING ] missing an atom that depends on a nonexistent polymer connection! " <<
611  seqpos_ << ' ' << atom_name(i) << std::endl << " --> using existing bogus coordinates!" << std::endl;
612  continue;
613  }
614 
615  still_missing = true;
616 
617  // check to see if any of our stub atoms are missing:
618  bool stub_atoms_missing( false );
619  for ( Size j=1; j<= 3; ++j ) {
620  chemical::ICoorAtomID const & id( ic.stub_atom(j) );
621  if ( id.type() == chemical::ICoorAtomID::INTERNAL && missing[ id.atomno() ] ) {
622  stub_atoms_missing = true;
623  if ( id.atomno() == i ) {
624  TR.Error << "[ ERROR ] missing atom " << i << " (" << atom_name(i) << ") in " << type().name() << " is its own stub" << std::endl;
625  utility_exit_with_message("Endless loop in fill_missing_atoms()");
626  }
627  break;
628  }
629  }
630 
631  if ( !stub_atoms_missing ) {
632  // no stub atoms missing: build our ideal coordinates
633  missing[i] = false;
634  //std::cout << "Residue::fill_missing_atoms: rebuild backbone atom: " << name() << ' ' <<
635  // atom_name(i) << std::endl;
636  set_xyz( i, build_atom_ideal( i, conformation ) );
637  }
638  }
639  }
640  }
641 
642 
643 }
644 
645 
646 
647 void
649 {
650  for ( Size ii = 1; ii <= connect_map_.size(); ++ii ) {
651  //connect_map_[ ii ].resid( 0 );
652  //connect_map_[ ii ].connid( 0 );
653  connect_map_[ ii ].mark_incomplete();
654  }
655  connections_to_residues_.clear();
656  pseudobonds_.clear();
657  nonstandard_polymer_ = false;
658 }
659 
660 void
662 {
664  this->connect_map_ = src.connect_map_;
666  this->pseudobonds_ = src.pseudobonds_;
667 }
668 
669 
670 bool
672 {
673  for ( Size ii = 1; ii <= connect_map_.size(); ++ii ) {
674  if ( connection_incomplete( ii ) ) return true;
675  }
676  return false;
677 }
678 
679 
680 /// @detailed
681 /// determine whether an atom is completely connected to all possible bonded partners
682 bool
684  Size const atomno
685 ) const
686 {
687  Size const num_connections(n_residue_connections());
688 
689  for (Size i = 1; i <= num_connections; ++i) {
690  if (residue_connect_atom_index(i) == atomno && connection_incomplete(i)) return true;
691  }
692 
693  return false;
694 }
695 
696 
697 bool
699 {
700  return connect_map_[ resconnid ].incomplete();
701 }
702 
703 
704 /// @details
705 /// set a connection to this residue by adding its partner's residue number
706 void
708  Size const resconn_index, // ie, our connid
709  Size const otherres,
710  Size const other_connid
711 )
712 {
713  connect_map_[ resconn_index ].resid(otherres);
714  connect_map_[ resconn_index ].connid( other_connid );
716 // utility::vector1< Size > newlist;
717 // if ( connections_to_residues_.find( otherres ) != connections_to_residues_.end() ) {
718 // newlist = connections_to_residues_[ otherres ];
719 // }
720 // if ( newlist.size() != 0 ) {
721 // for ( Size ii = 1; ii <= newlist.size(); ++ii ) {
722 // if ( newlist[ ii ] == resconn_index ) {
723 // //std::cout << "Setting residue connection partner on residue " << seqpos_ << " to residue " << otherres << " twice!" << std::endl;
724 // break;
725 // }
726 // else if ( ii == newlist.size() ) {
727 // newlist.push_back( resconn_index );
728 // connections_to_residues_[ otherres ] = newlist;
729 // break;
730 // }
731 // }
732 // } else {
733 // newlist.push_back( resconn_index );
734 // connections_to_residues_[ otherres ] = newlist;
735 // }
737 }
738 
739 
740 /// @details Private function to keep the connections_to_residues_ array up to date
741 /// @note This could be made faster -- connections_to_residues_ is a std::map< > so operator[] calls are slow
742 
743 void
745 {
746  connections_to_residues_.clear();
747  for ( Size i=1, i_end = n_residue_connections(); i<= i_end; ++i ) {
748  Size const other_resid( connect_map_[ i ].resid() );
749  connections_to_residues_[ other_resid ].push_back( i );
750  }
751 }
752 
753 /// @details update sequence numbers for this residue and
754 /// the numbers stored about its connections.
755 /// called by our owning conformation when the
756 /// sequence numbers are remapped
757 void
759 {
760  seqpos_ = old2new[ seqpos_ ];
761  //std::map< Size, utility::vector1< Size > > connections_to_residues_copy( connections_to_residues_ );
762 
763  //connections_to_residues_.clear();
764  for ( Size i=1, ie= connect_map_.size(); i<= ie; ++i ) {
765  Size const old_resid = connect_map_[ i ].resid();
766  if ( old_resid == 0 ) continue;
767 
768  Size const new_resid = old2new[ old_resid ];
769 
770  connect_map_[i].resid( new_resid );
771 
772  // If the partner disappears, partner atomid should be zero too. Otherwise if you add and
773  // then delete a residue to a pose, a neighboring residue does not stay invariant.
774  if( new_resid == 0 ) connect_map_[i].connid( 0 );
775 
776 
777 // if ( new_resid ) {
778 // connections_to_residues_[ new_resid ] = connections_to_residues_copy[ old_resid ];
779 // }
780  }
782  if ( ! pseudobonds_.empty() ) {
783  std::map< Size, PseudoBondCollectionCOP > copy_pseudobonds( pseudobonds_ );
784  pseudobonds_.clear();
785  for ( std::map< Size, PseudoBondCollectionCOP >::const_iterator
786  pb_iter = copy_pseudobonds.begin(),
787  pb_iter_end = copy_pseudobonds.end();
788  pb_iter != pb_iter_end; ++pb_iter ) {
789  Size old_neighbor_resid = pb_iter->first;
790  Size new_neighbor_resid = old2new[ old_neighbor_resid ];
791  if ( ! new_neighbor_resid ) continue;
792  pseudobonds_[ new_neighbor_resid ] = pb_iter->second->clone_with_new_sequence_numbering( old2new );
793  }
794  }
795 
797 }
798 
799 Distance
801  conformation::Conformation const & conf,
802  Size const resconn_index,
803  Vector const matchpoint
804 ) const
805 {
806  Vector ipos = type().residue_connection( resconn_index ).icoor().build( *this, conf );
807  //std::cout << "ipos for " << name() << "'s connection atom " << resconn_index;
808  //std::cout << ": ( " << ipos.x() << ", " << ipos.y() << ", " << ipos.z() << ")" << std::endl;
809  return ipos.distance( matchpoint );
810 }
811 
812 
813 /// @details first check if it is polymer upper or lower connected to the other residue.
814 /// then check if it is boned to the other residue through non-polymer connection.
815 bool
816 Residue::is_bonded( Residue const & other ) const
817 {
818  // trying this simpler strategy -- does not require that we keep chain id's in sync with chemical
819  // connectivity
820  // APL says shouldn't be much slower
821  return ( connections_to_residues_.find( other.seqpos() ) != connections_to_residues_.end() );
822 // if ( is_polymer() && ! nonstandard_polymer_ ) {
823 // if ( polymeric_sequence_distance( other ) == 1 ) {
824 // // confirm that termini status is consistent with sequence_distance, which depends on chain
825 // assert( ( other.seqpos() == seqpos() + 1 && !is_upper_terminus() ) ||
826 // ( other.seqpos() == seqpos() - 1 && !is_lower_terminus() ) );
827 // return true;
828 // } else if ( rsd_type_.n_non_polymeric_residue_connections() == 0 ) {
829 // return false; // generic case
830 // }
831 // }
832 // return ( connections_to_residues_.find( Size(other.seqpos()) ) != connections_to_residues_.end() );
833 }
834 
835 bool
836 Residue::is_bonded( Size const other_index ) const
837 {
838  return ( connections_to_residues_.find( other_index ) != connections_to_residues_.end() );
839 }
840 
841 /// @details Am I polymer bonded to other.seqpos()?
842 bool
843 Residue::is_polymer_bonded( Residue const & other ) const
844 {
845  return is_polymer_bonded( other.seqpos() );
846 }
847 
848 /// @details Am I polymer bonded to other_index?
849 bool
850 Residue::is_polymer_bonded( Size const other_index ) const
851 {
852  if ( rsd_type_.is_polymer() ) {
853  Size const lower_id( rsd_type_.lower_connect_id() ), upper_id( rsd_type_.upper_connect_id() );
854  return ( ( lower_id && residue_connection_partner( lower_id ) == other_index ) ||
855  ( upper_id && residue_connection_partner( upper_id ) == other_index ) );
856  } else return false;
857 }
858 
859 /// @brief Returns the atom-index of my atom which is connected to the other residue
860 /// @details so long as there is only a single connection to other... if there are multiple
861 /// connections this will fail. If there are no connections this will fail.
862 /// This is a convenience function that can fail; be careful!
863 /// Fails if I'm not bonded to the other residue.
864 /// @note not well defined if multiple connections to another residue -- need more general function
865 Size
866 Residue::connect_atom( Residue const & other ) const
867 {
868  Size const other_seqpos( other.seqpos() );
869  if ( is_polymer() && ! nonstandard_polymer_ ) {
870  if ( other_seqpos == Size(seqpos_) + 1 && !is_upper_terminus() ) {
871  return upper_connect_atom();
872  } else if ( other_seqpos == Size(seqpos_) - 1 && !is_lower_terminus() ) {
873  return lower_connect_atom();
874  }
875  }
876  if ( connections_to_residues_.find( Size( other.seqpos()) ) != connections_to_residues_.end() ) {
877  return rsd_type_.residue_connection( connections_to_residues_.find( Size( other_seqpos) )->second[ 1 ] ).atomno();
878  }
879 
880  utility_exit_with_message( "Residue::conect_atom: I'm not bonded to that other residue!!");
881  return 0;
882 }
883 
886 {
887  std::map< Size, PseudoBondCollectionCOP >::const_iterator iter( pseudobonds_.find( resid ) );
888  if ( iter != pseudobonds_.end() ) {
889  return iter->second;
890  }
891  return 0;
892 }
893 
894 void
896 {
897  pseudobonds_[ resid ] = pbs;
898 }
899 
900 
901 
902 
903 /// @details determine how many atoms n the residue and adjacent residues are bonded to the given atom
904 /// (by default, intraresidue virtual atoms are excluded)
905 Size
907  core::Size const atomno,
908  bool virt // = false
909 ) const
910 {
911  Size num_neighbors(0);
912 
913  chemical::AtomIndices const & intrares_atomnos(bonded_neighbor(atomno));
914  for (Size i = 1; i <= intrares_atomnos.size(); ++i) {
915  if (virt || ! is_virtual(intrares_atomnos[i]) ) ++num_neighbors;
916  }
917 
918  Size const num_connections(n_residue_connections());
919 
920  for (Size i = 1; i <= num_connections; ++i) {
921  // this doesn't check the other residue to see if it is connected to a virtual atom
922  if (residue_connect_atom_index(i) == atomno && ! connection_incomplete(i)) ++num_neighbors;
923  }
924 
925  return num_neighbors;
926 }
927 
928 
929 ///fpd bondlength analog to set_chi
930 /// like set_chi, assumes changes propagate to atomtree
931 /// keyed off of chi#, so we only allow distances corresponding to chi angles to refine
932 /// distance corresponds to the distance between atoms 3 and 4 defining the chi
933 /// chino==0 ==> CA-CB distance, which allows us to refine ALA CB position for example
934 void
935 Residue::set_d( int const chino, Real const setting ) {
936  int const effchi = (chino==0)? 1 : 0;
937  int const baseatom = (chino==0)? 2 : 3;
938 
939  AtomIndices const & chi_atoms( rsd_type_.chi_atoms( effchi ) );
940 
941  // get the current d
942  Real const current_d( ( atom(chi_atoms[baseatom+1]).xyz() - atom(chi_atoms[baseatom]).xyz() ).length() );
943 
944  assert( rsd_type_.atom_base( chi_atoms[baseatom] ) == chi_atoms[baseatom] );
946 
947  Vector const axis (( atom(chi_atoms[baseatom+1]).xyz() - atom(chi_atoms[baseatom]).xyz() ).normalized());
948  Vector const v( (setting-current_d)*axis );
949 
950  // apply the transform to all "downstream" atoms
951  apply_transform_downstream( chi_atoms[baseatom+1], R, v );
952 
953  ASSERT_ONLY(Real const new_d( ( atom(chi_atoms[baseatom+1]).xyz() - atom(chi_atoms[baseatom]).xyz() ).length() );)
954  assert( std::abs( new_d - setting ) < 1e-2 );
955 
956  update_actcoord();//ek added 4/28/10
957 }
958 
959 
960 ///fpd bondangle analog to set_chi (see above for details)
961 void
962 Residue::set_theta( int const chino, Real const setting ) {
963  int const effchi = (chino==0)? 1 : 0;
964  int const baseatom = (chino==0)? 2 : 3;
965 
966  AtomIndices const & chi_atoms( rsd_type_.chi_atoms( effchi ) );
967 
968  // get the current chi angle
969  Real const current_theta
970  ( numeric::angle_degrees( atom( chi_atoms[baseatom-1] ).xyz(), atom( chi_atoms[baseatom] ).xyz(), atom( chi_atoms[baseatom+1] ).xyz() ) );
971 
972  Vector const v12( atom(chi_atoms[baseatom]).xyz() - atom(chi_atoms[baseatom-1]).xyz() );
973  Vector const v23( atom(chi_atoms[baseatom+1]).xyz() - atom(chi_atoms[baseatom]).xyz() );
974  Vector const axis (v12.cross(v23).normalized());
975 
976  // debug ordering of chi atoms
977  assert( ( rsd_type_.atom_base( chi_atoms[baseatom] ) == chi_atoms[baseatom-1] ) &&
978  ( rsd_type_.atom_base( chi_atoms[baseatom+1] ) == chi_atoms[baseatom] ) );
979 
981  ( numeric::rotation_matrix_degrees( axis, - setting + current_theta ) );
982 
983  Vector const chi_atom2_xyz( atom( chi_atoms[baseatom] ).xyz() );
984  Vector const v( chi_atom2_xyz - R * chi_atom2_xyz );
985 
986  // apply the transform to all "downstream" atoms
987  apply_transform_downstream( chi_atoms[baseatom], R, v );
988 
989  ASSERT_ONLY(Real const new_th(numeric::angle_degrees(
990  atom( chi_atoms[baseatom-1] ).xyz(), atom( chi_atoms[baseatom] ).xyz(), atom( chi_atoms[baseatom+1] ).xyz() )); )
991  assert( std::abs( basic::subtract_degree_angles( new_th, setting ) ) < 1e-2 );
992 
993  update_actcoord();
994 }
995 
996 
997 
998 
999 /////////////////////////////////////////////////////////////////////////////
1000 /// @details this assumes that change propagates according to the information from
1001 /// atom_base array, not from atom tree. So be sure not to get into an
1002 /// endless loop.
1003 ///
1004 void
1005 Residue::set_chi( int const chino, Real const setting )
1006 {
1007 
1008 //#ifdef NDEBUG
1009 // bool const debug( false );
1010 //#else
1011 // bool const debug( true );
1012 //#endif
1013 
1014  chi_[ chino ] = setting;
1015 
1016  AtomIndices const & chi_atoms( rsd_type_.chi_atoms( chino ) );
1017 
1018  // get the current chi angle
1019  Real const current_chi
1020  ( numeric::dihedral_degrees( atom( chi_atoms[1] ).xyz(),
1021  atom( chi_atoms[2] ).xyz(),
1022  atom( chi_atoms[3] ).xyz(),
1023  atom( chi_atoms[4] ).xyz() ) );
1024 
1025  Vector const axis
1026  (( atom(chi_atoms[3]).xyz() - atom(chi_atoms[2]).xyz() ).normalized());
1027  // debug ordering of chi atoms
1028  assert( ( rsd_type_.atom_base( chi_atoms[3] ) == chi_atoms[2] ) &&
1029  ( rsd_type_.atom_base( chi_atoms[4] ) == chi_atoms[3] ) );
1030 
1032  ( numeric::rotation_matrix_degrees( axis, setting - current_chi ) );
1033 
1034  Vector const chi_atom3_xyz( atom( chi_atoms[3] ).xyz() );
1035  Vector const v( chi_atom3_xyz - R * chi_atom3_xyz );
1036 
1037  // apply the transform to all "downstream" atoms
1039 
1040 
1041  ASSERT_ONLY(Real const new_chi
1042  ( numeric::dihedral_degrees( atom( chi_atoms[1] ).xyz(),
1043  atom( chi_atoms[2] ).xyz(),
1044  atom( chi_atoms[3] ).xyz(),
1045  atom( chi_atoms[4] ).xyz() ) );)
1046  assert( std::abs( basic::subtract_degree_angles( new_chi, setting ) ) <
1047  1e-2 );
1048 
1049  update_actcoord();//ek added 4/28/10
1050 
1051 }
1052 
1053 
1054 void
1056 {
1057  // This works for now, but there's probably a faster implementation which only runs the coordinate update once.
1058  for(Size i=1; i<= nchi(); i++) {
1059  set_chi( i, chis[i] );
1060  }
1061 }
1062 
1063 
1064 /////////////////////////////////////////////////////////////////////////////
1065 /// @details xyz --> R * xyz + v \n
1066 /// this uses information from atom_base array to transform all the downstream atoms
1067 /// along the sidechain recursively. it assumes that the atom_base array will not get
1068 /// us into any infinite loops!
1069 ///
1070 /// @note this is not for general atom tree folding. only used in set_chi in which
1071 /// changes for a chi angle is fast propagated within one residue and not to invoke
1072 /// folding the whole atom tree.
1073 
1074 void
1076  int const atomno,
1077  numeric::xyzMatrix< Real > const & R,
1078  Vector const & v
1079 )
1080 {
1081  // transform my coordinates:: xyz -> R * xyz + v
1082  //
1083  atom( atomno ).xyz( R * atom( atomno ).xyz() + v );
1084 
1085  // now apply recursively to my downstream nbrs:
1086  AtomIndices const & nbrs( rsd_type_.bonded_neighbor( atomno ) );
1087  int const my_atom_base( rsd_type_.atom_base( atomno ) );
1088  for ( Size i=1; i<= nbrs.size(); ++i ) {
1089  int const nbr( nbrs[i] );
1090  int const nbr_base( rsd_type_.atom_base( nbr ) );
1091  if ( nbr_base == atomno ) {
1092  if ( my_atom_base != nbr ) {
1093  apply_transform_downstream( nbr, R, v );
1094  } else {
1095  TR.Warning << "DANGER: almost got stuck in infinite loop!" << std::endl;
1096  }
1097  }
1098  }
1099 }
1100 
1101 void
1104  Vector v
1105 ) {
1106  for ( Size atom_idx = 1; atom_idx <= type().natoms(); ++atom_idx ) {
1107  set_xyz( atom_idx, R * xyz(atom_idx) + v );
1108  }
1109 }
1110 
1111 
1112 void
1114 {
1115  if ( is_polymer() ) {
1116  if ( ! is_upper_terminus() &&
1117  ( type().upper_connect_id() == 0 ||
1118  connect_map_[ type().upper_connect_id() ].incomplete() ||
1119  connect_map_[ type().upper_connect_id() ].resid() != seqpos() + Size( 1 )) ) {
1120  nonstandard_polymer_ = true;
1121  return;
1122  }
1123  if ( ! is_lower_terminus() &&
1124  ( type().lower_connect_id() == 0 ||
1125  connect_map_[ type().lower_connect_id() ].incomplete() ||
1126  connect_map_[ type().lower_connect_id() ].resid() != seqpos() - Size( 1 )) ) {
1127  nonstandard_polymer_ = true;
1128  return;
1129  }
1130  }
1131  nonstandard_polymer_ = false;
1132 }
1133 
1134 ////////////////////////////////////////////////////////////////////////////////
1135 //ja
1136 std::ostream & operator << ( std::ostream & os, Residue const & res )
1137 {
1138  os << res.name() << ' ' << res.seqpos() << ": \n";
1139  for ( Size j=1; j<=res.natoms(); ++j ) {
1140  Atom const & atom ( res.atom(j) );
1141  os << res.atom_name(j) << ": ";
1142  os << atom.xyz()(1) << ' ' << atom.xyz()(2) << ' '<< atom.xyz()(3) << std::endl;
1143  }
1144  if (res.is_carbohydrate()) {
1145  os << std::endl;
1146  res.carbohydrate_info()->show(os);
1147  }
1148  return os;
1149 }
1150 
1151 std::ostream & operator << ( std::ostream & os, Atom const & atom )
1152 {
1153  os << "Atom type:" << atom.type() << " xyz:" << atom.xyz().x() << ' ' << atom.xyz().y() << ' ' << atom.xyz().z();
1154  return os;
1155 }
1156 
1157 ////////////////////////////////////////////////
1158 bool
1159 Residue::is_virtual( Size const & atomno ) const
1160 {
1161  return rsd_type_.atom_type( atomno ).is_virtual();
1162 }
1163 
1164 #ifdef USEBOOSTSERIALIZE
1165 // this function takes the old res, clones it rotamer library by applying it to the new res
1166 // and adds it to the rotamerlibrary singleton
1167 void add_cloned_ligand_rotamer_library( core::chemical::ResidueType & new_res, core::chemical::ResidueType const & base_res ) {
1168  using namespace core::pack::dunbrack;
1169 
1172  static_cast< SingleLigandRotamerLibrary const * >
1173  ( RotamerLibrary::get_instance().get_rsd_library( base_res )() ));
1174  if( old_lrots != 0 ) {
1175  utility::vector1< ResidueOP > new_rotamers;
1176  utility::vector1< ResidueOP > const old_rotamers = old_lrots->get_rotamers();
1177  for( utility::vector1< ResidueOP>::const_iterator oldrot_it = old_rotamers.begin(); oldrot_it != old_rotamers.end(); ++oldrot_it){
1178  ResidueOP new_rot_res = new Residue( new_res, true);
1179  for( core::Size at_ct = 1; at_ct <= new_rot_res->natoms(); at_ct++){
1180  if( !(*oldrot_it)->has( new_rot_res->atom_name( at_ct ) ) ){
1181  std::cerr << "Unexpected ERROR: when regenerating ligand rotamer library (for covalent constraints), one atom wasn't found in a template rotamer." << std::endl;
1182  utility::exit( EXIT_FAILURE, __FILE__, __LINE__);
1183  }
1184  else{
1185  new_rot_res->set_xyz( at_ct, (*oldrot_it)->xyz( new_rot_res->atom_name( at_ct ) ) );
1186  }
1187  }
1188  new_rot_res->chi( (*oldrot_it)->chi() );
1189  new_rotamers.push_back( new_rot_res );
1190  }
1191  new_lrots->set_reference_energy( old_lrots->get_reference_energy() );
1192  new_lrots->set_rotamers( new_rotamers );
1193  } // no fallback if there isnt a reference rotamer library
1194  RotamerLibrary::get_instance().add_residue_library( new_res, new_lrots );
1195 }
1196 #endif
1197 
1198 } // conformation
1199 } // core
1200