Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
SegmentInsert.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 protocols/forge/build/SegmentInsert.cc
11 /// @brief insert an external segment flanked by new regions
12 /// @author Yih-En Andrew Ban (yab@u.washington.edu)
13 
14 // unit headers
16 
17 // package headers
21 
22 // project headers
23 #include <core/id/AtomID.hh>
24 #include <core/id/TorsionID.hh>
25 #include <core/id/types.hh>
26 
33 #include <core/pose/PDBInfo.hh>
34 #include <basic/Tracer.hh>
35 
36 // numeric headers
37 #include <numeric/random/random.hh>
38 
40 #include <utility/vector1.hh>
41 
42 
43 
44 namespace protocols {
45 namespace forge {
46 namespace build {
47 
48 
49 // static for this file
50 static numeric::random::RandomGenerator RG( 101381274 ); // magic number, don't change
51 static basic::Tracer TR( "protocols.forge.build.SegmentInsert" );
52 
53 
54 /// @brief default constructor
56  Super()
57 {}
58 
59 
60 /// @brief sec.struct only constructor (poly-ala for flanking regions)
61 /// @param[in] interval The interval between which the insert will span.
62 /// To perform a pure insertion without replacing any residues
63 /// within a region, use an interval with a zero as the left endpoint, e.g.
64 /// [0, insert_after_this_residue]. If inserting before the first residue
65 /// of the Pose then interval = [0,0]. If inserting after the last residue
66 /// of the Pose then interval = [0, last_residue].
67 /// @param[in] ss The secondary structure specifying the flanking regions,
68 /// with a character '^' specifying where the insert is to be placed.
69 /// @param[in] insert The Pose to insert.
70 /// @param[in] keep_known_bb_torsions_at_junctions Attempt to keep the omega
71 /// at original_interval().left-1, the phi at original_interval().left, and
72 /// the psi+omega at original_interval().right present from the original Pose
73 /// in the modified Pose. This should be false for pure insertions.
74 /// @param[in] connection_scheme Connect insertion on its N-side, C-side,
75 /// or decide randomly between the two (default RANDOM).
77  Interval const & i,
78  String const & ss,
79  Pose const & insert,
80  bool const keep_known_bb_torsions_at_junctions,
81  SegmentInsertConnectionScheme::Enum connection_scheme
82 ) :
83  Super( i, &insert.residue( 1 ).residue_type_set() ),
84  interval_( i ),
85  ss_( ss ),
86  keep_known_bb_torsions_at_junctions_( keep_known_bb_torsions_at_junctions ),
87  insert_connection_scheme_( connection_scheme ),
88  insert_pose_( insert )
89 {
90  // construct the poly-ala a.a. string w/ insertion point
91  for ( Size i = 0, ie = ss_.length(); i < ie; ++i ) {
92  if ( ss.at( i ) != insertion_char() ) {
93  aa_.push_back( 'A' );
94  } else {
95  aa_.push_back( insertion_char() );
96  }
97  }
98 
99  // safety
101  TR.Warning << "keep_known_bb_torsions_at_junctions set to True, but performing pure insertion, so forcing the setting to False" << std::endl;
103  }
104 
105  init();
106 }
107 
108 
109 /// @brief sec.struct + aa constructor
110 /// @param[in] interval The interval between which the insert will span.
111 /// To perform a pure insertion without replacing any residues
112 /// within a region, use an interval with a zero as the left endpoint, e.g.
113 /// [0, insert_after_this_residue]. If inserting before the first residue
114 /// of the Pose then interval = [0,0]. If inserting after the last residue
115 /// of the Pose then interval = [0, last_residue].
116 /// @param[in] ss The secondary structure specifying the flanking regions,
117 /// with a character '^' specifying where the insert is to be placed.
118 /// @param[in] aa The annotated amino acid string specifying the flanking
119 /// regions, with a character '^' specifying where the insert is to be
120 /// placed.
121 /// @param[in] insert The Pose to insert.
122 /// @param[in] keep_known_bb_torsions_at_junctions Attempt to keep the omega
123 /// at original_interval().left-1, the phi at original_interval().left, and
124 /// the psi+omega at original_interval().right present from the original Pose
125 /// in the modified Pose. This should be false for pure insertions.
126 /// @param[in] connection_scheme Connect insertion on its N-side, C-side,
127 /// or decide randomly between the two (default RANDOM).
128 /// @remarks length of the *one-letter* aa must equal the length of ss
130  Interval const & i,
131  String const & ss,
132  String const & aa,
133  Pose const & insert,
134  bool const keep_known_bb_torsions_at_junctions,
135  SegmentInsertConnectionScheme::Enum connection_scheme
136 ) :
137  Super( i, &insert.residue( 1 ).residue_type_set() ),
138  interval_( i ),
139  ss_( ss ),
140  aa_( aa ),
141  keep_known_bb_torsions_at_junctions_( keep_known_bb_torsions_at_junctions ),
142  insert_connection_scheme_( connection_scheme ),
143  insert_pose_( insert )
144 {
145  if ( !aa.empty() ) {
146  // length and insertion point correspondence checks
147  String const one_letter_aa = core::pose::annotated_to_oneletter_sequence( aa_ );
148  runtime_assert( ss_.length() == one_letter_aa.length() );
149  runtime_assert( ss_.find( insertion_char() ) == one_letter_aa.find( insertion_char() ) );
150 
151  } else {
152 
153  // construct the poly-ala a.a. string w/ insertion point
154  for ( Size i = 0, ie = ss_.length(); i < ie; ++i ) {
155  if ( ss.at( i ) != insertion_char() ) {
156  aa_.push_back( 'A' );
157  } else {
158  aa_.push_back( insertion_char() );
159  }
160  }
161  }
162 
163  // safety
165  TR.Warning << "keep_known_bb_torsions_at_junctions set to True, but performing pure insertion, so forcing the setting to False" << std::endl;
167  }
168 
169  init();
170 }
171 
172 
173 /// @brief copy constructor
175  Super( rval ),
176  interval_( rval.interval_ ),
177  ss_( rval.ss_ ),
178  aa_( rval.aa_ ),
179  insert_connection_scheme_( rval.insert_connection_scheme_ ),
180  insert_pose_( rval.insert_pose_ ),
181  insert_pose_torsion_override_movemap_( rval.insert_pose_torsion_override_movemap_ )
182 {}
183 
184 
185 /// @brief default destructor
187 
188 
189 /// @brief copy assignment
191  if ( this != &rval ) {
192  Super::operator =( rval );
193 
194  interval_ = rval.interval_;
195  ss_ = rval.ss_;
196  aa_ = rval.aa_;
198  insert_pose_ = rval.insert_pose_;
200  }
201 
202  return *this;
203 }
204 
205 
206 /// @brief clone this object
208  return new SegmentInsert( *this );
209 }
210 
211 
212 /// @brief the pose to insert
214  return insert_pose_;
215 }
216 
217 
218 /// @brief get the absolute index of the insertion point with respect to the
219 /// flanking regions (i.e. the index inside the ss string)
220 /// @return the index, otherwise std::string::npos if not found
222  return ss_.find( insertion_char() );
223 }
224 
225 
226 /// @brief get the residue at the start of the insertion relative to the
227 /// modified interval (flanking positions are not part of the insertion!)
228 /// @return the residue position, otherwise 0 if not found
230  return interval().left + ss_.find( insertion_char() );
231 }
232 
233 
234 /// @brief get the residue at the end of the insertion relative to the
235 /// modified interval (flanking positions are not part of the insertion!)
236 /// @return the residue position, otherwise 0 if not found
238  return interval().left + ss_.find( insertion_char() ) + insert_pose_.n_residue() - 1;
239 }
240 
241 
242 /// @brief get the number of flanking residues to the left of the insertion
243 /// point
245  return ss_.find( insertion_char() );
246 }
247 
248 
249 /// @brief get the number of flanking residues to the right of the insertion
250 /// point
252  return ss_.length() - ss_.find( insertion_char() ) - 1;
253 }
254 
255 
256 /// @brief get the ss string of the flanking residues to the left of the
257 /// insertion point
259  return ss_.substr( 0, ss_.find( insertion_char() ) );
260 }
261 
262 
263 /// @brief get the ss string of the flanking residues to the right of the
264 /// insertion point
266  return ss_.substr( ss_.find( insertion_char() ) + 1 );
267 }
268 
269 
270 /// @brief get the annotated aa string of the flanking residues to the left
271 /// of the insertion point
273  return aa_.substr( 0, aa_.find( insertion_char() ) );
274 }
275 
276 
277 /// @brief get the annotated aa string of the flanking residues to the right
278 /// of the insertion point
280  return aa_.substr( aa_.find( insertion_char() ) + 1 );
281 }
282 
283 
284 /// @brief a copy of the working range of residues specifying the modified region
285 /// @details This residue range can change wrt length changes in Pose /Conformation
286 /// being watched.
288  return interval_;
289 }
290 
291 
292 /// @brief return a copy of the set of positions within the new region
293 /// that were pre-existing in the original Pose prior to modify()
294 /// @return An empty set, there are no pre-existing positions.
296  return Positions();
297 }
298 
299 
300 /// @brief return a copy of the set of positions that are "new" and did
301 /// not exist in the original Pose.
304 
305  // everything in the interval is new
306  Interval const ival = interval();
307  return closed_range( ival.left, ival.right );
308 }
309 
310 
311 /// @brief return a copy of the set of positions within the newly modified
312 /// region that has a defined conformation. E.g. existing or copied residues.
313 /// @details This set can change wrt length changes in Pose/Conformation being
314 /// watched.
317 
318  // only the insert is defined
320 }
321 
322 
323 /// @brief return a copy of the set of positions within the newly modified
324 /// region that has an undefined conformation. E.g. newly created residues.
325 /// @details This set can change wrt length changes in Pose/Conformation being
326 /// watched.
329 
330  Positions undefined;
331 
332  // the flanking regions are undefined
333  Interval const ival = interval();
334  insert_closed_range( ival.left, insertion_start_residue() - 1, undefined );
335  insert_closed_range( insertion_end_residue() + 1, ival.right, undefined );
336 
337  return undefined;
338 }
339 
340 
341 /// @brief return a copy of the MoveMap that defines the moveable/fixed
342 /// positions/dofs for this instruction
343 /// @return TO BE FILLED IN
344 /// @details This set can change wrt length changes in Pose/Conformation being
345 /// watched.
347  using core::id::BB;
348  using core::id::phi_torsion;
349  using core::id::psi_torsion;
351  using core::id::TorsionID;
352 
353  typedef MoveMap::MoveMapTorsionID MoveMapTorsionID;
354  typedef MoveMap::TorsionTypeMap TorsionTypeMap;
355  typedef MoveMap::MoveMapTorsionID_Map MoveMapTorsionID_Map;
356  typedef MoveMap::TorsionID_Map TorsionID_Map;
357 
358  MoveMap mm;
359 
360  Interval const ival = interval();
362  Interval const left_flank( ival.left, insertion.left - 1 );
363  Interval const right_flank( insertion.right + 1, ival.right );
364 
365  // If attempting to keep the backbone torsions at in the positions equivalent
366  // to the endpoints of the original interval in the original Pose, mark
367  // partially moveable backbone at fixed-flanking and flanking-insertion
368  // junction points
370  // 1. start of the left flanking region
371  mm.set( TorsionID( left_flank.left, BB, phi_torsion ), false );
372  mm.set( TorsionID( left_flank.left, BB, psi_torsion ), true );
373  mm.set( TorsionID( left_flank.left, BB, omega_torsion ), true );
374 
375  // 2. left and right endpoints of the insertion
376  mm.set( TorsionID( insertion.left, BB, phi_torsion ), true );
377  mm.set( TorsionID( insertion.left, BB, psi_torsion ), false );
378  mm.set( TorsionID( insertion.left, BB, omega_torsion ), false );
379  mm.set( TorsionID( insertion.right, BB, phi_torsion), false );
380  mm.set( TorsionID( insertion.right, BB, psi_torsion ), true );
381  mm.set( TorsionID( insertion.right, BB, omega_torsion ), true );
382 
383  // 3. end of the right flanking region
384  mm.set( TorsionID( right_flank.right, BB, phi_torsion ), true );
385  mm.set( TorsionID( right_flank.right, BB, psi_torsion ), false );
386  mm.set( TorsionID( right_flank.right, BB, omega_torsion ), false );
387 
388  } else { // all bb torsions moveable
389  mm.set_bb( left_flank.left, true );
390  mm.set_bb( insertion.left, true );
391  mm.set_bb( insertion.left, true );
392  mm.set_bb( right_flank.right, true );
393  }
394 
395  // mark fully moveable parts of left flanking region
396  for ( Size i = left_flank.left + 1; i <= left_flank.left; ++i ) {
397  mm.set_bb( i, true );
398  }
399 
400  // mark fully fixed parts of fixed insert
401  for ( Size i = insertion.left + 1, ie = insertion.right - 1; i <= ie; ++i ) {
402  mm.set_bb( i, false );
403  }
404 
405  // mark fully moveable parts of right insert
406  for ( Size i = right_flank.left, ie = right_flank.right - 1; i <= ie; ++i ) {
407  mm.set_bb( i, true );
408  }
409 
410  // Now import torsion settings in the insert_pose_torsion_override_movemap_,
411  // transferring from lowest to highest stringency.
412  Size const ridx_offset = insertion.left - 1; // residue index offset, add this to movemap settings to get proper numbering
413 
414  // TorsionType first
415  for ( TorsionTypeMap::const_iterator i = insert_pose_torsion_override_movemap().torsion_type_begin(), ie = insert_pose_torsion_override_movemap().torsion_type_end(); i != ie; ++i ) {
416  mm.set( i->first, i->second );
417  }
418 
419  // MoveMapTorsionID second
420  for ( MoveMapTorsionID_Map::const_iterator i = insert_pose_torsion_override_movemap().movemap_torsion_id_begin(), ie = insert_pose_torsion_override_movemap().movemap_torsion_id_end(); i != ie; ++i ) {
421  MoveMapTorsionID shifted_id = i->first;
422  shifted_id.first += ridx_offset;
423  assert( insertion.left <= shifted_id.first && shifted_id.first <= insertion.right );
424  mm.set( shifted_id, i->second );
425  }
426 
427  // TorsionID last
428  for ( TorsionID_Map::const_iterator i = insert_pose_torsion_override_movemap().torsion_id_begin(), ie = insert_pose_torsion_override_movemap().torsion_id_end(); i != ie ; ++i ) {
429  TorsionID shifted_id = i->first;
430  shifted_id.rsd() += ridx_offset;
431  assert( insertion.left <= shifted_id.rsd() && shifted_id.rsd() <= insertion.right );
432  mm.set( shifted_id, i->second );
433  }
434 
435  return mm;
436 }
437 
438 
439 /// @brief set a torsion (bb/chi) specific override movemap indexed wrt the insert
440 /// Pose (residue indices may only be within the range [1, insert_pose.n_residue()]
441 /// @remarks When generating the movemap(), this torsion movemap will be enforced.
442 /// Only *explicit* settings of TorsionType, MoveMapTorsionID, and TorsionID will
443 /// be honored. Implicit false settings are ignored.
445 
446  typedef MoveMap::TorsionTypeMap TorsionTypeMap;
447  typedef MoveMap::MoveMapTorsionID_Map MoveMapTorsionID_Map;
448  typedef MoveMap::TorsionID_Map TorsionID_Map;
449 
450  // run through all explicit torsion settings and make sure they're within
451  // the range [1, insert_pose_.n_residue()] and only consist of BB & CHI
452  // settings
453 
454  // TorsionTypeMap first
455  for ( TorsionTypeMap::const_iterator i = mm.torsion_type_begin(), ie = mm.torsion_type_end(); i != ie; ++i ) {
456 
457  if ( i->first != core::id::BB && i->first != core::id::CHI ) {
458  TR.Error << "ERROR: insert_pose_torsion_override_movemap() passed a MoveMap with an unhandled TorsionType setting" << std::endl;
459  runtime_assert( false );
460  }
461  }
462 
463  // MoveMapTorsionID_Map second
464  for ( MoveMapTorsionID_Map::const_iterator i = mm.movemap_torsion_id_begin(), ie = mm.movemap_torsion_id_end(); i != ie; ++i ) {
465 
466  if ( i->first.second != core::id::BB && i->first.second != core::id::CHI ) {
467  TR.Error << "ERROR: insert_pose_torsion_override_movemap() passed a MoveMap with an unhandled"
468  << " MoveMapTorsionID type at residue " << i->first.first << std::endl;
469  runtime_assert( false );
470  }
471 
472  if ( i->first.first > insert_pose_.n_residue() ) {
473  TR.Error << "ERROR: insert_pose_torsion_override_movemap() passed a MoveMap with a MoveMapTorsionID"
474  << " setting greater than the total number of residues in the insert pose at residue "
475  << i->first.first << std::endl;
476  runtime_assert( false );
477  }
478  }
479 
480  // TorsionID_Map last
481  for ( TorsionID_Map::const_iterator i = mm.torsion_id_begin(), ie = mm.torsion_id_end(); i != ie; ++i ) {
482 
483  if ( i->first.type() != core::id::BB && i->first.type() != core::id::CHI ) {
484  TR.Error << "ERROR: insert_pose_torsion_override_movemap() passed a MoveMap with an unhandled"
485  << " TorsionID type at residue " << i->first.rsd() << std::endl;
486  runtime_assert( false );
487  }
488 
489  if ( i->first.rsd() > insert_pose_.n_residue() ) {
490  TR.Error << "ERROR: insert_pose_torsion_override_movemap() passed a MoveMap with a MoveMapTorsionID"
491  << " setting greater than the total number of residues in the insert pose at residue "
492  << i->first.rsd() << std::endl;
493  runtime_assert( false );
494  }
495  }
496 
497  // set the movemap
499 }
500 
501 
502 /// @brief update indexing on residue append
504  if ( event.position < interval_.left ) {
505  //++interval_.left;
506  interval_.left += event.length_change;
507  }
508 
509  if ( event.position < interval_.right ) {
510  //++interval_.right;
511  interval_.right += event.length_change;
512  }
513 }
514 
515 
516 /// @brief update indexing on residue prepend
518  if ( event.position <= interval_.left ) {
519  //++interval_.left;
520  interval_.left += event.length_change;
521  }
522 
523  if ( event.position <= interval_.right ) {
524  //++interval_.right;
525  interval_.right += event.length_change;
526  }
527 }
528 
529 
530 /// @brief update indexing on residue delete
532  // event.position == interval.left is not caught below.
533  // It has context dependent consequences and is manually corrected for
534  // during modify().
535  if ( event.position < interval_.left ) { // left
536  //--interval_.left;
537  if( int(interval_.left) + event.length_change < int(event.position) ) interval_.left = event.position;
538  else interval_.left += event.length_change;
539  }
540 
541  if ( event.position < interval_.right ) { // right
542  //--interval_.right;
543  if( int(interval_.right) + event.length_change < int(event.position) ) interval_.right = event.position;
544  else interval_.right += event.length_change;
545  }
546 }
547 
548 
549 /// @brief return the set of positions within the original interval that
550 /// will be kept in this BuildInstruction
551 /// @return An empty set -- no positions are kept.
553  return Positions();
554 }
555 
556 
557 /// @brief return set of positions within the original interval that will
558 /// be deleted in this BuildInstruction
559 /// @return A set containing all positions in the open interval
560 /// (original.left, original.right)
564 }
565 
566 
567 /// @brief return set of any fixed positions necessary with respect to the original
568 /// interval and original Pose numbering
569 /// @remarks Used for ensuring build regions for instructions do not overlap and
570 /// so that jumps may be placed correctly.
571 /// @return empty set if no fixed positions necessary
573  Positions fixed;
574 
575  fixed.insert( original_interval().left - 1 );
576  fixed.insert( original_interval().right + 1 );
577 
578  return fixed;
579 }
580 
581 
582 /// @brief return set of any mutable positions necessary with respect to the original
583 /// interval and original Pose numbering
584 /// @remarks Used for ensuring build regions for instructions do not overlap and
585 /// so that jumps may be placed correctly.
587  // for SegmentInsert, this is the same as the original deleted positions
589 }
590 
591 
592 /// @brief do the actual work of modifying the Pose
598  using core::id::AtomID;
604 
614 
615  // there are two cases below:
616  // (1) internal insertion where the removed segment may either be continuous
617  // or have cutpoints at any position along [original.left, original.right-1]
618  // (2) boundary insertion where one of the endpoints of the removed segment
619  // is a terminus
620 
621  // are we doing an n- or c-terminal extension?
622  bool performing_n_term_insertion = false;
623  bool performing_c_term_insertion = false;
624 
625  if ( performing_pure_insertion() ) {
626  performing_n_term_insertion = original_interval().right == 0;
627  performing_c_term_insertion = original_interval().right == pose.n_residue();
628  }
629  assert( !( performing_n_term_insertion && performing_c_term_insertion ) );
630 
631  // Cache information from original structure.
632  bool left_has_lower_terminus = false;
633  bool left_has_upper_terminus = false;
634  bool right_has_lower_terminus = false;
635  bool right_has_upper_terminus = false;
636 
637  if ( !performing_n_term_insertion ) {
638 
639  Size const left_endpoint = performing_pure_insertion() ? interval_.right : interval_.left;
640  left_has_lower_terminus = pose.residue( left_endpoint ).is_lower_terminus();
641  left_has_upper_terminus = pose.residue( left_endpoint ).is_upper_terminus();
642 
643  } else { // case for fully n-terminal insertion
644  left_has_lower_terminus = true;
645  left_has_upper_terminus = false;
646  }
647 
648  if ( !performing_c_term_insertion ) {
649 
650  Size const right_endpoint = performing_pure_insertion() ? interval_.right + 1 : interval_.right;
651  right_has_lower_terminus = pose.residue( right_endpoint ).is_lower_terminus();
652  right_has_upper_terminus = pose.residue( right_endpoint ).is_upper_terminus();
653 
654  } else { // case for fully c-terminal insertion
655  right_has_lower_terminus = false;
656  right_has_upper_terminus = true;
657  }
658 
659  // If the following runtime_assert is triggered, that likely means you
660  // tried to replace the entire length of the Pose or an entire chain of
661  // a multi-chain Pose. This class currently doesn't handle those cases
662  // properly and will likely break.
663  runtime_assert( !( left_has_lower_terminus && right_has_upper_terminus ) );
664 
665  // count # cutpoints along segment [left, right)
666  Size n_cutpoints = 0;
667  if ( performing_pure_insertion() ) {
668 
669  // for pure insertion/extensions we only check the residue
670  // where the insertion will be made
671  if ( pose.fold_tree().is_cutpoint( interval_.right ) ) {
672  ++n_cutpoints;
673  }
674 
675  } else { // regular case
676 
677  for ( Size i = interval_.left; i < interval_.right; ++i ) {
678  if ( pose.fold_tree().is_cutpoint( i ) ) {
679  ++n_cutpoints;
680  }
681  }
682  }
683 
684  // save psi @ left-1 and phi @ right+1 to ensure they are set correctly
685  // and not junked after residue deletion, set to 999.0 if not applicable
686  Real const pre_psi = !( left_has_lower_terminus || left_has_upper_terminus ) && interval_.left > 1 ? pose.psi( interval_.left - 1 ) : 999.0;
687  Real const post_phi = !( right_has_lower_terminus || right_has_upper_terminus ) && interval_.right < pose.n_residue() ? pose.phi( interval_.right + 1 ) : 999.0;
688 
689  // Store omega at original_interval().left-1, phi at original_interval().left,
690  // and psi+omega at original_interval().right if user requests keeping them in
691  // the equivalent positions in the modified Pose. Set to 999.0 if not applicable.
692  //
693  // TODO: I think there might be an issue here... if keeping the known
694  // backbone torsions at the junctions, we should consider also keeping
695  // in bond lengths and bond angles surrounding the junction. That's
696  // currently not done.
697  Real left_endpoint_minus_one_omega = 999.0;
698  Real left_endpoint_phi = 999.0;
699  Real right_endpoint_psi = 999.0;
700  Real right_endpoint_omega = 999.0;
702  // on the left
703  if ( !left_has_lower_terminus && interval_.left > 1 ) {
704  left_endpoint_minus_one_omega = pose.omega( interval_.left - 1 );
705  left_endpoint_phi = pose.phi( interval_.left );
706  }
707 
708  // on the right
709  if ( !right_has_upper_terminus && interval_.right < pose.n_residue() ) {
710  right_endpoint_psi = pose.psi( interval_.right );
711  right_endpoint_omega = pose.omega( interval_.right );
712  }
713  }
714 
715  // grab residue types from aa string
719  false
720  );
721 
725  false
726  );
727 
728  // BEGIN INTERVAL SHIFT: after this point, interval_ will begin to shift due to length
729  // changes in the Pose
730 
731  if ( !( performing_n_term_insertion || performing_c_term_insertion ) ) { // internal insertion
732 
733  // Two subcases:
734  // (1) a pure insertion, no residue replacement
735  // (2) insertion + residue replacement
736  if ( !performing_pure_insertion() ) {
737  // Blow away the old segment. delete_residue_range_slow() should keep
738  // all coordinates intact, though the bond lengths/angles adjacent to
739  // the deletion might get funky. Any strange geometry should get resolved
740  // upon append/prepend of residues w/ ideal geometry below
742 
743  // At this point interval_.left should temporarily sit at left-1.
744  --interval_.left;
745  } else {
747  ++interval_.right;
748  }
749 
750  // Step 0: create a cutpoint if necessary
751  // Make a new jump only if the original segment was continuous.
752  // If the original segment had jumps anywhere along [left, right)
753  // this should imply there is already a jump connecting the left and right
754  // halves. If the jump existed somewhere in the original segment, the
755  // residue deletion should have shifted the jump to an appropriate place.
756  FoldTree ft = pose.fold_tree();
757  Size const root = ft.root();
758 
759  if ( n_cutpoints == 0 && !left_has_lower_terminus && !right_has_upper_terminus
760  && !left_has_upper_terminus && !right_has_lower_terminus
761  )
762  {
763  Size const new_jump_number = ft.new_jump( interval_.left, interval_.right, interval_.left );
764 
765  // following ensures changes in dihedral below do not shift the conformation
766  ft.jump_edge( new_jump_number ).start_atom() = "N";
767  ft.jump_edge( new_jump_number ).stop_atom() = "C";
768 
769  } else if ( n_cutpoints > 0 ) { // check/modify existing jump
770 
771  Size const jump = find_connecting_jump( interval_.left, interval_.right, ft );
772 
773  // We only do operations if there happens to be a jump defined
774  // between the segments that 'left' and 'right' live on.
775  if ( jump > 0 ) {
776 
777  Edge jump_edge = ft.jump_edge( jump );
778  ft.delete_edge( jump_edge ); // remove edge
779 
780  // next two 'if' statements ensures changes in dihedral below do
781  // not shift the conformation
782  order( jump_edge );
783 
784  if ( static_cast< Size >( jump_edge.start() ) == interval_.left ) {
785  jump_edge.start_atom() = "N";
786  } else if ( jump_edge.start_atom().empty() ) {
787  // if no existing jump atom, need to fill it in, otherwise
788  // edge will not be recognized as having specific atom
789  // settings
790  jump_edge.start_atom() = pose.residue( jump_edge.start() ).atom_name(
791  get_anchor_atomno( pose.residue( jump_edge.start() ), core::kinematics::dir_jump )
792  );
793  }
794 
795  if ( static_cast< Size >( jump_edge.stop() ) == interval_.right ) {
796  jump_edge.stop_atom() = "C";
797  } else if ( jump_edge.stop_atom().empty() ) {
798  // if no existing jump atom, need to fill it in, otherwise
799  // edge will not be recognized as having specific atom
800  // settings
801  jump_edge.stop_atom() = pose.residue( jump_edge.stop() ).atom_name(
802  get_anchor_atomno( pose.residue( jump_edge.stop() ), core::kinematics::dir_jump )
803  );
804  }
805 
806  ft.add_edge( jump_edge ); // re-add modified edge
807  }
808  }
809 
810  ft.reorder( root );
811  pose.fold_tree( ft );
812 
813  } else { // terminal insertion
814 
815  // need to manually modify the interval here for terminal insertions
816  if ( performing_n_term_insertion ) {
817  interval_.left = 1;
818  interval_.right = 1;
819  } else if ( performing_c_term_insertion ) {
820  interval_.left = pose.n_residue();
821  interval_.right = pose.n_residue();
822  }
823 
824  }
825 
826  // Step 1: perform the growing of the flanking regions not directly
827  // connected to the insertion
828  Size before_insert_point = 0;
829  if ( !left_has_lower_terminus ) { // grow towards the right
830  assert( !performing_n_term_insertion );
831 
832  if ( !r_types_flanking_left.empty() ) {
833 
834  before_insert_point = grow_right_rtype(
835  pose,
836  interval_.left,
837  r_types_flanking_left.begin(),
838  r_types_flanking_left.end()
839  );
840 
841  } else {
842  before_insert_point = interval_.left;
843  }
844  }
845 
846  Size after_insert_point = 0;
847  if ( !right_has_upper_terminus ) { // grow towards the left
848  assert( !performing_c_term_insertion );
849 
850  if ( !r_types_flanking_right.empty() ) {
851 
852  after_insert_point = grow_left_rtype(
853  pose,
855  r_types_flanking_right.rbegin(),
856  r_types_flanking_right.rend()
857  );
858 
859  } else {
860  after_insert_point = interval_.right;
861  }
862  }
863 
864  assert( !left_has_lower_terminus && !right_has_upper_terminus ? before_insert_point == after_insert_point - 1 : true );
865 
866  // Step 2: perform the insertion and perform any growing of any flanking
867  // regions directly connected to the insertion.
868  // The connection (peptide bond) between the junction of the insertion
869  // and flanking regions will temporarily be distorted. This is corrected
870  // later in the procedure.
871 
872  // figure out exactly which side the insertion will be glued to
874  if ( left_has_lower_terminus ) {
875  insert_connection_scheme = C;
876  } else if ( right_has_upper_terminus ) {
877  insert_connection_scheme = N;
878  } else { // either choice is possible
879 
880  if ( insert_connection_scheme == RANDOM_SIDE ) {
881  if ( RG.uniform() < 0.5 ) {
882  insert_connection_scheme = N;
883  } else {
884  insert_connection_scheme = C;
885  }
886  }
887 
888  }
889 
890  assert( insert_connection_scheme != RANDOM_SIDE );
891 
892  // make a copy of the residues for safety
893  ResidueOPs insert_residues;
894  for ( Size i = 1, ie = insert_pose_.n_residue(); i <= ie; ++i ) {
895  insert_residues.push_back( insert_pose_.residue( i ).clone() );
896  }
897 
898  // add the residues from the insert Pose and grow any directly connected
899  // flanking regions
900  switch ( insert_connection_scheme ) {
901  case N: {
902  Size const new_anchor = grow_right_r(
903  pose,
904  before_insert_point, insert_residues.begin(), insert_residues.end(),
905  true,
906  true // place coordinates as-is
907  );
908  if ( right_has_upper_terminus ) {
909  grow_right_rtype( pose, new_anchor, r_types_flanking_right.begin(), r_types_flanking_right.end() );
910  }
911  break;
912  }
913  case C: {
914  Size const new_anchor = grow_left_r(
915  pose,
916  after_insert_point, insert_residues.rbegin(), insert_residues.rend(),
917  true,
918  true // place coordinates as-is
919  );
920  if ( left_has_lower_terminus ) {
921  grow_left_rtype( pose, new_anchor, r_types_flanking_left.rbegin(), r_types_flanking_left.rend() );
922  }
923  break;
924  }
925  default:
926  runtime_assert( false ); // should never get here
927  }
928 
929  // finalize the interval so that it accurately reflects the new region
930  if ( performing_n_term_insertion ) {
931  interval_.left = 1;
932  --interval_.right;
933  } else if ( performing_c_term_insertion ) {
934  ++interval_.left;
935  interval_.right = pose.n_residue();
936  } else { // internal insertion {
937  ++interval_.left;
938  --interval_.right;
939  }
940 
941  assert( interval_.left < interval_.right ); // check ordering
942  assert( interval_.length() > 0 );
944 
945  // END INTERVAL SHIFT: after this point, interval_ has stabilized and stores
946  // the new endpoints of the rebuilt segment
947 
948  // pick a cutpoint and set the new topology if doing internal insertion
949  if ( !( performing_n_term_insertion || performing_c_term_insertion ) ) {
950 
951  FoldTree new_ft = pose.fold_tree();
952  Size const cutpoint = find_cutpoint( pose, interval_.left, interval_.right );
953  assert( cutpoint > 0 ); // there should be a cutpoint
954 
955  Size new_cutpoint = 0;
956  switch ( insert_connection_scheme ) {
957  case N: {
958  // must remember to avoid making cut that affects bb torsions
959  // at junction if user requests that option
960  Size const largest_possible_cut_position = keep_known_bb_torsions_at_junctions_ ? interval_.right - 1 : interval_.right;
961 
962  if ( flanking_right_nres() > 0 ) {
963  new_cutpoint = RG.random_range( interval_.right - flanking_right_nres(), largest_possible_cut_position );
964  } else { // flanking_right_nres == 0
965  new_cutpoint = interval_.right;
966  }
967  break;
968  }
969  case C: {
970  if ( flanking_left_nres() > 0 ) {
971  new_cutpoint = RG.random_range( interval_.left, interval_.left + flanking_left_nres() - 1 );
972  } else {
973  assert( interval_.left > 1 ); // safety, should never happen
974  new_cutpoint = interval_.left - 1;
975  }
976  break;
977  }
978  default:
979  runtime_assert( false ); // should never get here
980  }
981 
982  if ( new_cutpoint != cutpoint ) {
983  new_ft.slide_cutpoint( cutpoint, new_cutpoint );
984  }
985 
986  // set the new topology
987  pose.fold_tree( new_ft );
988  }
989 
990  // Handle any jumps that happen to connect to left-1 or right+1. These
991  // need to have their jump atoms altered so that the torsion changes below
992  // don't cause any rigid body shifts.
993  FoldTree ft = pose.fold_tree();
994  bool ft_was_altered = false;
995  for ( FoldTree::const_iterator e = pose.fold_tree().begin(), ee = pose.fold_tree().end(); e != ee; ++e ) {
996  if ( e->label() > 0 ) {
997  Edge tmp = *e;
998  order( tmp );
999 
1000  bool start_changed = false;
1001  if ( static_cast< Size >( tmp.start() ) == interval_.left - 1 ) {
1002  tmp.start_atom() = "N";
1003  start_changed = true;
1004  }
1005 
1006  bool stop_changed = false;
1007  if ( static_cast< Size >( tmp.stop() ) == interval_.right + 1 ) {
1008  tmp.stop_atom() = "C";
1009  stop_changed = true;
1010  }
1011 
1012  // Must set opposing atom if it's not already set, otherwise
1013  // refold procedure will not recognize this edge as having
1014  // custom jump atoms. Using default atom selection from
1015  // atom tree routines.
1016  if ( start_changed && !stop_changed && tmp.stop_atom().empty() ) {
1017  tmp.stop_atom() = pose.residue( tmp.stop() ).atom_name(
1019  );
1020  stop_changed = true;
1021  }
1022 
1023  if ( !start_changed && stop_changed && tmp.start_atom().empty() ) {
1024  tmp.start_atom() = pose.residue( tmp.start() ).atom_name(
1025  get_anchor_atomno( pose.residue( tmp.start() ), core::kinematics::dir_jump )
1026  );
1027  start_changed = true;
1028  }
1029 
1030  // re-add the edge only if the edge has been changed
1031  if ( start_changed && stop_changed ) {
1032  ft.delete_edge( *e );
1033  ft.add_edge( tmp );
1034  ft_was_altered = true;
1035  }
1036  }
1037  }
1038 
1039  if ( ft_was_altered ) {
1040  ft.reorder( pose.fold_tree().root() );
1041  pose.fold_tree( ft );
1042  }
1043 
1044  // Mark flanking regions and any existing connecting residues at left-1 and right
1045  // needing omega correction. Omega correction is not actually performed until
1046  // bond length/angle corrections are done.
1047  Size omega_left_start = 0, omega_left_end = 0;
1048  Size omega_right_start = 0, omega_right_end = 0;
1049 
1050  if ( flanking_left_nres() > 0 ) {
1051 
1052  if ( interval_.left == 1 ) {
1053  omega_left_start = interval_.left;
1054  omega_left_end = flanking_left_nres();
1055  } else {
1056  omega_left_start = interval_.left - 1; // include residue immediately -1 to interval
1057  omega_left_end = omega_left_start + flanking_left_nres();
1058  }
1059 
1060  assert( omega_left_start <= omega_left_end );
1061  }
1062 
1063  if ( flanking_right_nres() > 0 ) {
1064  omega_right_start = interval_.right - flanking_right_nres();
1065 
1066  if ( interval_.right == pose.n_residue() ) {
1067  omega_right_end = interval_.right - 1;
1068  } else {
1069  omega_right_end = interval_.right;
1070  }
1071 
1072  assert( omega_right_start <= omega_right_end );
1073  }
1074 
1075  // Correct all bond angles and lengths at junction between flanking and
1076  // insert regions. This will "rubber band snap" the insert into the right
1077  // position with existing (possibly non-ideal) internal geometry intact.
1078  switch ( insert_connection_scheme ) {
1079  case N:
1080  // always handle 'left_flanking <-> insert' junction residue, this
1081  // will never be a cutpoint
1082  if ( flanking_left_nres() > 0 ) {
1083  assert( omega_left_end > 0 );
1084  assert( !pose.fold_tree().is_cutpoint( omega_left_end ) );
1085  pose.conformation().insert_ideal_geometry_at_polymer_bond( omega_left_end );
1086  }
1087 
1088  // handle 'insert <-> right_flanking' junction residue only if not
1089  // a cutpoint
1090  if ( flanking_right_nres() > 0 ) {
1091  assert( omega_right_start > 0 );
1092  if ( !pose.fold_tree().is_cutpoint( omega_right_start ) ) {
1093  pose.conformation().insert_ideal_geometry_at_polymer_bond( omega_right_start );
1094  }
1095  }
1096 
1097  break;
1098  case C:
1099  // handle 'left_flanking <-> insert' junction residue only if not
1100  // a cutpoint
1101  if ( flanking_left_nres() > 0 ) {
1102  assert( omega_left_end > 0 );
1103  if ( !pose.fold_tree().is_cutpoint( omega_left_end ) ) {
1104  pose.conformation().insert_ideal_geometry_at_polymer_bond( omega_left_end );
1105  }
1106  }
1107 
1108  // always handle 'insert <-> right_flanking' junction residue, this
1109  // will never be a cutpoint
1110  if ( flanking_right_nres() > 0 ) {
1111  assert( omega_right_start > 0 );
1112  assert( !pose.fold_tree().is_cutpoint( omega_right_start ) );
1113  pose.conformation().insert_ideal_geometry_at_polymer_bond( omega_right_start );
1114  }
1115 
1116  break;
1117  default:
1118  runtime_assert( false ); // should never get here
1119  }
1120 
1121  // recover psi @ left-1 and phi @ right+1 to ensure they are set correctly
1122  // and not junked due to residue deletion, values set to 999.0 if not applicable
1123  if ( pre_psi <= 360.0 ) {
1124  pose.set_psi( interval_.left - 1, pre_psi );
1125  pose.set_omega( interval_.left - 1, 180.0 );
1126  }
1127  if ( post_phi <= 360.0 ) {
1128  pose.set_phi( interval_.right + 1, post_phi );
1129  }
1130 
1131  // correct all omegas for flanking regions and any existing connecting
1132  // residues at left-1 and right
1133  if ( flanking_left_nres() > 0 ) {
1134  trans_omega( omega_left_start, omega_left_end, pose );
1135  }
1136 
1137  if ( flanking_right_nres() > 0 ) {
1138  trans_omega( omega_right_start, omega_right_end, pose );
1139  }
1140 
1141  // recover old angles at junctions if requested
1143 
1144  // torsion angles
1145  if ( left_endpoint_minus_one_omega <= 360.0 ) {
1146  pose.set_omega( interval_.left - 1, left_endpoint_minus_one_omega );
1147  }
1148 
1149  if ( left_endpoint_phi <= 360.0 ) {
1150  pose.set_phi( interval_.left, left_endpoint_phi );
1151  }
1152 
1153  if ( right_endpoint_psi <= 360.0 ) {
1154  pose.set_psi( interval_.right, right_endpoint_psi );
1155  }
1156 
1157  if ( right_endpoint_omega <= 360.0 ) {
1158  pose.set_omega( interval_.right, right_endpoint_omega );
1159  }
1160 
1161  }
1162 
1163  // set the desired secondary structure across the flanking regions and the
1164  // insert
1165  String const f_l_ss = flanking_left_ss();
1166  for ( Size i = 0, ie = f_l_ss.length(); i < ie; ++i ) {
1167  pose.set_secstruct( interval_.left + i, f_l_ss.at( i ) );
1168  }
1169 
1170  String const f_r_ss = flanking_right_ss();
1171  Size r = interval_.right - f_r_ss.length() + 1;
1172  for ( Size i = 0, ie = f_r_ss.length(); i < ie; ++i, ++r ) {
1173  pose.set_secstruct( r, f_r_ss.at( i ) );
1174  }
1175 
1177  for ( Size i = 1, ie = insert_pose_.n_residue(); i <= ie; ++i, ++r ) {
1178  pose.set_secstruct( r, insert_pose_.secstruct( i ) );
1179  }
1180 
1181  // safety, make sure PDBInfo leaves obsolete
1182  if ( pose.pdb_info().get() ) {
1183  pose.pdb_info()->obsolete( true );
1184  }
1185 
1186 }
1187 
1188 
1189 /// @brief do the actual reset of intervals, positions, etc to initial state
1192 }
1193 
1194 
1195 /// @brief init to be called during non-default constructors
1199 
1200  // remove lower/upper terminus only at 1, nres
1201  if ( insert_pose_.n_residue() > 0 ) {
1202  if ( insert_pose_.residue( 1 ).is_lower_terminus() ) {
1204  }
1205 
1206  if ( insert_pose_.residue( insert_pose_.n_residue() ).is_upper_terminus() ) {
1208  }
1209  }
1210 }
1211 
1212 
1213 } // namespace build
1214 } // namespace forge
1215 } // namespace protocols