Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
util.cc
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet:
3 //
4 // 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/pose/symmetry/util.hh
10 /// @brief utility functions for handling of symmetric conformations
11 /// @author Ingemar Andre
12 
13 // Unit headers
16 
24 #include <core/pose/Pose.hh>
25 #include <core/pose/util.hh>
27 #include <core/chemical/AA.hh>
30 
32 
33 // Utility functions
34 #include <basic/options/option.hh>
35 #include <basic/options/keys/symmetry.OptionKeys.gen.hh>
36 #include <basic/options/keys/fold_and_dock.OptionKeys.gen.hh>
37 #include <core/id/AtomID.hh>
38 #include <numeric/random/random.hh>
39 
40 // Package Headers
41 #include <core/kinematics/Edge.hh>
43 #include <core/pose/PDBInfo.hh>
44 
45 #include <basic/Tracer.hh>
46 
47 // ObjexxFCL Headers
48 #include <ObjexxFCL/FArray1D.hh>
49 #include <ObjexxFCL/FArray2D.hh>
50 #include <numeric/xyzMatrix.hh>
51 #include <numeric/xyzVector.hh>
52 #include <numeric/xyz.functions.hh>
53 
54 #include <utility/vector1.hh>
55 
56 
57 
58 namespace core {
59 namespace pose {
60 namespace symmetry {
61 
62 static basic::Tracer TR("core.pose.symmetry.util");
63 static numeric::random::RandomGenerator RG(408539); // <- Magic number, do not change it!!!
64 
65 bool
66 is_symmetric( scoring::Energies const & energies )
67 {
68  return ( dynamic_cast< scoring::symmetry::SymmetricEnergies const * >( &energies ) );
69 }
70 
71 /// @details Attempt to detect whether a pose is symmetric
72 bool
73 is_symmetric( pose::Pose const & pose )
74 {
76 }
77 
78 
79 bool
81 {
82  return ( dynamic_cast< scoring::symmetry::SymmetricScoreFunction const * >( &scorefxn ) );
83 }
84 
85 
86 /// @details Attempts to grab the symmetry info if the pose is symmetric
88 {
89  runtime_assert( is_symmetric( pose ) );
91  dynamic_cast<conformation::symmetry::SymmetricConformation const &> ( pose.conformation()) );
92  return SymmConf.Symmetry_Info();
93 }
94 
95 /// @details Attempt to detect whether a conformation is symmetric
96 bool
98 {
99  return ( dynamic_cast< conformation::symmetry::SymmetricConformation const * >( &conf ) );
100 }
101 
102 /// @details Attempt to detect whether a pose is symmetric
103 bool
105 {
107 }
108 
109 /// @details constructs a symmetric pose with a symmetric conformation and energies object
110 /// from a monomeric pose and symmetryinfo object.
111 /// Unlike the version of make_symmetric_pose from symmdata, this does not expand the
112 /// pose; it assumes the symmetric fold tree and residues are already present
113 /// For example, this is used to reconstruct a symm pose from a silent file
114 void
116  pose::Pose & pose,
118 )
119 {
121 
123 
124  pose.set_new_conformation( symm_conf );
125  pose.set_new_energies_object( symm_energy );
126 
127  pose::PDBInfoOP pdb_info = new pose::PDBInfo( pose, true );
128 
129  //fpd if the input pdb info is valid copy it
130  if ( pose.pdb_info() && pose.pdb_info()->nres() == pose.total_residue() ) {
131  pdb_info = new pose::PDBInfo( *(pose.pdb_info()) );
132  }
133  pose.pdb_info( pdb_info );
134 
135  assert( is_symmetric( pose ) );
136 
137  pose.conformation().detect_bonds();
138 }
139 
140 /// @details constructs a symmetric pose with a symmetric conformation and energies object from a monomeric pose
141 /// and symmData object
142 void
144  pose::Pose & pose,
146 )
147 {
148  pose::PDBInfoOP pdb_info_src( pose.pdb_info() );
149  if ( !pose.pdb_info() ) {
150  pdb_info_src = new pose::PDBInfo( pose, true );
151  }
152 
154  ( setup_symmetric_conformation( pose.conformation(), symmdata, conf2pdb_chain(pose) ) );
155 
157 
158  pose.set_new_conformation( symm_conf );
159  pose.set_new_energies_object( symm_energy );
160 
161  pose::PDBInfoOP pdb_info = new pose::PDBInfo( pose, true );
162  core::pose::symmetry::make_symmetric_pdb_info( pose, pdb_info_src, pdb_info );
163  pose.pdb_info( pdb_info );
164 
165  assert( is_symmetric( pose ) );
166 
168  pose.conformation().detect_bonds();
169 }
170 
171 /// @details constructs a symmetric pose with a symmetric conformation and energies object from a monomeric pose
172 /// and symmetry definition file on command line. Requires the presence of a symmetry_definition file
173 void
175  pose::Pose & pose,
176  std::string symmdef_file
177 )
178 {
179  using namespace basic::options;
180 
181  conformation::symmetry::SymmData symmdata( pose.n_residue(), pose.num_jump() );
182  std::string symm_def = symmdef_file.length()==0 ? option[ OptionKeys::symmetry::symmetry_definition ] : symmdef_file;
183  symmdata.read_symmetry_data_from_file(symm_def);
184  make_symmetric_pose( pose, symmdata );
185 }
186 
187 // @details make a symmetric pose assymmetric by instantiating new conformation and energies objects
188 void
190  pose::Pose & pose
191 )
192 {
193  // we need to cast the objects statically to get this working
194  scoring::Energies asym_energies( static_cast< scoring::Energies const & >( ( pose.energies() ) ) );
195  conformation::Conformation asym_conformation( static_cast< conformation::Conformation const & >( ( pose.conformation() ) ) );
196  conformation::ConformationOP conformation = new conformation::Conformation( asym_conformation );
197  scoring::EnergiesOP energies = new scoring::Energies( asym_energies );
198  pose.set_new_conformation( conformation );
199  // Necessary to reinitialize the energy_graph
200  energies->clear_energies();
201  pose.set_new_energies_object( energies );
202  assert( !is_symmetric( pose ) );
203 }
204 
205 // @details make a new (asymmetric) pose that contains only the master subunit from the input pose
206 // maintain local foldtree
207 void extract_asymmetric_unit(core::pose::Pose const& pose_in, core::pose::Pose & pose_out, bool with_virtual_atoms) {
213  using namespace core::conformation::symmetry;
214 
215  if (!is_symmetric( pose_in )) {
216  pose_out = pose_in;
217  return;
218  }
219 
220  SymmetricConformation const & symm_conf (
221  dynamic_cast<SymmetricConformation const & > ( pose_in.conformation() ) );
222  SymmetryInfoCOP symm_info( symm_conf.Symmetry_Info() );
223 
224  bool jump_to_next = false;
225  for( Size i=1; i<=symm_info->num_total_residues_without_pseudo(); i++ ) {
226  if (!symm_info->bb_is_independent(i))
227  continue;
228 
229  Residue residue( pose_in.residue( i ) );
230  if(residue.type().is_lower_terminus() ||
231  residue.aa() == aa_unk || residue.aa() == aa_vrt || jump_to_next ) {
232 
233  if( residue.aa() == aa_unk || residue.aa() == aa_vrt ) {
234  jump_to_next = true;
235  } else if( jump_to_next ) {
236  jump_to_next = false;
237  if( ! residue.is_lower_terminus() )
238  TR.Warning << "Residue following X, Z, or an upper terminus is _not_ a lower terminus type! Continuing ..." << std::endl;
239  }
240  pose_out.append_residue_by_jump( residue, 1, "", "", true ); // each time this happens, a new chain should be started
241  } else {
242  pose_out.append_residue_by_bond( residue, false );
243 
244  if ( residue.type().is_upper_terminus()) jump_to_next = true;
245  }
246  }
247 
248  // disulfide topology has to be reconstructed
249  using basic::options::option;
250  using namespace basic::options::OptionKeys;
251  if ( pose_out.is_fullatom() ) {
252  pose_out.conformation().detect_disulfides();
253  }
254 
255  // add the parent VRT, set foldtree
256  if( with_virtual_atoms ) {
259  pose_out.fold_tree( f_in );
260  }
261 
262  pose::PDBInfoOP pdb_info = new pose::PDBInfo( pose_out, true );
263 
264  pose::PDBInfoCOP pdb_info_src ( pose_in.pdb_info() );
265  if ( !pose_in.pdb_info() )
266  pdb_info_src = new pose::PDBInfo( pose_in, true );
267 
268  core::pose::symmetry::extract_asymmetric_unit_pdb_info( pose_in, pdb_info_src, pdb_info );
269  pose_out.pdb_info( pdb_info );
270 
271  runtime_assert( !core::pose::symmetry::is_symmetric( pose_out ) );
272 }
273 
274 
275 
276 
277 // @details make a asymmetric pose copying residues of original pose
280  pose::Pose const & pose
281 )
282 {
288 
289  core::pose::Pose new_pose;
290 
291  bool jump_to_next = false;
292  for( Size i=1; i<=pose.total_residue(); i++ ) {
293 
294  Residue residue( pose.residue( i ) );
295 
296  if(residue.type().has_variant_type( LOWER_TERMINUS ) ||
297  residue.aa() == aa_unk || residue.aa() == aa_vrt || jump_to_next ) {
298 
299  if( residue.aa() == aa_unk || residue.aa() == aa_vrt ) {
300  jump_to_next = true;
301  } else if( jump_to_next ) {
302  jump_to_next = false;
303  ///fpd ^^^ the problem is that the residue following the X should be connected by a jump as well.
304  /// it should be of LOWER_TERMINUS variant type, but if not, we'll recover & spit out a warning for now.
305  /// same thing for ligands???
306  if( ! residue.has_variant_type( LOWER_TERMINUS ) )
307  TR.Warning << "Residue following X, Z, or an upper terminus is _not_ a lower terminus type! Continuing ..." << std::endl;
308  }
309  new_pose.append_residue_by_jump( residue, 1, "", "", true ); // each time this happens, a new chain should be started
310 
311  } else {
312 
313  new_pose.append_residue_by_bond( residue, false );
314 
315  //fpd If res i is an upper terminus but (i+1) is not a lower terminus, the code exits on a failed assertion
316  //fpd Don't let this happen; always jump in these cases
317  if ( residue.type().has_variant_type( UPPER_TERMINUS )) jump_to_next = true;
318  }
319  }
320 
321  return new_pose;
322 }
323 
324 // @details make symmetric PDBIinfo
325 void
327  pose::Pose const & pose,
328  pose::PDBInfoOP pdb_info_src,
329  pose::PDBInfoOP pdb_info_target
330 )
331 {
332  using namespace core::conformation::symmetry;
333 
334  std::string chr_chains( "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$&.<>?]{}|-_\\~`\"')=%qrstuvwxyz" );
335 
336  runtime_assert( is_symmetric( pose ) );
337  runtime_assert( pdb_info_target->nres() == pose.total_residue() );
338  SymmetricConformation const & symm_conf (
339  dynamic_cast<SymmetricConformation const & > ( pose.conformation() ) );
340  SymmetryInfoCOP symm_info( symm_conf.Symmetry_Info() );
341 
342  // for updating chain IDs we need to know how many chains are in the scoring subunit
343  Size lastchnid=0;
344  for ( Size res=1; res <= pdb_info_src->nres(); ++res ) {
345  char chn_id = pdb_info_src->chain( res );
346  Size chn_idx = chr_chains.find(chn_id);
347  if (chn_idx!=std::string::npos) { // maybe chn is some other character ... the output chain IDs will be funky then ...
348  lastchnid = std::max( lastchnid, chn_idx );
349  }
350  }
351 
352  for ( Size res=1; res <= pdb_info_src->nres(); ++res ) {
353  // resids in scoring subunit
354  int res_id = pdb_info_src->number( res );
355  pdb_info_target->number( res, res_id );
356 
357  // chnids in scoring subunit
358  char chn_id = pdb_info_src->chain( res );
359  Size chn_idx = chr_chains.find(chn_id);
360  if (chn_idx==std::string::npos)
361  chn_idx = 0; // treat all weird-character chains as 'A' in symm copies
362  pdb_info_target->chain( res, chn_id );
363 
364  // symmetrize B's
365  for ( Size atm=1; atm <= pdb_info_src->natoms(res) /*pose.residue(res).natoms()*/; ++atm) {
366  core::Real b_atm = pdb_info_src->temperature( res, atm );
367  pdb_info_target->temperature( res, atm, b_atm );
368  }
369 
370  int clonecounter=1;
371  for ( std::vector< Size>::const_iterator
372  clone = symm_info->bb_clones( res ).begin(),
373  clone_end = symm_info->bb_clones( res ).end();
374  clone != clone_end; ++clone ) {
375  int clone_res( *clone );
376  pdb_info_target->number( clone_res, res_id );
377 
378  int newchn_idx = chn_idx + (clonecounter++)*(lastchnid+1);
379  pdb_info_target->chain( clone_res, chr_chains[newchn_idx] );
380 
381  // symmetrize B's
382  for ( Size atm=1; atm <= pdb_info_src->natoms(res) /*pose.residue(res).natoms()*/; ++atm) {
383  pdb_info_target->temperature( clone_res, atm, pdb_info_src->temperature( res, atm ) );
384  }
385  }
386  }
387 
388  // rebuild pdb2pose
389  pdb_info_target->rebuild_pdb2pose();
390 
391  // copy header and remark lines
392  if(pdb_info_src->header_information()){
393  pdb_info_target->header_information( new io::pdb::HeaderInformation(*pdb_info_src->header_information()));
394  }
395  pdb_info_target->remarks( pdb_info_src->remarks() );
396 }
397 
398 void
400  pose::Pose const & pose,
401  pose::PDBInfoCOP pdb_info_src,
402  pose::PDBInfoOP pdb_info_target
403 )
404 {
405  using namespace core::conformation::symmetry;
406 
407  if (!is_symmetric(pose)) {
408  pdb_info_target = new pose::PDBInfo( *pdb_info_src );
409  return;
410  }
411 
412  SymmetricConformation const & symm_conf (
413  dynamic_cast<SymmetricConformation const & > ( pose.conformation() ) );
414  SymmetryInfoCOP symm_info( symm_conf.Symmetry_Info() );
415 
416  for ( Size res=1; res <= symm_info->get_nres_subunit(); ++res ) {
417  int res_id = pdb_info_src->number( res );
418  pdb_info_target->number( res, res_id );
419 
420  char chn_id = pdb_info_src->chain( res );
421  pdb_info_target->chain( res, chn_id );
422 
423  // symmetrize B's
424  for ( Size atm=1; atm <= pose.residue(res).natoms(); ++atm) {
425  pdb_info_target->temperature( res, atm, pdb_info_src->temperature( res, atm ) );
426  }
427  }
428  // rebuild pdb2pose
429  pdb_info_target->rebuild_pdb2pose();
430 
431  // copy header and remark lines
432  if(pdb_info_src->header_information()){
433  pdb_info_target->header_information( new io::pdb::HeaderInformation(*pdb_info_src->header_information() ));
434  }
435  pdb_info_target->remarks( pdb_info_src->remarks() );
436 }
437 
438 
439 
440 // @details setting the movemap to only allow for symmetrical dofs.
441 // Jumps information is discarded and dof information in symmetry_info
442 // object is used instead
443 void
445  pose::Pose const & pose,
446  kinematics::MoveMap & movemap
447 )
448 {
449  using namespace core::conformation::symmetry;
450 
451  runtime_assert( is_symmetric( pose ) );
452  SymmetricConformation const & symm_conf (
453  dynamic_cast<SymmetricConformation const & > ( pose.conformation()) );
454  SymmetryInfoCOP symm_info( symm_conf.Symmetry_Info() );
455 
456  // allow only one subunit to change chi and torsions
457  for ( Size i=1; i<= pose.conformation().size(); ++i ) {
458  if ( !symm_info->bb_is_independent( i ) ) {
459  movemap.set_bb ( i,false );
460  movemap.set_chi( i, false );
461  }
462  }
463 
464  // get number of non-VRT reses
465  int numNonVrt = symm_info->num_total_residues_without_pseudo();
466 
467  // use the dof information in the symmetry_info object set allowed rb
468  // dofs
469  std::map< Size, SymDof > dofs ( symm_info->get_dofs() );
470 
471  std::map< Size, SymDof >::iterator it;
472  std::map< Size, SymDof >::iterator it_begin = dofs.begin();
473  std::map< Size, SymDof >::iterator it_end = dofs.end();
474 
475  // first find out whether we have any allowed jumps. we just need to
476  // find one jump that is true to know that set_jump have been set to
477  // true
478  kinematics::MoveMapOP movemap_in ( new kinematics::MoveMap( movemap ) );
479 
480  //fpd only let THETA and D move in master subunit
481  if ( movemap.get( core::id::THETA ) ) {
482  movemap.set( core::id::THETA , false );
483  for ( Size i=1; i<= pose.conformation().size(); ++i ) {
484  if ( symm_info->bb_is_independent( i ) ) {
485  int const n_atoms( pose.residue(i).natoms() );
486  for ( int j=1; j<=n_atoms; ++j ) {
487  id::DOF_ID id( id::AtomID(j,i) ,id::THETA );
488  if ( id.valid() && pose.has_dof(id) )
489  movemap.set( id, true );
490  }
491  }
492  }
493  }
494  if ( movemap.get( core::id::D ) ) {
495  movemap.set( core::id::D , false );
496  for ( Size i=1; i<= pose.conformation().size(); ++i ) {
497  if ( symm_info->bb_is_independent( i ) ) {
498  int const n_atoms( pose.residue(i).natoms() );
499  for ( int j=1; j<=n_atoms; ++j ) {
500  id::DOF_ID id( id::AtomID(j,i) ,id::D );
501  if ( id.valid() && pose.has_dof(id) )
502  movemap.set( id, true );
503  }
504  }
505  }
506  }
507 
508 
509 
510  // First set all jump to false
511  movemap.set_jump(false);
512 
513  // Allow internal jumps to move (if allowed in movemap_in
514  // ... allow it to move if it is in the controlling subunit
515  // ... otherwise, it can't move
516  for (int jump_nbr = 1; jump_nbr <= (int)pose.num_jump(); ++jump_nbr) {
517  int upstream_resid = pose.fold_tree().upstream_jump_residue (jump_nbr);
518  int downstream_resid = pose.fold_tree().downstream_jump_residue (jump_nbr);
519  if ( upstream_resid <= numNonVrt && downstream_resid <= numNonVrt &&
520  symm_info->bb_is_independent(upstream_resid) && symm_info->bb_is_independent(downstream_resid) ) {
521  bool jump_move( movemap_in->get_jump( jump_nbr ) );
522  for ( Size i = X_DOF; i <= Z_ANGLE_DOF; ++i ) {
523  id::DOF_ID const & id( pose.conformation().dof_id_from_torsion_id(id::TorsionID(jump_nbr,id::JUMP,i)));
524  if ( jump_move || movemap_in->get( id ) ) {
525  movemap.set( id, true );
526  }
527  }
528  //TR << "Setting internal jump (" << upstream_resid << "->" << downstream_resid
529  // << ") to " << movemap_in->get_jump(jump_nbr) << std::endl;
530  }
531  }
532 
533  // Then allow only dofs according to the dof information
534  for ( it = it_begin; it != it_end; ++it ) {
535  int jump_nbr ( (*it).first );
536  SymDof dof( (*it).second );
537 
538  //bool jump_move( false );
539  bool jump_move( movemap_in->get_jump( jump_nbr ) );
540  for ( Size i = X_DOF; i <= Z_ANGLE_DOF; ++i ) {
541  id::DOF_ID const & id
543  jump_move |= movemap_in->get( id );
544  }
545  if ( !jump_move ) {
546  continue;
547  }
548 
549  if ( dof.allow_dof( X_DOF ) ) {
550  id::DOF_ID const & id
552  movemap.set( id, true );
553  //std::cout << "make symmetric movemap: " << jump_nbr << " X_DOF jump is allowed" << std::endl;
554 
555  }
556  if ( dof.allow_dof( Y_DOF ) ) {
557  id::DOF_ID const & id
559  movemap.set( id, true );
560  //std::cout << "make symmetric movemap: " << jump_nbr << " Y_DOF jump is allowed" << std::endl;
561  }
562  if ( dof.allow_dof( Z_DOF ) ) {
563  id::DOF_ID const & id
565  movemap.set( id, true );
566  //std::cout << "make symmetric movemap: " << jump_nbr << " Z_DOF jump is allowed" << std::endl;
567  }
568  if ( dof.allow_dof( X_ANGLE_DOF ) ) {
569  id::DOF_ID const & id
571  movemap.set( id, true );
572  //std::cout << "make symmetric movemap: " << jump_nbr << " X_ANGLE_DOF jump is allowed" << std::endl;
573  }
574  if ( dof.allow_dof( Y_ANGLE_DOF ) ) {
575  id::DOF_ID const & id
577  movemap.set( id, true );
578  //std::cout << "make symmetric movemap: " << jump_nbr << " Y_ANGLE_DOF jump is allowed" << std::endl;
579  }
580  if ( dof.allow_dof( Z_ANGLE_DOF ) ) {
581  id::DOF_ID const & id
583  movemap.set( id, true );
584  //std::cout << "make symmetric movemap: " << jump_nbr << " Z_ANGLE_DOF jump is allowed" << std::endl;
585  }
586  }
587 }
588 
589 // @details find the anchor residue in the first subunit. This function assumes that the
590 // fold tree is rooted at the first jump from a virtual to its subunit
591 /*int
592 find_symmetric_basejump_anchor( pose::Pose & pose )
593 {
594  kinematics::FoldTree const & f = pose.conformation().fold_tree();
595  kinematics::FoldTree::const_iterator it=f.begin();
596  assert ( it->is_jump() );
597  return it->stop();
598 }*/
599 // @details find the anchor residue in the first subunit. This function assumes that
600 // there is only one one jump between a subunit and a virtual and that the subunit is
601 // folded downstream to the virtual
602 int
604 {
605  kinematics::FoldTree const & f = pose.conformation().fold_tree();
606  for ( int i = 1; f.num_jump(); ++i ) {
607  if ( pose.residue( f.downstream_jump_residue(i) ).name() != "VRT" &&
608  pose.residue( f.upstream_jump_residue(i) ).name() == "VRT" )
609  return f.downstream_jump_residue(i);
610  }
611  utility_exit_with_message( "No anchor residue is found..." );
612  return 0;
613 }
614 
615 // @ details move the anchor residue of a symmetric system. This function moves the anchors from
616 // virtual residues that define the coordinate system to the subunits. Useful during fragment insertion
617 // make sure to call rotate_to_x after this step so that the anchor moves correctly in the coordinate
618 // system defined by the virtual. The new anchor point is selected randomly or is selected as the point
619 // where the chains are closest together
620 void
622 {
623  using namespace core::conformation::symmetry;
624 
625  runtime_assert( is_symmetric( pose ) );
626  SymmetricConformation & symm_conf (
627  dynamic_cast<SymmetricConformation & > ( pose.conformation()) );
628  SymmetryInfoCOP symm_info( symm_conf.Symmetry_Info() );
629 
630  Size nres_subunit ( symm_info->num_independent_residues() );
631  Size anchor_start ( pose::symmetry::find_symmetric_basejump_anchor( pose ) );
632 
633  //Looking in central half of each segment -- pick a random point.
634  Size anchor = static_cast<Size>( RG.uniform() * (nres_subunit/2) ) +
635  (nres_subunit/4) + 1;
636 
637  if ( basic::options::option[ basic::options::OptionKeys::fold_and_dock::set_anchor_at_closest_point ] )
638  {
639  //Find Closest point of contact.
640  core::Real mindist = pose.residue(anchor).xyz("CEN").distance( pose.residue(anchor + nres_subunit).xyz("CEN") );
641  for (Size i = 1; i <= nres_subunit; i++) {
642  Size const j = i + nres_subunit;
643  core::Real dist = pose.residue(i).xyz("CEN").distance( pose.residue(j).xyz("CEN") );
644  if ( dist < mindist ){
645  mindist = dist;
646  anchor = i;
647  }
648  }
649  }
650 
651  // Update the fold tree with the new jump points
653 
654  // Setyp the lists of jumps and cuts
655  Size num_jumps( f.num_jump() );
656  Size num_cuts( f.num_cutpoint() );
657 
658  utility::vector1< int > cuts_vector( f.cutpoints() );
659  ObjexxFCL::FArray1D_int cuts( num_cuts );
660  ObjexxFCL::FArray2D_int jumps( 2, num_jumps );
661 
662  // Initialize jumps
663  for ( Size i = 1; i<= num_jumps; ++i ) {
664  int down ( f.downstream_jump_residue(i) );
665  int up ( f.upstream_jump_residue(i) );
666  if ( down < up ) {
667  jumps(1,i) = down;
668  jumps(2,i) = up;
669  } else {
670  jumps(1,i) = up;
671  jumps(2,i) = down;
672  }
673  }
674 
675  for ( Size i = 1; i<= num_cuts; ++i ) {
676  cuts(i) = cuts_vector[i];
677  }
678 
679  // anchor is always in first subunit. We need to convert it to the controlling subunit.
680  if ( symm_info->bb_follows( anchor ) != 0 ) {
681  //Size diff = symm_info->bb_follows( anchor_start ) - anchor_start;
682  //anchor_start = symm_info->bb_follows( anchor_start );
683  //anchor += diff;
684  anchor = symm_info->bb_follows( anchor );
685  }
686 
687  // This is the basejump
688  int root ( f.root() );
689  int const jump_number ( f.get_jump_that_builds_residue( anchor_start ) );
690  int residue_that_builds_anchor( f.upstream_jump_residue( jump_number ) );
691 
692  jumps(1, jump_number ) = anchor;
693  jumps(2, jump_number ) = residue_that_builds_anchor;
694 
695  bool try_assert ( true );
696  if ( symm_info->bb_follows( anchor_start ) != 0 ) {
697  anchor_start = symm_info->bb_follows( anchor_start );
698  try_assert = false;
699  }
700 
701  for ( std::vector< Size>::const_iterator
702  clone = symm_info->bb_clones( anchor_start ).begin(),
703  clone_end = symm_info->bb_clones( anchor_start ).end();
704  clone != clone_end; ++clone ) {
705  int jump_clone ( f.get_jump_that_builds_residue( *clone ) );
706  int takeoff_pos ( f.upstream_jump_residue( jump_clone ) );
707  int new_anchor ( anchor - anchor_start + *clone );
708  if ( try_assert ) runtime_assert( jumps(1,jump_clone) == int( *clone ) && jumps(2,jump_clone) == takeoff_pos );
709  jumps(1, jump_clone ) = new_anchor;
710  jumps(2, jump_clone ) = takeoff_pos;
711  //std::cout<<"new_anchor "<<new_anchor<< " " <<anchor<<" "<<anchor_start<<" "<< takeoff_pos <<std::endl;
712  }
713  /* debug
714  std::cout<<"cuts ";
715  for ( Size i = 1; i<= num_cuts; ++i ) {
716  std::cout<< cuts(i) << ' ';
717  }
718  std::cout<<std::endl;
719  std::cout<<"jumps ";
720  for ( Size i = 1; i<= num_jumps; ++i ) {
721  std::cout<< " ( "<<jumps(1,i) << " , " << jumps(2,i) << " ) ";
722  }
723  std::cout<<std::endl;
724  */
725  f.tree_from_jumps_and_cuts( pose.conformation().size(), num_jumps, jumps, cuts );
726  f.reorder( root );
727  pose.conformation().fold_tree( f );
728 }
729 
730 // @details this function rotates a anchor residue to the x-axis defined by the virtual residue
731 // at the root of the fold tree. It is necessary that the anchor is placed in the coordinate system
732 // of the virtual residue so that rigid body movers and minimization code moves in the correct direction
733 void
735 
736  //first anchor point -- assume its the first jump.
737  kinematics::FoldTree f( pose.fold_tree() );
738  int anchor ( find_symmetric_basejump_anchor( pose ) );
739  int const jump_number ( f.get_jump_that_builds_residue( anchor ) );
740  int coordsys_residue( f.upstream_jump_residue( jump_number ) );
741  //Where is this stupid anchor point now?
742  Vector anchor_pos ( pose.residue( anchor ).xyz("CA") );
743  float theta = std::atan2( anchor_pos(2), anchor_pos(1) );
744 
745  // we should make sure that the residue type is VRT
746  runtime_assert( pose.residue( coordsys_residue ).name() == "VRT" );
747  Vector x_axis( pose.residue( coordsys_residue ).xyz("X") - pose.residue( coordsys_residue ).xyz("ORIG") );
748  Vector y_axis( pose.residue( coordsys_residue ).xyz("Y") - pose.residue( coordsys_residue ).xyz("ORIG") );
749 
750  Vector z_axis( x_axis );
751  z_axis.normalize();
752  Vector y_axis_nrml( y_axis );
753  y_axis_nrml.normalize();
754  z_axis = z_axis.cross( y_axis_nrml );
755  z_axis.normalize();
756 
757 
758  numeric::xyzMatrix< Real > coordsys_rot ( numeric::xyzMatrix< Real >::rows( x_axis, y_axis, z_axis ) );
759  // make sure it is a rotation matrix
760  runtime_assert( std::abs( coordsys_rot.det() - 1.0 ) < 1e-6 );
761 
762  // initialize a rotation matrix that rotates the anchor to cartesian x
763  numeric::xyzMatrix< Real > z_rot = numeric::z_rotation_matrix_degrees(
764  ( -1.0 * numeric::conversions::to_degrees( theta ) ) );
765 
766  kinematics::Jump base_jump( pose.jump( jump_number ) );
767  // rotate around absolute x
768  Vector center(0,0,0);
769  // Find the stub
770  core::kinematics::Stub upstream_stub = pose.conformation().upstream_jump_stub( jump_number );
771  // rotate to cartesian x, then rotate to the coordinate system defined by the virtual residue
772  base_jump.rotation_by_matrix( upstream_stub, center, coordsys_rot.transpose()*z_rot );
773  // set the jump
774  pose.set_jump( jump_number, base_jump );
775  // The convention is to place the subunit so that it has positive x values for slide moves to
776  // go in the right direction. Silly!!!
777  Vector new_anchor_pos ( pose.residue( anchor ).xyz("CA") );
778 // std::cout << "before: " << anchor_pos(1) << " " << anchor_pos(2) << " " << anchor_pos(3) << std::endl
779 // << "after: " << new_anchor_pos(1) << " " << new_anchor_pos(2) << " " << new_anchor_pos(3) << std::endl;
780  if ( new_anchor_pos(1) < 0 ) {
781  upstream_stub = pose.conformation().upstream_jump_stub( jump_number );
782  numeric::xyzMatrix< Real > twofold = numeric::z_rotation_matrix_degrees( 180.0 );
783  base_jump.rotation_by_matrix( upstream_stub, center, twofold );
784  pose.set_jump( jump_number, base_jump );
785  }
786 }
787 
788 // a couple functions to transform between symmetric and asymmetric foldtrees
789 // these do not require the symm data
790 void
793 }
794 
795 void
798 }
799 
800 // symmetry-aware version of FoldTree::partition_by_jump(). Accepts multiple jumps.
801 // "floodfills" from root, not crossing any of the input jumps
802 void
804  utility::vector1< int > jump_numbers,
805  core::kinematics::FoldTree const & ft,
807  ObjexxFCL::FArray1D_bool & partner1
808 ) {
809  using namespace core::kinematics;
810 
811  // expand jumps to include jump clones
812  Size njumps = jump_numbers.size();
813  for (int i=1; i<=njumps; ++i) {
814  utility::vector1< Size > clones_i = symm_info->jump_clones( jump_numbers[i] );
815  for (int j=1; j<= clones_i.size(); ++j) {
816  jump_numbers.push_back( clones_i[j] );
817  }
818  }
819 
820  //int const pos1( ft.root() );
821  int pos1;
822  for (int i=1; i<=symm_info->num_total_residues_without_pseudo(); ++i) {
823  if (symm_info->bb_is_independent(i)) {
824  pos1 = i;
825  break;
826  }
827  }
828 
829  partner1 = false;
830  partner1( pos1 ) = true;
831 
832  bool new_member ( true );
833  std::vector< Edge >::const_iterator it_begin( ft.begin() );
834  std::vector< Edge >::const_iterator it_end ( ft.end() );
835 
836  while ( new_member ) { // keep adding new members
837  new_member = false;
838  for ( std::vector< Edge >::const_iterator it = it_begin; it != it_end; ++it ) {
839  if ( std::find ( jump_numbers.begin(), jump_numbers.end(), it->label() ) != jump_numbers.end() ) continue;
840 
841  int const start( std::min( it->start(), it->stop() ) );
842  int const stop ( std::max( it->start(), it->stop() ) );
843  if ( (partner1( start ) && !partner1( stop )) ||
844  (partner1( stop ) && !partner1( start )) ) {
845  new_member = true;
846  if ( it->is_polymer() ) {
847  // all the residues
848  for ( int i=start; i<= stop; ++i ) {
849  partner1( i ) = true;
850  }
851  } else {
852  // just the vertices
853  partner1( start ) = true;
854  partner1( stop ) = true;
855  }
856  }
857  }
858  }
859 }
860 
861 
862 // find symmetry axis
863 // returns <0,0,0> if:
864 // system is nonsymmetric
865 // dimer symmetry
868  if( !is_symmetric( pose ) ) return numeric::xyzVector< core::Real >(0,0,0);
869 
871  dynamic_cast<conformation::symmetry::SymmetricConformation const & > ( pose.conformation() ) );
872  conformation::symmetry::SymmetryInfoCOP symm_info( symm_conf.Symmetry_Info() );
873 
874  // find first independent residue
875  core::Size base = 1;
876  for ( Size i=1; i <=symm_info->num_total_residues_with_pseudo(); ++i ){
877  if (symm_info->bb_is_independent(i)) {
878  base = i;
879  break;
880  }
881  }
882 
883  // find clones
884  utility::vector1< core::Size > base_clones = symm_info->bb_clones( base );
885  if (base_clones.size() <= 1)
886  return numeric::xyzVector< core::Real >(0,0,0);
887 
888  // base_clones >= 2
889  numeric::xyzVector< core::Real > X = pose.residue(base_clones[1]).xyz(1) - pose.residue(base).xyz(1);
890  numeric::xyzVector< core::Real > Y = pose.residue(base_clones[2]).xyz(1) - pose.residue(base).xyz(1);
891  return X.cross( Y ).normalize();
892 }
893 
894 void
896  if( !is_symmetric( p ) ) return;
897 
899  dynamic_cast<conformation::symmetry::SymmetricConformation const & > ( p.conformation() ) );
901  // Size nres_subunit ( symm_info->num_independent_residues() );
902  // Size nsubunits ( symm_info->subunits() );
903 
904  runtime_assert( symm_info->num_total_residues_with_pseudo() == msk.size() );
905 
906  for (core::Size i=1; i<= msk.size(); ++i) {
907  bool msk_i=msk[i];
908  if (msk_i && !symm_info->fa_is_independent( i )) {
909  msk[i] = false;
910  msk[ symm_info->bb_follows( i ) ] = true;
911  }
912  }
913 }
914 
915 // Remove internal subunit jumps and cuts and create a fold tree that only has the symmetric
916 // jump framework
919  if( !is_symmetric( pose ) ) {
920  TR.Error << "sealed_symmetric_fold_tree called with assymetric fold tree. Return FoldTree" << std::endl;
921  return pose.fold_tree();
922  }
923 
924  kinematics::FoldTree f_orig = pose.fold_tree();
925  kinematics::FoldTree f = f_orig;
926  //TR.Error << "sealed_symmetric_fold_tree called with " << f_orig << std::endl;
927 
929  dynamic_cast<conformation::symmetry::SymmetricConformation const & > ( pose.conformation() ) );
931  Size nres_subunit ( symm_info->num_independent_residues() );
932 
933  // mjo commenting out 'nsubunits' because it is not used and casus a warning
934  //Size nsubunits ( symm_info->subunits() );
935  Size num_nonvrt = symm_info->num_total_residues_without_pseudo();
936 
937  // 1 - Get monomer jumps, cuts, and anchor
938 
939  // mjo commenting out 'new_anchor' because it is not used and causes a warning
940  //Size new_anchor = 0;
941  utility::vector1< Size > new_cuts;
943 
944  utility::vector1< int > cuts_vector( f_orig.cutpoints() );
945 
946  // 2 - Get symmetic jumps cuts and anchor
947  // inter-VRT jumps
948  for ( Size i = 1; i<= f_orig.num_jump(); ++i ) {
949  Size down ( f_orig.downstream_jump_residue(i) );
950  Size up ( f_orig.upstream_jump_residue(i) );
951  // connections between VRTs are unchanged
952  if ( up > num_nonvrt && down > num_nonvrt) {
953  new_jumps.push_back( std::pair<Size,Size>(up,down) );
954  }
955  // jumps to anchor
956  if ( up > num_nonvrt && down <= num_nonvrt) {
957  new_jumps.push_back( std::pair<Size,Size>( up, down ) );
958  }
959  // jumps from anchor
960  if ( up <= num_nonvrt && down > num_nonvrt) {
961  new_jumps.push_back( std::pair<Size,Size>( up, down ) );
962  }
963  }
964 
965  // cuts
966  cuts_vector = f_orig.cutpoints();
967  for ( Size i = 1; i<=cuts_vector.size(); ++i ) {
968  // cuts between vrts and jumps between chains
969  if ( cuts_vector[i] >= (int) num_nonvrt || cuts_vector[i]%nres_subunit == 0 )
970  new_cuts.push_back( cuts_vector[i] );
971  }
972 
973  // 3 - put them in FArrays
974  ObjexxFCL::FArray1D_int cuts( new_cuts.size() );
975  ObjexxFCL::FArray2D_int jumps( 2, new_jumps.size() );
976  // Initialize jumps
977  for ( Size i = 1; i<= new_jumps.size(); ++i ) {
978  jumps(1,i) = std::min( (int)new_jumps[i].first, (int)new_jumps[i].second);
979  jumps(2,i) = std::max( (int)new_jumps[i].first, (int)new_jumps[i].second);
980  // DEBUG -- PRINT JUMPS AND CUTS
981  //TR.Error << " jump " << i << " : " << jumps(1,i) << " , " << jumps(2,i) << std::endl;
982  }
983  for ( Size i = 1; i<= new_cuts.size(); ++i ) {
984  cuts(i) = (int)new_cuts[i];
985  // TR.Error << " cut " << i << " : " << cuts(i) << std::endl;
986  }
987 
988  // 4 make the sealed foldtree
989  f.clear();
990  f.tree_from_jumps_and_cuts( pose.total_residue(), new_jumps.size(), jumps, cuts, f_orig.root(), false );
991  return f;
992 }
993 
994 // @brief given a symmetric pose and a jump number, get_sym_aware_jump_num
995 // translates the jump number into the corresponding SymDof so that the
996 // symmetric pose can moved moved appropriately.
997 int
998 get_sym_aware_jump_num ( core::pose::Pose const & pose, int jump_num ) {
999  using namespace core::conformation::symmetry;
1000  int sym_jump = jump_num;
1003  std::map<Size,SymDof> dofs = sym_info->get_dofs();
1004  sym_jump = 0;
1005  Size jump_counter = 0;
1006 
1007  for(std::map<Size,SymDof>::iterator i = dofs.begin(); i != dofs.end(); i++) {
1008  //fpd if slide moves are not allowed on this jump, then skip it
1009  if (!i->second.allow_dof(1) && !i->second.allow_dof(2) && !i->second.allow_dof(3)) continue;
1010  if (++jump_counter == jump_num) {
1011  sym_jump = i->first;
1012  break;
1013  }
1014  }
1015  if (sym_jump == 0) {
1016  TR.Error << "Failed to find sym_dof with index " << jump_num << std::endl;
1017  utility_exit_with_message("Symmetric slide DOF "" not found!");
1018  }
1019  }
1020  return sym_jump;
1021 } // get_symdof_from_jump_num
1022 
1023 
1026  using namespace core::conformation::symmetry;
1029  std::map<Size,SymDof> dofs = syminfo->get_dofs();
1030  for(std::map<Size,SymDof>::iterator i = dofs.begin(); i != dofs.end(); i++) {
1031  names.push_back(syminfo->get_jump_name(i->first));
1032  }
1033  return names;
1034 }
1035 
1036 int
1037 sym_dof_jump_num(core::pose::Pose const & pose, std::string const & jname){
1038  return core::pose::symmetry::symmetry_info(pose)->get_jump_num(jname);
1039 }
1040 
1042 get_symdof_subunits(core::pose::Pose const & pose, std::string const & jname){
1043  using namespace core::conformation::symmetry;
1046  SymmetryInfo const & sym_info = *core::pose::symmetry::symmetry_info(pose);
1047  int jnum = sym_dof_jump_num(pose,jname);
1048  ObjexxFCL::FArray1D_bool partition;
1049  pose.fold_tree().partition_by_jump(jnum,partition);
1050  for(Size i = 1; i <= sym_info.num_total_residues_without_pseudo(); i+=sym_info.get_nres_subunit()){
1051  if(partition(i)){
1052  subs.push_back( sym_info.subunit_index(i) );
1053  std::cout << subs.back() << std::endl;
1054  }
1055  }
1056  } else {
1057  utility_exit_with_message("pose not symmetric!");
1058  }
1059  return subs;
1060 }
1061 
1063  return symmetry_info(pose)->get_components().size()==1;
1064 }
1066  return symmetry_info(pose)->get_components().size()>=2;
1067 }
1068 
1070  return symmetry_info(pose)->get_component_lower_bound(c);
1071 }
1073  return symmetry_info(pose)->get_component_upper_bound(c);
1074 }
1076  return symmetry_info(pose)->get_component_of_residue(ir);
1077 }
1079  return symmetry_info(pose)->get_subunit_name_to_component(vname);
1080 }
1082  return symmetry_info(pose)->get_jump_name_to_components(jname);
1083 }
1085  return symmetry_info(pose)->get_jump_name_to_subunits(jname);
1086 }
1087 
1088 } // symmetry
1089 } // pose
1090 } // core