Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
SymmetricConformation.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 // This file is part of the Rosetta software suite and is made available under license.
5 // The Rosetta software is developed by the contributing members of the Rosetta Commons consortium.
6 // (C) 199x-2009 Rosetta Commons participating institutions and developers.
7 // For more information, see http://www.rosettacommons.org/.
8 
9 /// @file core/conformation/symmetry/SymmetricConformation.hh
10 /// @brief symmetry conformation container.
11 // Contains overloaded functions needed to
12 // make changes in conformation symmetric
13 /// @author Phil Bradley, Ingemar Andre
14 
15 // Unit headers
19 #include <basic/options/option.hh>
20 #include <basic/options/keys/in.OptionKeys.gen.hh>
21 
22 #include <basic/Tracer.hh>
23 
24 #include <core/id/TorsionID.hh>
25 #include <utility/vector1.hh>
26 
27 //Auto Headers
29 
39 
40 namespace core {
41 namespace conformation {
42 namespace symmetry {
43 
44 static basic::Tracer TR("core.conformation.symmetry.Conformation");
45 
46 /// @brief Default CTOR
48  Conformation(),
49  symm_info_()
50 {
51  Tsymm_.clear();
52 }
53 
54  /// @brief Default CTOR
56  Conformation( conf ),
57  symm_info_( symm_info.clone() )
58 {
59  Tsymm_.clear();
60 }
61 
62 /// @brief copy constructor
64  Conformation( src ),
65  symm_info_( src.symm_info_->clone() ),
66  Tsymm_( src.Tsymm_ )
67 {}
68 
69 /// @brief operator=
72 {
73  // will this work?
75  symm_info_ = src.symm_info_->clone();
76  Tsymm_ = src.Tsymm_;
77  return *this;
78 }
79 
80 
81 ///@details make a copy of this conformation( allocate actual memory for it )
84 {
85  return new SymmetricConformation( *this );
86 }
87 
88 bool
89 SymmetricConformation::same_type_as_me( Conformation const & other, bool recurse /* = true */ ) const
90 {
91  if ( ! dynamic_cast< SymmetricConformation const * > ( &other) ) {
92  return false;
93  }
94  if ( recurse ) {
95  return other.same_type_as_me( *this, false );
96  } else {
97  return true;
98  }
99 }
100 
103 {
104  return symm_info_;
105 }
106 
109 {
110  return symm_info_;
111 }
112 
114 
115 /// DOF
116 void
117 SymmetricConformation::set_dof( DOF_ID const & id, Real const setting )
118 {
119  typedef SymmetryInfo::DOF_IDs DOF_IDs;
120 
121  core::Size parent_rsd;
122 
123  if ( !symm_info_->dof_is_independent( id, *this ) ) {
124  TR.Debug << "SymmetricConformation:: directly setting a dependent DOF!, try to set its parent" << std::endl;
125  if (id.type() >= id::RB1 && id.type() <= id::RB6) {
126  int parent_jump = symm_info_->jump_follows( fold_tree().get_jump_that_builds_residue( id.rsd() ) );
127  parent_rsd = fold_tree().downstream_jump_residue( parent_jump );
128 
129  // clear cached transforms ... is this necessary??
130  Tsymm_.clear();
131  } else {
132  parent_rsd = symm_info_->bb_follows( id.rsd() ) ;
133  }
134  } else {
135  parent_rsd = id.rsd();
136  }
137 
138  id::DOF_ID parent_id ( id::AtomID( id.atomno(), parent_rsd ), id.type() );
139 
140  // set this DOF using base-class method
141  Conformation::set_dof( parent_id, setting );
142  {
143  DOF_IDs const & dofs( symm_info_->dependent_dofs( parent_id, *this ) );
144  for ( DOF_IDs::const_iterator dof =dofs.begin(), dofe= dofs.end(); dof != dofe; ++dof ) {
145  Conformation::set_dof( *dof, setting );
146  }
147  }
148 }
149 
150 /// @brief set the secondary structure of a sequence position
151 /// @details Sets secondary structure character of a sequence position.
152 /// Will resize the secondary structure array if the requested sequence
153 /// position is larger than the length of the array.
154 void
155 SymmetricConformation::set_secstruct( Size const seqpos, char const setting )
156 {
157  Conformation::set_secstruct( seqpos, setting );
158  if ( symm_info_->bb_is_independent( seqpos ) ) {
159  for ( SymmetryInfo::Clones::const_iterator pos=symm_info_->bb_clones( seqpos ).begin(),
160  epos=symm_info_->bb_clones( seqpos ).end(); pos != epos; ++pos ) {
161  Conformation::set_secstruct( *pos, setting );
162  }
163  } else {
164  TR.Debug << "SymmetricConformation:: Setting secstruct for dependent residue!, try to set its parent" << std::endl;
165  }
166 }
167 
168 /// set the fold_tree, update symmetryinfo
169 void
171 {
172  Conformation::fold_tree( fold_tree_in );
173  FoldTree asymm_f = get_asymm_unit_fold_tree(*this);
174  symm_info_->update_nmonomer_jumps( asymm_f.num_jump()-1 ); // always an extra jump
175 }
176 
177 /// TORSIONS
178 void
180 {
181  typedef SymmetryInfo::TorsionIDs TorsionIDs;
182 
183  TR.Trace << "SymmetricConformation: set_torsion: " << id << ' ' << setting << std::endl;
184 
185  core::Size parent_rsd;
186 
187  if ( !symm_info_->torsion_is_independent( id ) ) {
188  TR.Debug << "SymmetricConformation:: directly setting a dependent TORSION!, try to set its parent" << std::endl;
189  parent_rsd = symm_info_->bb_follows( id.rsd() ) ;
190  } else {
191  parent_rsd = id.rsd();
192  }
193 
194  id::TorsionID parent_id ( parent_rsd, id.type(), id.torsion() );
195 
196  // set this DOF using base-class method
197  Conformation::set_torsion( parent_id, setting );
198  {
199  TorsionIDs const & tors( symm_info_->dependent_torsions( parent_id ) );
200  for ( TorsionIDs::const_iterator tor =tors.begin(), tore= tors.end(); tor != tore; ++tor ) {
201  Conformation::set_torsion( *tor, setting );
202  }
203  }
204 }
205 
206 /// TORSION ANGLES
207 void
209  AtomID const & atom1,
210  AtomID const & atom2,
211  AtomID const & atom3,
212  AtomID const & atom4,
213  Real const setting
214 )
215 {
216  AtomID parent_atom1, parent_atom2, parent_atom3, parent_atom4;
217 
218  TR.Trace << "SymmetricConformation: set_torsion_angle: " << atom1 << "+ to " << setting << std::endl;
219 
220  // assume if 1st atom is dependent, all are
221  if ( !symm_info_->bb_is_independent( atom1.rsd() ) ) {
222  TR.Debug << "SymmetricConformation:: directly setting a dependent ANGLE!, try to set its parent" << std::endl;
223  parent_atom1 = id::AtomID( atom1.atomno(), symm_info_->bb_follows( atom1.rsd() ) );
224  parent_atom2 = id::AtomID( atom2.atomno(), symm_info_->bb_follows( atom2.rsd() ) );
225  parent_atom3 = id::AtomID( atom3.atomno(), symm_info_->bb_follows( atom3.rsd() ) );
226  parent_atom4 = id::AtomID( atom3.atomno(), symm_info_->bb_follows( atom3.rsd() ) );
227  } else {
228  parent_atom1=atom1;
229  parent_atom2=atom2;
230  parent_atom3=atom3;
231  parent_atom4=atom4;
232  }
233 
234  // set this DOF using base-class method
235  Conformation::set_torsion_angle( parent_atom1, parent_atom2, parent_atom3, parent_atom4, setting );
236 
237  {
238  core::Size nclones = symm_info_->num_bb_clones( );
239  SymmetryInfo::Clones clones1 = symm_info_->bb_clones( parent_atom1.rsd() );
240  SymmetryInfo::Clones clones2 = symm_info_->bb_clones( parent_atom2.rsd() );
241  SymmetryInfo::Clones clones3 = symm_info_->bb_clones( parent_atom3.rsd() );
242  SymmetryInfo::Clones clones4 = symm_info_->bb_clones( parent_atom4.rsd() );
243  AtomID dep_atom1, dep_atom2, dep_atom3, dep_atom4;
244  for (int i=1; i<=(int)nclones; ++i) {
245  dep_atom1 = id::AtomID( atom1.atomno(), clones1[i] );
246  dep_atom2 = id::AtomID( atom2.atomno(), clones2[i] );
247  dep_atom3 = id::AtomID( atom3.atomno(), clones3[i] );
248  dep_atom4 = id::AtomID( atom4.atomno(), clones4[i] );
249  Conformation::set_torsion_angle( dep_atom1, dep_atom2, dep_atom3, dep_atom4, setting );
250  }
251  }
252 }
253 
254 
255 /// BOND ANGLES
256 void
258  AtomID const & atom1,
259  AtomID const & atom2,
260  AtomID const & atom3,
261  Real const setting
262 )
263 {
264  AtomID parent_atom1, parent_atom2, parent_atom3;
265 
266  TR.Trace << "SymmetricConformation: set_bond_angle: " << atom1 << "+ to " << setting << std::endl;
267 
268  // assume if 1st atom is dependent, all are
269  if ( !symm_info_->bb_is_independent( atom1.rsd() ) ) {
270  TR.Debug << "SymmetricConformation:: directly setting a dependent ANGLE!, try to set its parent" << std::endl;
271  parent_atom1 = id::AtomID( atom1.atomno(), symm_info_->bb_follows( atom1.rsd() ) );
272  parent_atom2 = id::AtomID( atom2.atomno(), symm_info_->bb_follows( atom2.rsd() ) );
273  parent_atom3 = id::AtomID( atom3.atomno(), symm_info_->bb_follows( atom3.rsd() ) );
274  } else {
275  parent_atom1=atom1;
276  parent_atom2=atom2;
277  parent_atom3=atom3;
278  }
279 
280  // set this DOF using base-class method
281  Conformation::set_bond_angle( parent_atom1, parent_atom2, parent_atom3, setting );
282 
283  {
284  core::Size nclones = symm_info_->num_bb_clones( );
285  SymmetryInfo::Clones clones1 = symm_info_->bb_clones( parent_atom1.rsd() );
286  SymmetryInfo::Clones clones2 = symm_info_->bb_clones( parent_atom2.rsd() );
287  SymmetryInfo::Clones clones3 = symm_info_->bb_clones( parent_atom3.rsd() );
288  AtomID dep_atom1, dep_atom2, dep_atom3;
289  for (int i=1; i<=(int)nclones; ++i) {
290  dep_atom1 = id::AtomID( atom1.atomno(), clones1[i] );
291  dep_atom2 = id::AtomID( atom2.atomno(), clones2[i] );
292  dep_atom3 = id::AtomID( atom3.atomno(), clones3[i] );
293  Conformation::set_bond_angle( dep_atom1, dep_atom2, dep_atom3, setting );
294  }
295  }
296 }
297 
298 /// BOND LENGTHS
299 void
301  AtomID const & atom1,
302  AtomID const & atom2,
303  Real const setting
304 )
305 {
306  AtomID parent_atom1, parent_atom2;
307 
308  TR.Trace << "SymmetricConformation: set_bond_length: " << atom1 << "+ to " << setting << std::endl;
309 
310  // assume if 1st atom is dependent, all are
311  if ( !symm_info_->bb_is_independent( atom1.rsd() ) ) {
312  TR.Debug << "SymmetricConformation:: directly setting a dependent BONDLENGTH!, try to set its parent" << std::endl;
313  parent_atom1 = id::AtomID( atom1.atomno(), symm_info_->bb_follows( atom1.rsd() ) );
314  parent_atom2 = id::AtomID( atom2.atomno(), symm_info_->bb_follows( atom2.rsd() ) );
315  } else {
316  parent_atom1=atom1;
317  parent_atom2=atom2;
318  }
319 
320  // set this DOF using base-class method
321  Conformation::set_bond_length( parent_atom1, parent_atom2, setting );
322 
323  {
324  core::Size nclones = symm_info_->num_bb_clones( );
325  SymmetryInfo::Clones clones1 = symm_info_->bb_clones( parent_atom1.rsd() );
326  SymmetryInfo::Clones clones2 = symm_info_->bb_clones( parent_atom2.rsd() );
327  AtomID dep_atom1, dep_atom2, dep_atom3;
328  for (int i=1; i<=(int)nclones; ++i) {
329  dep_atom1 = id::AtomID( atom1.atomno(), clones1[i] );
330  dep_atom2 = id::AtomID( atom2.atomno(), clones2[i] );
331  Conformation::set_bond_length( dep_atom1, dep_atom2, setting );
332  }
333  }
334 }
335 
336 
337  /// JUMPS
338 void
339 SymmetricConformation::set_jump( int const jump_number, kinematics::Jump const & new_jump )
340 {
341  typedef SymmetryInfo::AtomIDs AtomIDs;
342  typedef SymmetryInfo::Clones Clones;
343 
344  TR.Trace << "SymmetricConformation: set_jump jump_number: " << jump_number << std::endl;
345 
346  // clear cached transforms
347  Tsymm_.clear();
348 
349  id::AtomID const id( Conformation::jump_atom_id( jump_number ) );
350  Conformation::set_jump( id, new_jump );
351 
352  if ( !symm_info_->jump_is_independent( jump_number ) ) {
353  TR.Warning << "SymmetricConformation:: directly setting a dependent ATOM!" << std::endl;
354  TR.Warning << "the jump " << jump_number << " is controlled by " << symm_info_->jump_follows( jump_number ) << std::endl;
355  } else {
356  for ( Clones::const_iterator pos= symm_info_->jump_clones( jump_number ).begin(),
357  epos=symm_info_->jump_clones( jump_number ).end(); pos != epos; ++pos ) {
358  id::AtomID const id_clone( Conformation::jump_atom_id( *pos ) );
359  Conformation::set_jump( id_clone, new_jump );
360  }
361  }
362 }
363 
364 void
365 SymmetricConformation::set_jump_now( int const jump_number, kinematics::Jump const & new_jump )
366 {
367  typedef SymmetryInfo::AtomIDs AtomIDs;
368  typedef SymmetryInfo::Clones Clones;
369 
370  TR.Trace << "SymmetricConformation: set_jump jump_number: " << jump_number << std::endl;
371 
372  // clear cached transforms
373  Tsymm_.clear();
374 
375  Conformation::set_jump_now( jump_number, new_jump );
376 
377  if ( !symm_info_->jump_is_independent( jump_number ) ) {
378  TR.Warning << "SymmetricConformation:: directly setting a dependent ATOM!" << std::endl;
379  } else {
380  for ( Clones::const_iterator pos= symm_info_->jump_clones( jump_number ).begin(),
381  epos=symm_info_->jump_clones( jump_number ).end(); pos != epos; ++pos ) {
382  id::AtomID const id_clone( Conformation::jump_atom_id( *pos ) );
383  Conformation::set_jump( id_clone, new_jump );
384  }
385  }
386 }
387 
388 // This doesn't work with
389 void
391 {
392  typedef SymmetryInfo::AtomIDs AtomIDs;
393  typedef SymmetryInfo::Clones Clones;
394 
395  TR.Trace << "SymmetricConformation: set_jump id:" << id << std::endl;
396 
397  // clear cached transforms
398  Tsymm_.clear();
399 
400  Conformation::set_jump( id, new_jump );
401 
402  int const jump_number ( fold_tree().get_jump_that_builds_residue( id.rsd() ) );
403  if ( !symm_info_->jump_is_independent( jump_number ) ) {
404  TR.Warning << "SymmetricConformation:: directly setting a dependent ATOM!" << std::endl;
405  } else {
406  for ( Clones::const_iterator pos= symm_info_->jump_clones( jump_number ).begin(),
407  epos=symm_info_->jump_clones( jump_number ).end(); pos != epos; ++pos ) {
408  id::AtomID const id_clone( Conformation::jump_atom_id( *pos ) );
409  Conformation::set_jump( id_clone, new_jump );
410  }
411  }
412 }
413 
414 ///////////////////////////////////////////////////////////////////////////////
415 /// @details Returns a mask of residues over which scoring is restricted.
416 /// Only these residues will be used in constructing the neighbor list
419  return symm_info_->independent_residues();
420 }
421 
424  return symm_info_->score_multiply(resid1,resid2);
425 }
426 
427 /// @details symmetry-safe replace residue
428 void
429 SymmetricConformation::replace_residue( Size const seqpos, Residue const & new_rsd_in, bool const orient_backbone ) {
430  TR.Debug << "SymmetricConformation: replace_residue: " << seqpos << std::endl;
431 
432  core::Size parent_rsd;
433  Residue new_rsd = new_rsd_in;
434 
435  if ( !symm_info_->bb_is_independent( seqpos ) ) {
436  TR.Debug << "SymmetricConformation::replace_residue(2) directly setting a dependent TORSION!, try to set its parent" << std::endl;
437 
438  parent_rsd = symm_info_->bb_follows( seqpos ) ;
439 
440  // if we're not orienting backbone, we need to transform the coord frame to that of the ind. subunit
441  if (!orient_backbone) {
442  // make the new res
443  for (int i=1; i<=(int)new_rsd.natoms(); ++i) {
444  new_rsd.set_xyz(i , apply_transformation( new_rsd_in.xyz(i), seqpos, parent_rsd ) );
445  }
446  }
447  } else {
448  parent_rsd = seqpos;
449  }
450 
451  // set this residue using base-class method
452  Conformation::replace_residue( parent_rsd, new_rsd, orient_backbone );
453 
454  // now the copies
455  for ( SymmetryInfo::Clones::const_iterator pos=symm_info_->bb_clones( parent_rsd ).begin(),
456  epos=symm_info_->bb_clones( parent_rsd ).end(); pos != epos; ++pos ) {
457  // if we're not orienting backbone, update symm copies using local coord frame for each
458  //fpd --> we already oriented backbone for master, that should be good enough
459  if (!orient_backbone) {
460  // make the new res
461  Residue new_new_rsd = new_rsd;
462  for (int i=1; i<=(int)new_new_rsd.natoms(); ++i) {
463  new_new_rsd.set_xyz(i , apply_transformation( new_rsd.xyz(i), parent_rsd, *pos ) );
464  }
465  Conformation::replace_residue( *pos, new_new_rsd, false );
466  } else {
467  Conformation::replace_residue( *pos, new_rsd, orient_backbone );
468  }
469  }
470 }
471 
472 /// @details symmetry-safe replace residue
473 void
475  Residue const & new_rsd,
476  utility::vector1< std::pair< std::string, std::string > > const & atom_pairs ) {
477  core::Size parent_rsd;
478 
479  if ( !symm_info_->bb_is_independent( seqpos ) ) {
480  TR.Debug << "SymmetricConformation::replace_residue(3) setting a dependent TORSION!, try to set its parent" << std::endl;
481  parent_rsd = symm_info_->bb_follows( seqpos ) ;
482  } else {
483  parent_rsd = seqpos;
484  }
485 
486  // set this residue using base-class method
487  Conformation::replace_residue( parent_rsd, new_rsd, atom_pairs );
488 
489  // now the copies
490  for ( SymmetryInfo::Clones::const_iterator pos=symm_info_->bb_clones( parent_rsd ).begin(),
491  epos=symm_info_->bb_clones( parent_rsd ).end(); pos != epos; ++pos ) {
492  //fpd Same logic as above; we already oriented backbone for master, that should be good enough
493  // make the new res
494  Residue new_new_rsd = new_rsd;
495  for (int i=1; i<=(int)new_new_rsd.natoms(); ++i) {
496  new_new_rsd.set_xyz(i , apply_transformation( new_rsd.xyz(i), parent_rsd, *pos ) );
497  }
498  Conformation::replace_residue( *pos, new_new_rsd, false );
499  }
500 }
501 
502 
505  if (this->residue( seqpos ).aa() == core::chemical::aa_vrt)
506  return seqpos;
507 
508  // find peptide segment that contains this res (?)
509  core::kinematics::Edge const &e = fold_tree().get_residue_edge( seqpos );
510  core::Size curr_res = e.start();
511 
512  while ( this->residue( curr_res ).aa() != core::chemical::aa_vrt ) {
513  core::kinematics::Edge const &e_i = fold_tree().get_residue_edge( curr_res );
514  curr_res = e_i.start();
515  }
516 
517  return curr_res;
518 }
519 
520 // Get the transformation controlling resid i
521 numeric::HomogeneousTransform< core::Real >
523  if (Tsymm_.size() != symm_info_->subunits())
525 
526  return Tsymm_[ symm_info_->subunit_index( resid ) ];
527 }
528 
529 // Remap coordinate X from resid i to j
532  PointPosition Xin,
533  core::Size residfrom,
534  core::Size residto ) {
535  if (Tsymm_.size() != symm_info_->subunits())
537 
538  numeric::HomogeneousTransform< core::Real > const &Tsymm_from
539  = Tsymm_[ symm_info_->subunit_index( residfrom ) ];
540  numeric::HomogeneousTransform< core::Real > const &Tsymm_to
541  = Tsymm_[ symm_info_->subunit_index( residto ) ];
542 
543  PointPosition Xout;
544  Xout = (Tsymm_from.inverse() * Xin);
545  Xout = (Tsymm_to * Xout);
546  // TR.Debug << "XFORM " << residfrom << " to " << residto << std::endl;
547  // TR.Debug << " Xin = (" << Xin[0] << "," << Xin[1] << "," << Xin[2] << ")" << std::endl;
548  // TR.Debug << "Tto * Tfrom^-1 * Xin = (" << Xout[0] << "," << Xout[1] << "," << Xout[2] << ")" << std::endl;
549  return Xout;
550 }
551 
552 // Symmetric set_xyz
553 void
555  AtomID const & id,
556  PointPosition const & position ) {
557  TR.Debug << "SymmetricConformation::set_xyz: " << id << std::endl;
558 
559  AtomID parent_id;
560  PointPosition parent_pos;
561 
562  // pass set_xyz on symmetric vrts directly to the base class
563  // this is potentially dangerous but may be useful
564  if ( id.rsd() > symm_info_->num_total_residues_without_pseudo() ) {
565  Conformation::set_xyz( id, position );
566  return;
567  }
568 
569  if ( !symm_info_->bb_is_independent( id.rsd() ) ) {
570  TR.Debug << "SymmetricConformation::set_xyz setting a dependent XYZ; remapping to its parent" << std::endl;
571  parent_id = AtomID( id.atomno(), symm_info_->bb_follows( id.rsd() ) );
572  parent_pos = apply_transformation( position, id.rsd(), parent_id.rsd() );
573  } else {
574  parent_id = id;
575  parent_pos = position;
576  }
577 
578  // set parent XYZ using base-class method, followed by all copies
579  Conformation::set_xyz( parent_id, parent_pos );
580  for ( SymmetryInfo::Clones::const_iterator pos=symm_info_->bb_clones( parent_id.rsd() ).begin(),
581  epos=symm_info_->bb_clones( parent_id.rsd() ).end(); pos != epos; ++pos ) {
582  AtomID id_i = AtomID( id.atomno(), *pos );
583  PointPosition pos_i = apply_transformation( parent_pos, parent_id.rsd(), *pos );
584  Conformation::set_xyz( id_i, pos_i );
585  }
586 }
587 
588 // Symmetric batch_set_xyz
589 void
591  utility::vector1<AtomID> const & ids,
592  utility::vector1<PointPosition> const & positions
593 ) {
594  runtime_assert( ids.size() == positions.size() );
595  TR.Debug << "SymmetricConformation::batch_set_xyz" << std::endl;
596 
597  utility::vector1<AtomID> ids_with_symm;
598  utility::vector1<PointPosition> positions_with_symm;
599 
600  // pass set_xyz on symmetric vrts directly to the base class
601  // this is potentially dangerous but may be useful
602  for (int i=1; i<=(int)ids.size(); ++i) {
603  AtomID id=ids[i], parent_id;
604  PointPosition position=positions[i], parent_pos;
605 
606  if ( id.rsd() > symm_info_->num_total_residues_without_pseudo() ) {
607  ids_with_symm.push_back( id );
608  positions_with_symm.push_back( position );
609  } else {
610  if ( !symm_info_->bb_is_independent( id.rsd() ) ) {
611  TR.Debug << "SymmetricConformation::set_xyz setting a dependent XYZ; remapping to its parent" << std::endl;
612  parent_id = AtomID( id.atomno(), symm_info_->bb_follows( id.rsd() ) );
613  parent_pos = apply_transformation( position, id.rsd(), parent_id.rsd() );
614  } else {
615  parent_id = id;
616  parent_pos = position;
617  }
618 
619  // set parent XYZ using base-class method, followed by all copies
620  ids_with_symm.push_back( parent_id );
621  positions_with_symm.push_back( parent_pos );
622  for ( SymmetryInfo::Clones::const_iterator pos=symm_info_->bb_clones( parent_id.rsd() ).begin(),
623  epos=symm_info_->bb_clones( parent_id.rsd() ).end(); pos != epos; ++pos ) {
624  AtomID id_i = AtomID( id.atomno(), *pos );
625  PointPosition pos_i = apply_transformation( parent_pos, parent_id.rsd(), *pos );
626  ids_with_symm.push_back( id_i );
627  positions_with_symm.push_back( pos_i );
628  }
629  }
630  }
631 
632  Conformation::batch_set_xyz( ids_with_symm, positions_with_symm );
633 }
634 
635 // recalculate the Tsymm_ transforms using the current pose
636 void
638  using namespace numeric;
639 
640  // clear current xforms
641  Tsymm_.clear();
642 
643  // rebuild based on virtuals
644  core::Size nsubunits = symm_info_->subunits();
645  core::Size nresMonomer = symm_info_->num_independent_residues();
646 
647  for (int i=1; i<=(int)nsubunits; ++i) {
648  // find the VRT that builds this res
649  core::Size vrt_ctrl = get_upstream_vrt( nresMonomer*(i-1) + 1 );
650  Residue const &parent_vrt_res = residue( vrt_ctrl );
651 
652  xyzVector< core::Real > const &orig = parent_vrt_res.atom("ORIG").xyz();
653  xyzVector< core::Real > X = parent_vrt_res.atom("X").xyz() - orig;
654  xyzVector< core::Real > Y = parent_vrt_res.atom("Y").xyz() - orig;
655  xyzVector< core::Real > Z = X.cross( Y );
656 
657  //TR.Debug << "[TRANSFORM " << i << "/" << vrt_ctrl << "]" << std::endl
658  // << " X = (" << X[0] << "," << X[1] << "," << X[2] << ")" << std::endl
659  // << " Y = (" << Y[0] << "," << Y[1] << "," << Y[2] << ")" << std::endl
660  // << " Z = (" << Z[0] << "," << Z[1] << "," << Z[2] << ")" << std::endl
661  // << " orig = (" << orig[0] << "," << orig[1] << "," << orig[2] << ")" << std::endl;
662  Tsymm_.push_back( HomogeneousTransform< core::Real>( orig-Y,orig-Z, orig ) );
663  }
664 }
665 
666 
667 //fpd
668 void
670  conformation::Residue const & new_rsd,
671  Size const anchor_pos,
672  std::string const& anchor_atom, // could be zero
673  std::string const& root_atom, // ditto
674  bool const start_new_chain // default false
675 )
676 {
677  if (start_new_chain) {
678  TR.Warning << "SymmetricConformation::append_residue_by_jump ignores start_new_chain" << std::endl;
679  }
680 
681  core::Size nmonomer_jumps = symm_info_->get_njumps_subunit();
682  core::Size nres_monomer = symm_info_->get_nres_subunit();
683  core::Size nsubunits = symm_info_->subunits();
684  core::Size asymm_anchor = ((anchor_pos-1)%nres_monomer) + 1;
685 
686  // add to the end of each subunit
687  // transform to the coordinate frame of the scoring subunit
688  // go from last->first so we don't have to worry about offsets
689  for ( int i=nsubunits; i>=1; --i ) {
690  core::Size seqpos = i*nres_monomer;
691  core::Size anchor_pos = (i-1)*nres_monomer+asymm_anchor;
692  Residue new_new_rsd = new_rsd;
693  if ( !symm_info_->bb_is_independent( seqpos ) ) {
694  // transform coords
695  for (int j=1; j<=(int)new_new_rsd.natoms(); ++j) {
696  new_new_rsd.set_xyz(j , apply_transformation( new_rsd.xyz(j), nres_monomer, seqpos ) );
697  }
698  }
699  insert_residue_by_jump( new_new_rsd, seqpos+1, anchor_pos, anchor_atom, root_atom, start_new_chain );
700  }
701  // update symminfo
702  symm_info_->resize_asu( nres_monomer + 1 );
703  symm_info_->update_nmonomer_jumps( nmonomer_jumps + 1 );
704 
705  // update ft
708  fold_tree( f_in );
709 }
710 
711 void
713  Conformation const & new_conf,
714  Size const insert_seqpos,
715  Size const,
716  Size const anchor_pos,
717  Size const anchor_jump_number,
718  std::string const & anchor_atom,
719  std::string const & root_atom
720 ) {
721  if (anchor_jump_number != 0) {
722  TR.Warning << "SymmetricConformation::insert_conformation_by_jump ignores anchor_jump_number" << std::endl;
723  }
724 
725  core::Size nmonomer_jumps = symm_info_->get_njumps_subunit();
726  core::Size nres_monomer = symm_info_->get_nres_subunit();
727  core::Size nsubunits = symm_info_->subunits();
728  core::Size asymm_insert = ((insert_seqpos-2)%nres_monomer) + 2; //?
729  core::Size asymm_anchor = ((anchor_pos-1)%nres_monomer) + 1;
730 
731  // insert at the end of each subunit
732  // transform to the coordinate frame of the scoring subunit
733  // go from last->first so we don't have to worry about offsets
734  for ( int i=nsubunits; i>=1; --i ) {
735  core::Size insert_i = (i-1)*nres_monomer+asymm_insert;
736  core::Size anchor_i = (i-1)*nres_monomer+asymm_anchor;
737 
738  Conformation new_new_conf = new_conf;
739  if ( !symm_info_->bb_is_independent( anchor_i ) ) {
740  // transform coords
741  for (core::Size j=1; j<=new_new_conf.size(); ++j) {
742  for (core::Size k=1; k<=new_new_conf.residue(j).natoms(); ++k) {
743  new_new_conf.set_xyz(core::id::AtomID(k,j) , apply_transformation( new_conf.residue(j).xyz(k), nres_monomer, anchor_i ) );
744  }
745  }
746  }
747  Conformation::insert_conformation_by_jump( new_new_conf, insert_i, nmonomer_jumps+i, anchor_i, 0, anchor_atom, root_atom );
748  }
749 
750  // update symminfo
751  symm_info_->resize_asu( nres_monomer + new_conf.size() );
752  symm_info_->update_nmonomer_jumps( nmonomer_jumps + new_conf.fold_tree().num_jump() + 1 );
753 
754  // update ft
757  fold_tree( f_in );
758 }
759 
760 /**
761  * @brief Detect existing disulfides from the protein structure.
762  * @details For full atom confomations, looks at SG-SG distance. If the SG-SG
763  * are about 2.02 A apart, calls it a disulfide bond. For centroid and other
764  * conformations, the less accurate CB-CB distance is used instead. In this
765  * case a CB-CB distance of 3.72 A is optimal.
766  */
767 void
769 {
770  using namespace graph;
771  using namespace basic::options;
772 
773  // gather all cys, construct mapping from resid to cys index
774  utility::vector1< Size > resid_2_cysid( size(), 0 );
775  Size num_cys( 0 );
776  for ( Size ii = 1; ii <= size(); ++ii ) {
777  if ( residue(ii).aa() == chemical::aa_cys ) {
778  ++num_cys;
779  resid_2_cysid[ ii ] = num_cys;
780  }
781  }
782  if ( num_cys == 0 ) return;
783 
784  // construct reverse mapping from cys index to resid
785  utility::vector1< Size > cysid_2_resid( num_cys );
786  for ( Size ii = 1; ii <= size(); ++ii ) {
787  if ( resid_2_cysid[ ii ] != 0 ) {
788  cysid_2_resid[ resid_2_cysid[ ii ]] = ii;
789  }
790  }
791 
792  // If all the cys are fullatom, use stricter criteria
793  bool fullatom(true);
794  for( Size ii = 1; ii <= num_cys; ++ii) {
795  if( residue_type(cysid_2_resid[ii]).residue_type_set().name()
797  {
798  fullatom = false;
799  break;
800  }
801  }
802  // SG-SG distance for fullatom, CB-CB distance otherwise
803  Real const typical_disulfide_distance = fullatom? 2.02 : 3.72;
804  Real const tolerance = option[OptionKeys::in::detect_disulf_tolerance].user()
805  ? option[OptionKeys::in::detect_disulf_tolerance]()
806  : ( fullatom? 0.5 : 1.0 );
807  std::string const distance_atom = fullatom? "SG" : "CB";
808 
809  // Create point graph
810  PointGraphOP pg = new PointGraph;
811  pg->set_num_vertices( num_cys );
812  Distance maxrad( 0.0 );
813  Distance maxd( typical_disulfide_distance + tolerance );
814  for ( Size ii = 1; ii <= num_cys; ++ii ) {
815  Residue const & ii_res = residue( cysid_2_resid[ ii ] );
816  pg->get_vertex(ii).data().xyz() = ii_res.atoms()[ ii_res.nbr_atom() ].xyz();
817  if ( ii_res.nbr_radius() > maxrad ) maxrad = ii_res.nbr_radius();
818  }
819  Distance neighbor_cutoff = maxrad + maxd;
820  find_neighbors( pg, neighbor_cutoff );
821 
822  // Iterate across neighbors of cys residues; examine SG-SG distances.
823  // Note that since graph only stores upper neighbors iterating through
824  // the (upper) edge list will automatically prevent double counting.
825  std::set< Size > processed_cys; // track cys that have already been processed
826  for ( Size ii = 1; ii <= num_cys; ++ii ) {
827  Size const ii_resid = cysid_2_resid[ ii ];
828  if(ii_resid > symm_info_->num_independent_residues()) continue;
829  //Size const ii_n_conn = residue( ii_resid ).type().n_residue_connections();
830  Residue const & ii_res( residue( ii_resid ) );
831  //if ii already processed, continue
832  if( processed_cys.find( ii_resid) != processed_cys.end() ) {
833  continue;
834  }
835 
836  //Determine which atom makes the disulfide bond
837  Size ii_sg_atomno(0);
838  if(ii_res.type().has_atom_name("SG")) {
839  ii_sg_atomno = residue( cysid_2_resid[ ii ] ).atom_index( "SG" );
840  } else if(ii_res.type().has_atom_name("CEN")) {
841  ii_sg_atomno = residue( cysid_2_resid[ ii ] ).atom_index( "CEN" );
842  } else {
843  TR.Error << "Error: Can't find an atom to disulfide bond from at residue "<< ii_resid <<std::endl;
844  utility_exit();
845  }
846 
847  Distance best_match( 0.0 );
848  Size best_neighbor( 0 );
849  //Size best_neighbor_cysid( 0 );
850 
852  ii_iter = pg->get_vertex( ii ).upper_edge_list_begin(),
853  ii_end_iter = pg->get_vertex( ii ).upper_edge_list_end();
854  ii_iter != ii_end_iter; ++ii_iter ) {
855  Size const jj = ii_iter->upper_vertex();
856 
857  Size const jj_resid = cysid_2_resid[ jj ];
858 
859  Residue const & jj_res( residue( jj_resid ) );
860 
861  //if jj already processed, continue
862  if( processed_cys.find( jj_resid) != processed_cys.end() ) {
863  continue;
864  }
865 
866  Distance dist = ii_res.atom( ii_sg_atomno ).xyz().distance(
867  jj_res.atom( jj_res.atom_index( distance_atom )).xyz() );
868  if ( best_neighbor == 0 || dist < best_match ) {
869  best_neighbor = jj_resid;
870  //best_neighbor_cysid = jj; // set but never used ~Labonte
871  best_match = dist;
872  }
873  }
874 
875  if ( best_neighbor == 0 || best_match >= typical_disulfide_distance + tolerance ) {
876  // handle case where old disulfide doesn't exist anymore and
877  // needs to be cleared
878  if ( processed_cys.find( ii_resid ) == processed_cys.end() && ii_res.has_variant_type( chemical::DISULFIDE ) ) {
879  TR << "Reverting out-of-date disulfide CYD to CYS at resid " << ii_resid << std::endl;
880 
881  bool const successful_revert = conformation::change_cys_state( ii_resid, "CYS", *this ) && !residue(ii_resid).has_variant_type( chemical::DISULFIDE );
882  if ( !successful_revert ) {
883  TR.Error << "ERROR: unable to revert CYD to CYS for removal of disulfide at resid " << ii_resid << std::endl;
884  }
885  }
886 
887  // mark cys as processed
888  processed_cys.insert( ii_resid );
889 
890  continue;
891 
892  } else { // found disulfide bond
893 
894  // Create disulfide bond using CYD residues. Note that this will
895  // end up doing a dummy replace for already existing disulfides,
896  // but it doesn't necessarily hurt just in case something weird
897  // happened.
898  TR << "Found "<< (fullatom?"":"CEN ") << "disulfide between residues " << ii_resid << " " << best_neighbor << std::endl;
899  TR << "current variant for " << ii_resid << " " << ( residues_[ ii_resid ]->has_variant_type( chemical::DISULFIDE ) ? "CYD" : "CYS" ) << std::endl;
900  TR << "current variant for " << best_neighbor << " " << ( residues_[ best_neighbor ]->has_variant_type( chemical::DISULFIDE ) ? "CYD" : "CYS" ) << std::endl;
901 
902  bool const success_at_ii = conformation::change_cys_state( ii_resid, "CYD", *this )
903  && residues_[ ii_resid ]->has_variant_type( chemical::DISULFIDE );
904  bool const success_at_best_neighbor = conformation::change_cys_state( best_neighbor, "CYD", *this )
905  && residues_[ best_neighbor ]->has_variant_type( chemical::DISULFIDE );
906 
907  if ( !success_at_ii ) {
908  TR.Error << "ERROR: unable to create residue type CYD for disulfide at resid " << ii_resid << std::endl;
909  }
910 
911  if ( !success_at_best_neighbor ) {
912  TR.Error << "ERROR: unable to create residue type CYD for disulfide at resid " << best_neighbor << std::endl;
913  }
914 
915  TR << "current variant for " << ii_resid << " " << ( residues_[ ii_resid ]->has_variant_type( chemical::DISULFIDE ) ? "CYD" : "CYS" ) << std::endl;
916  TR << "current variant for " << best_neighbor << " " << ( residues_[ best_neighbor ]->has_variant_type( chemical::DISULFIDE ) ? "CYD" : "CYS" ) << std::endl;
917 
918  // Record SG-SG connections.
919  if ( success_at_ii && success_at_best_neighbor ) {
920  Residue const & ii_new_res( residue( ii_resid ) );
921  // ASSUMPTION Disulfide forming cystein SG atoms for exactly one inter-residue chemical bond.
922  Size ii_connid = ii_new_res.type().residue_connection_id_for_atom( ii_sg_atomno );
923  Size jj_resid = best_neighbor;
924  Residue const & jj_res = residue( jj_resid );
925  Size jj_sg_atomno(0);
926  if(jj_res.type().has_atom_name("SG")) {
927  jj_sg_atomno = jj_res.atom_index( "SG" );
928  } else if(jj_res.type().has_atom_name("CEN")) {
929  jj_sg_atomno = jj_res.atom_index( "CEN" );
930  } else {
931  TR.Error << "Error: Can't find an atom to disulfide bond from at residue "<< jj_resid <<std::endl;
932  utility_exit();
933  }
934 
935  Size jj_connid = jj_res.type().residue_connection_id_for_atom( jj_sg_atomno );
936 
937  residues_[ ii_resid ]->residue_connection_partner( ii_connid, jj_resid, jj_connid );
938  residues_[ jj_resid ]->residue_connection_partner( jj_connid, ii_resid, ii_connid );
939  }
940  // mark both cys as processed
941  processed_cys.insert( ii_resid );
942  processed_cys.insert( best_neighbor );
943  }
944  }
945 
946 
947 }
948 
949 
950 
951 }
952 } // conformation
953 } // core
954 
955