Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
AtomTree.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 core/kinematics/AtomTree.cc
11 /// @brief Atom tree class
12 /// @author Phil Bradley
13 
14 
15 // Unit headers
18 
19 // Package headers
20 // AUTO-REMOVED #include <core/kinematics/DomainMap.hh>
21 // AUTO-REMOVED #include <core/kinematics/tree/BondedAtom.hh>
22 // AUTO-REMOVED #include <core/kinematics/tree/JumpAtom.hh>
23 // AUTO-REMOVED #include <core/kinematics/util.hh>
24 
25 #include <basic/basic.hh> // periodic_range
26 #include <basic/prof.hh> // profiling
27 #include <basic/Tracer.hh> // profiling
28 
29 
30 // ObjexxFCL headers
31 #include <ObjexxFCL/FArray1D.hh>
32 // AUTO-REMOVED #include <ObjexxFCL/FArray2D.hh>
33 // AUTO-REMOVED #include <ObjexxFCL/FArray3D.hh>
34 //#include <ObjexxFCL/FArray4D.h>
35 //#include <ObjexxFCL/formatted.io.h>
36 
37 // Numeric headers
38 // AUTO-REMOVED #include <numeric/all.fwd.hh>
39 #include <numeric/constants.hh>
40 #include <numeric/conversions.hh>
41 #include <numeric/xyz.functions.hh>
42 #include <numeric/xyzMatrix.hh>
43 #include <numeric/xyzVector.hh>
44 
45 // Utility headers
46 #include <utility/assert.hh>
47 // AUTO-REMOVED #include <utility/io/orstream.hh>
48 
49 // C++ headers
50 #include <cstdlib>
51 // AUTO-REMOVED #include <cstdio>
52 
54 #include <core/kinematics/types.hh>
56 #include <utility/vector1.hh>
57 
58 
59 
60 namespace core {
61 namespace kinematics {
62 
63 static basic::Tracer TR( "core.kinematics.AtomTree" );
64 
65 /////////////////////////////////////////////////////////////////////////////
66 /// @details this will claim the tree as our own. new_root has information about its children,
67 /// and they have information about their children. From those atom positions, internal
68 /// coordinates can be updated and atom pointers will be added into the AtomTree map.
69 /// @note that we steal the atoms, ie it's incorporated into the AtomTree (by recording
70 /// their pointers),not cloned
72  AtomPointer2D const & new_atom_pointer,
73  bool const from_xyz // = true
74 ):
75  this_weak_ptr_(0),
76  root_( 0 ),
77  atom_pointer_(), // default_setting_ = null pointer
78  internal_coords_need_updating_( false ),
79  xyz_coords_need_updating_( false ),
80  topological_match_to_( 0 ),
81  external_coordinate_residues_changed_( new ResidueCoordinateChangeList )
82 {
83  replace_tree( new_atom_pointer, from_xyz );
84  external_coordinate_residues_changed_->total_residue( new_atom_pointer.size() );
85 }
86 
88  this_weak_ptr_(0),
89  root_(0),
90  atom_pointer_(),
91  internal_coords_need_updating_( false ),
92  xyz_coords_need_updating_( false ),
93  topological_match_to_( 0 ),
94  external_coordinate_residues_changed_( new ResidueCoordinateChangeList )
95 {}
96 
97 /// @brief Destructor
99 {
100  clear();
101 }
102 
103 
104 
105 /////////////////////////////////////////////////////////////////////////////
106 /// @details copy ctor, uses operator=
107 AtomTree::AtomTree( AtomTree const & src ) :
108  utility::pointer::ReferenceCount(),
109  this_weak_ptr_( 0 ),
110  root_( 0 ), /// without this initialization, the destruction of this
111  /// uninitialized pointer might have disasterous consequences
112  atom_pointer_(), // default_setting_ = null pointer
113  internal_coords_need_updating_( false ),
114  xyz_coords_need_updating_( false ),
115  topological_match_to_( 0 ),
116  external_coordinate_residues_changed_( new ResidueCoordinateChangeList )
117 {
118  *this = src;
119 }
120 
121 
123 {
124  assert( self_pointer() == this );
125  this_weak_ptr_ = self_pointer;
126 }
127 
128 
129 /**
130 /////////////////////////////////////////////////////////////////////////////
131 ///
132 ///@li update xyz or internal coord before adding this atom.
133 ///@li notify xyz or internal coord need to be updated after adding this atom.
134 ///@li if atom id2 is not in the AtomID_Map and root atom is not set, atom id1
135 /// is set as the root of the tree (the parent of the root is 0).
136 ///@li if atom id2 is in the AtomID_Map, atom id1 is added into the map either
137 /// as a bonded_atom or jump_atom and atom id2 is set as its parent.
138 ///@li Throw an error if atom id2 is not in the map and root atom is already set.
139 ///
140 void
141 AtomTree::add_atom(
142  AtomID const & id1,
143  AtomID const & id2,
144  bool const add_bonded_atom,
145  bool const from_xyz
146 )
147 {
148  if ( from_xyz ) {
149  update_xyz_coords();
150  } else {
151  update_internal_coords();
152  }
153 
154 
155  AtomOP parent(0);
156  if ( !id2.valid() || // root
157  !atom_pointer_.has( id2 ) ||
158  atom_pointer_[ id2 ] == 0 ) {
159  //
160  if ( root_ != 0 ) {
161  utility_exit_with_message("add_atom: parent not in the tree");
162  }
163  } else {
164  parent = atom_pointer_[ id2 ];
165  }
166 
167  // create the new atom
168  AtomOP atom( add_bonded_atom ?
169  static_cast< AtomOP >( new BondedAtom() ) :
170  static_cast< AtomOP >( new JumpAtom() ) );
171  atom->id( id1 );
172  atom_pointer_.set( id1, atom );
173 
174  if ( parent ) {
175  parent->append_atom( atom );
176  } else {
177  root_ = atom;
178  atom->parent( 0 );
179  }
180 
181 
182  if ( from_xyz ) {
183  internal_coords_need_updating_ = true;
184  } else {
185  xyz_coords_need_updating_ = true;
186  }
187 
188 }
189 **/
190 
191 
192 /////////////////////////////////////////////////////////////////////////////
193 void
195 {
196  root_ = 0;
197  for ( Size i=1; i<= atom_pointer_.size(); ++i ) {
198  for ( Size j=1; j<= atom_pointer_[i].size(); ++j ) {
199  assert( atom_pointer_[i][j] && atom_pointer_[i][j]->id() == AtomID( j,i ) );
200  if ( atom_pointer_[i][j]->parent() == 0 ) {
201  assert( !root_ );
202  root_ = atom_pointer_[i][j]();
203  }
204  }
205  }
206 }
207 
208 
209 /////////////////////////////////////////////////////////////////////////////
210 ///
211 /// @details fill the AtomTree with a new tree of atoms by recording their pointers in
212 /// the map. Sync internal and xyz coords.
213 void
215  AtomPointer2D const & new_atom_pointer,
216  bool const from_xyz // = true
217 )
218 {
219  clear();
220 
221  atom_pointer_ = new_atom_pointer;
222 
224 
226 
227  if ( from_xyz ) {
230 
232  } else {
235 
237  }
238 
239 
240  // anything that depends on the tree topology needs to be updated
242 }
243 
244 /**
245 void
246 AtomTree::setup_backrub_segment(
247  utility::vector1< AtomID > const & mainchain,
248  AtomID const & downstream_id, // mainchain child of last atom in mainchain vector
249  utility::vector1< std::pair< Size, Size > > const & edges,
250  Size const first_new_pseudo_residue
251 )
252 {
253 
254  // this assumes that the segment of mainchain has exactly one connection in and exactly one connection out, (to
255  // the downstream_id atom) and all of the atoms to be replaced are bonded atoms
256  //
257  for ( Size i=1; i<= mainchain.size(); ++i ) {
258  assert( !( atom_pointer_[ mainchain[i] ]->is_jump() ) );
259  }
260  AtomID const last_mainchain_id( mainchain[ mainchain.size() ] );
261  assert( atom_pointer_[ downstream_id ]->parent()->id() == last_mainchain_id );
262 
263  // operation is done "by xyz" leaving the internal coords out of date
264  update_xyz_coords();
265 
266  AtomOP subtree_root
267  ( setup_backrub_atom_tree( mainchain, downstream_id, atom_pointer_, edges, first_new_pseudo_residue ) );
268  assert( subtree_root->id() == mainchain[1] );
269 
270  AtomOP old_root( atom_pointer_[ mainchain[1] ] );
271  AtomOP anchor( old_root->parent() );
272 
273  AtomOP downstream_atom( atom_pointer_[ downstream_id ] );
274  downstream_atom->parent()->delete_atom( downstream_atom ); // delete the old outgoing connection
275 
276  // update atom_pointer_
277  subtree_root->update_atom_pointer( atom_pointer_, true );
278 
279  // insert the new tree
280  anchor->replace_atom( old_root, subtree_root ); // incoming connection
281  atom_pointer_[ last_mainchain_id ]->insert_atom( downstream_atom ); // outoing connection
282 
283  // erase the old tree
284  // this call will erase and delete all of old_root's children
285  old_root->erase();
286  // free the last bit of old data
287  delete old_root;
288 
289  internal_coords_need_updating_ = true;
290 
291 }
292 **/
293 
294 
295 /// @details This is a helper function to find a linear transform that when applied to the downstream stub
296 /// has the effect that RT( instub, transformed-downstream-stub) == target_rt
297 void
299  Stub const & stub1, // upstream stub
300  Stub const & stub2, // downstream stub
301  RT const & rt, // the target RT
302  Stub::Matrix & A,
303  Vector & b
304 )
305 {
306  Stub::Matrix const & M1( stub1.M ), M2( stub2.M ), R( rt.get_rotation() );
307  Vector const & v1( stub1.v ), v2( stub2.v ), t( rt.get_translation() );
308 
309  // look for a transformation of the form x |----> A*x + b
310  //
311  // this will change stub2 to stub2' with M2' = A * M2, v2' = A*v2 + b
312  //
313  // if we let (R,t) be the target RT, then we want
314  //
315  // R = M1^T * M2' = M1^T * A * M2 ==> A = M1 * R * M2^T
316  //
317  // t = M1^T * ( v2' - v1 ) ==> v2' = M1 * t + v1, which with b = v2' - A*v2 gives b = M1 * t + v1 - A * v2
318  //
319 
320  A = M1 * R * M2.transposed();
321  b = M1 * t + v1 - A * v2;
322 }
323 
324 
325 
326 
327 
328 /////////////////////////////////////////////////////////////////////////////
329 /// assumes one incoming and at most one outgoing
330 /// Need fancier fxn for general case
331 ///
332 void
334 {
335  Size const old_size( size() ), new_size( old_size - 1 );
336 
337  // find the anchor, root, and perhaps child atoms
338  Size const natoms( atom_pointer_[seqpos].size() );
339  AtomOP anchor(0), root(0), child(0);
340  for ( Size i=1; i<= natoms; ++i ) {
341  AtomOP atom( atom_pointer_[seqpos][i]() );
342  if ( !atom ) continue;
343  if ( Size(atom->parent()->id().rsd()) != seqpos ) {
344  assert( !anchor );
345  root = atom;
346  anchor = atom->parent();
347  // could break but debug 1 incoming connxn by continuing
348  }
349  for ( Atom::Atoms_ConstIterator iter=atom->atoms_begin(), iter_end = atom->atoms_end(); iter!= iter_end; ++iter ) {
350  if ( Size((*iter)->id().rsd()) != seqpos ) {
351  assert( !child );
352  child = *iter;
353  // could break but debug at most 1 outgoing connxn by continuing
354  }
355  }
356  }
357 
358  if ( !anchor ) {
359  utility_exit_with_message( "AtomTree::delete_seqpos can't handle deleting the root residue");
360  }
361 
362  // rewire connxns
363  if ( child ) {
364  anchor->replace_atom( root, child );
365  } else {
366  anchor->delete_atom( root );
367  }
368 
369 // // now delete atoms
370 // for ( Size i=1; i<= natoms; ++i ) {
371 // delete atom_pointer_[seqpos][i];
372 // }
373 
374  atom_pointer_[ seqpos ].resize(0);
375 
376  // now renumber
377  utility::vector1< int > old2new( old_size );
378  for ( Size i=1; i<= old_size; ++i ) {
379  if ( i < seqpos ) old2new[i] = i;
380  else if ( i == seqpos ) old2new[i] = 0;
381  else old2new[i] = i-1;
382  }
383 
384  update_sequence_numbering( new_size, old2new );
385 
386  // anything that depends on the tree topology needs to be updated
388 }
389 
390 
391 /// @note This can also handle the case of inserting a residue, proved that we've already renumbered atomtree leaving an empty slot at seqpos.
392 /// @note If the new residue contains the root of the tree, incoming.atom1 should be BOGUS_ATOM_ID
393 /// @note Note that for all BondID's atom1 should be the parent and atom2 should be the child
394 
395 /// Couple of special cases:
396 /// -- appending a residue
397 /// -- inserting a residue
398 /// -- replacing the root residue
399 /// -- inserting a new root residue
400 
401 void
403  id::BondID const & incoming,
404  utility::vector1< id::BondID > const & outgoing,
405  AtomPointer1D const & new_atoms // this will be the new slice of our atom_pointer
406 )
407 {
408  // general rule:
409  //
410  // before we set or get a type of coordinate, have to
411  // do an update
412  //
413  // in this case, we are "setting" the xyz's for the new subtree
414  // this will put the internal coords out of date, so we want to
415  // ensure that the xyz's are up to date at the start, otherwise
416  // we can end up in the disastrous situation of having both
417  // internal and xyz coords out of data -- and thus no "reference"
418  // state from which to update!
419  //
421 
422  Size const seqpos( incoming.atom2.rsd() ); // should be Size but AtomID::rsd() returns int
423  AtomPointer1D const & old_atoms( atom_pointer_[ seqpos ] );
424 
425  // confirm that bond id's go from parent to child, atom1 to atom2
426  for ( Size i=1; i<= outgoing.size(); ++i ) assert( outgoing[i].atom1.rsd() == seqpos );
427  for ( Size i=1; i<= new_atoms.size(); ++i ) assert( new_atoms[i]->id() == AtomID( i, seqpos ) );
428 
429  //
430  AtomOP anchor_atom(0);
431  AtomOP old_root_atom(0);
432  AtomOP new_root_atom( new_atoms[ incoming.atom2.atomno() ]() );
433 
434  if ( incoming.atom1.valid() ) anchor_atom = atom_pointer( incoming.atom1 );
435 
436  // rewire the outgoing connections -- these are added to new atoms in the order that they come in the outgoing list
437  // the children in these connections will all have parents in seqpos unless we are inserting into an empty slot,
438  // ie unless old_atoms.empty()
439  for ( Size i=1; i<= outgoing.size(); ++i ) {
440  AtomOP child( atom_pointer( outgoing[i].atom2 ) );
441  AtomOP old_parent( child->parent() );
442  assert( child->id().rsd() != seqpos );
443  if ( !old_parent ) {
444  // we're becoming the new root residue
445  assert( old_atoms.empty() && !incoming.atom1.valid() ); // implies anchor_atom == 0
446  assert( !old_root_atom );
447  old_root_atom = child;
448  } else if ( old_parent->id().rsd() != seqpos ) {
449  // we're inserting into a bond
450  assert( old_atoms.empty() && old_parent->id() == incoming.atom1 );
451  assert( !old_root_atom );
452  old_root_atom = child;
453  } else {
454  // only necessary for debugging purposes
455  old_parent->delete_atom( child );
456  }
457  AtomOP new_parent( new_atoms[ outgoing[i].atom1.atomno() ]() );
458  new_parent->insert_atom( child );
459  }
460 
461  // potentially have to look for old_root_atom
462  if ( old_root_atom ) {
463  assert( old_atoms.empty() );
464  } else {
465  for ( Size i=1; i<= old_atoms.size(); ++i ) {
466  AtomOP old_atom( old_atoms[i]() );
467  assert( old_atom ); // atom_pointer_ is ragged, always keep dimension equal to actual number of atoms
468  if ( ! old_atom->parent() ) {
469  // this was the root of the atomtree
470  assert( !incoming.atom1.valid() );
471  assert( !old_root_atom );
472  old_root_atom = old_atom;
473  } else if ( old_atom->parent()->id().rsd() != seqpos ) {
474  // this is the root of the old tree
475  assert( incoming.atom1 == old_atom->parent()->id() );
476  assert( !old_root_atom );
477  old_root_atom = old_atom;
478  }
479  // this is just debugging to confirm that outgoing vector actually contains all the outgoing connections
480  for ( Size i=0; i< old_atom->n_children(); ++i ) assert( old_atom->child(i)->id().rsd() == seqpos );
481  }
482  }
483 
484  // rewire the incoming connection
485  if ( anchor_atom ) {
486  if ( old_root_atom ) {
487  atom_pointer( incoming.atom1 )->replace_atom( old_root_atom, new_root_atom );
488  } else {
489  assert( outgoing.empty() && old_atoms.empty() );
490  atom_pointer( incoming.atom1 )->insert_atom( new_root_atom );
491  }
492 
493  } else {
494  assert( root_ == old_root_atom );
495  root_ = new_root_atom;
496  new_root_atom->parent(0);
497  }
498 
499 
500  // now nuke the old atoms
501  atom_pointer_[ seqpos ].clear();
502  atom_pointer_[ seqpos ] = new_atoms;
503 
504  //
505  // we've added the new atoms assuming that their xyz coords are
506  // valid, but their internal coords (especially at the junctions
507  // of the old and new) are likely to be messed up. This is also
508  // true, eg, for any younger siblings of subtree_root
509  //
511 
512  // anything that depends on the tree topology needs to be updated
514 
515 }
516 
517 
518 
519 /////////////////////////////////////////////////////////////////////////////
520 /// @brief retrieve a specific DOF by its ID.
521 Real
522 AtomTree::dof( DOF_ID const & id ) const
523 {
525  return atom_pointer_[ id.atom_id() ]->dof( id.type() );
526 }
527 
528 /////////////////////////////////////////////////////////////////////////////
529 /// @brief retrieve the xyz position of an atom in the tree by its AtomID
530 PointPosition const &
531 AtomTree::xyz( AtomID const & id ) const
532 {
534  // if ( !has(id) ) {
535 // std::cerr << "AtomTree::atom_pointer_ has not the atom " << id << std::endl;
536 // }
537 // runtime_assert( has( id ) );
538  return atom_pointer_[ id ]->position();
539 }
540 
541 /////////////////////////////////////////////////////////////////////////////
542 /// @brief retreive a kinematic Atom in the tree by its AtomID
543 tree::Atom const &
544 AtomTree::atom( AtomID const & id ) const
545 {
546  // we don't know what kind of access the caller may perform:
549 
550  return *(atom_pointer_[ id ]);
551 }
552 
553 /////////////////////////////////////////////////////////////////////////////
554 /// @brief retreive a kinematic Atom in the tree by its AtomID -- no update!
555 tree::Atom const &
557 {
558  return *(atom_pointer_[ id ]);
559 }
560 
561 /////////////////////////////////////////////////////////////////////////////
562 /// @brief retrieve a Jump in the tree by that JumpAtom's AtomID.
563 /// @note will abort if a BondedAtom's AtomID is passed in.
564 Jump const &
565 AtomTree::jump( AtomID const & id ) const
566 {
568  return atom_pointer_[ id ]->jump();
569 }
570 
571 
572 /////////////////////////////////////////////////////////////////////////////
573 /// @brief get the DOF_ID of a torsion angle given those four atoms which define this torsion
574 ///
575 /// @details an "offset" value is also calculated that torsion(id1,id2,id3,id4) = dof( dof_id ) + offset.
576 /// A BOGUS_DOF_ID will be returned if no proper DOF can be found for these four atoms.
577 /// offset is mainly for an atom with a previous sibling as the torsion(PHI) attached
578 /// to it is calculated as improper angle with respect to its sibling.
581  AtomID const & atom1_in_id,
582  AtomID const & atom2_in_id,
583  AtomID const & atom3_in_id,
584  AtomID const & atom4_in_id,
585  Real & offset
586 ) const
587 {
588  using numeric::conversions::degrees;
589  using numeric::constants::d::pi_2;
590  using numeric::constants::d::pi;
591  using numeric::dihedral;
592  using numeric::dihedral_radians;
593 
594  bool const debug( false );
595 
596  // we use the internal dof's if necessary to calculate the offset
598 
599  if ( debug ) update_xyz_coords();
600 
601  assert( atom_pointer( atom1_in_id ) && atom_pointer( atom2_in_id ) &&
602  atom_pointer( atom3_in_id ) && atom_pointer( atom4_in_id ) );
603 
604  // STUART -- (low priority) I'd like to be able to cache
605  // the results of this calculation to allow faster access.
606 
607 
608  AtomCOP
609  atom1_in( atom_pointer( atom1_in_id ) ),
610  atom2_in( atom_pointer( atom2_in_id ) ),
611  atom3_in( atom_pointer( atom3_in_id ) ),
612  atom4_in( atom_pointer( atom4_in_id ) );
613  AtomCOP atom1( atom1_in ), atom2( atom2_in ),
614  atom3( atom3_in ), atom4( atom4_in );
615  // reorder the atoms if necessary
616  // we want it to be the case that atom4 has
617  // input_stub_atom1 == atom3 and
618  // input_stub_atom2 == atom2
619  //
620  if ( !atom4->is_jump() &&
621  !atom4->keep_dof_fixed( PHI ) && // not stub atom3 of a jump
622  atom4->input_stub_atom1() == atom3 &&
623  atom4->input_stub_atom2() == atom2 &&
624  atom4->input_stub_atom3() == atom1 ) {
625  // pass -- this is what we want, perfect match!!
626  } else if ( !atom1->is_jump() &&
627  !atom1->keep_dof_fixed( PHI ) && // not stub atom3 of a jump
628  atom1->input_stub_atom1() == atom2 &&
629  atom1->input_stub_atom2() == atom3 &&
630  atom1->input_stub_atom3() == atom4 ) {
631  // perfect case in reverse, want to reverse the order of the atoms
632  atom1 = atom4_in;
633  atom2 = atom3_in;
634  atom3 = atom2_in;
635  atom4 = atom1_in;
636  } else if ( !atom4->is_jump() &&
637  !atom4->keep_dof_fixed( PHI ) && // not stub atom3 of a jump
638  atom4->input_stub_atom1() == atom3 &&
639  atom4->input_stub_atom2() == atom2 ) {
640  // pass -- this is what we want, not quite as perfect as 1st case though
641  } else if ( !atom1->is_jump() &&
642  !atom1->keep_dof_fixed( PHI ) && // not stub atom3 of a jump
643  atom1->input_stub_atom1() == atom2 &&
644  atom1->input_stub_atom2() == atom3 ) {
645  // reverse the order of the atoms
646  atom1 = atom4_in;
647  atom2 = atom3_in;
648  atom3 = atom2_in;
649  atom4 = atom1_in;
650  } else {
651  // no good!
652  return id::BOGUS_DOF_ID;
653  }
654 
655  offset = 0.0; // initialize
656 
657  if ( atom4->input_stub_atom3() == atom1 ) {
658  // perfect match
659  return DOF_ID( atom4->id(), PHI );
660  }
661 
662  assert( !atom4->is_jump() &&
663  atom4->input_stub_atom0() == atom3 &&
664  atom4->input_stub_atom1() == atom3 &&
665  atom4->input_stub_atom2() == atom2 &&
666  atom4->parent() == atom3 );
667 
668  // special case if atoms 1 and 4 are siblings -- not really well defined!
669  if ( atom1->parent() == atom3 ) {
670  Size const atom1_index( atom3->child_index( atom1 ) ),
671  atom4_index( atom3->child_index( atom4 ) );
672  if ( atom1_index < atom4_index ) {
673  Real const current_value( atom3->dihedral_between_bonded_children( atom1, atom4 ) );
674  offset = current_value - atom4->dof(PHI); // since torsion(id1...id4) = dof + offset;
675 
676  ASSERT_ONLY( Real const actual_current_value
677  ( dihedral_radians( atom4->xyz(), atom3->xyz(), atom2->xyz(), atom1->xyz() ) );)
678  assert( std::abs( basic::subtract_radian_angles( actual_current_value, current_value ) ) < 1e-3 );
679  assert( std::abs( basic::subtract_radian_angles( current_value, atom4->dof( PHI ) + offset ) ) < 1e-3 );
680 
681  return DOF_ID( atom4->id(), PHI );
682  } else {
683  Real const current_value( atom3->dihedral_between_bonded_children( atom1, atom4 ) );
684  offset = current_value - atom1->dof( PHI ); // since torsion(id1...id4) = dof + offset;
685  ASSERT_ONLY( Real const actual_current_value
686  ( dihedral_radians( atom4->xyz(), atom3->xyz(), atom2->xyz(), atom1->xyz() ) );)
687  assert( std::abs( basic::subtract_radian_angles( actual_current_value, current_value ) ) < 1e-3 );
688  assert( std::abs( basic::subtract_radian_angles( current_value, atom1->dof( PHI ) + offset ) ) < 1e-3 );
689  return DOF_ID( atom1->id(), PHI );
690  }
691  }
692  // atom4 is not the first sibling of atom3, get offset for that.
693  if ( atom4 != atom3->get_nonjump_atom(0) ) {
694  AtomCOP new_atom4( atom3->get_nonjump_atom(0) );
695  offset += atom3->dihedral_between_bonded_children( new_atom4, atom4 );
696 
697  if ( debug ) { // debugging
698  ASSERT_ONLY( Real const actual_dihedral
699  ( dihedral_radians( atom4->xyz(), atom3->xyz(), atom2->xyz(),
700  new_atom4->xyz() ) );)
701  assert( std::abs( basic::subtract_radian_angles
702  ( actual_dihedral, offset ) ) < 1e-3 );
703  }
704 
705  atom4 = new_atom4;
706  }
707 
708  DOF_ID dof_id( atom4->id(), PHI );
709 
710  AtomCOP dof_atom1( atom4->input_stub_atom3() );
711 
712  if ( dof_atom1 == atom1 ) {
713  return dof_id;
714  } else if ( atom1->parent() == atom2 && !atom1->is_jump() &&
715  atom3->parent() == atom2 && !atom3->is_jump() ) {
716 
717  // handle offset between atom1 and dof_atom1
718  // the only case we can do is if atom1->parent() == atom2
719  //
720  // this will happen, eg for chi1 if we are folding c2n:
721  //
722  // atom1 = N while dof_atom1 = parent(atom2) = C
723  // atom2 = CA
724  // atom3 = CB
725  // atom4 = CG
726  //
727 
728  // a little tricky: we don't want to access the positions,
729  // since we can't be sure that they are up to date in a routine
730  // that would be called inside dof setting and getting routines
731  //
732  //
733  // need to use some spherical geometry
734  //
735  // we've got three unit vectors:
736  //
737  // u1 -- from atom2 to atom1
738  // u2 -- from atom2 to dof_atom1
739  // u3 -- from atom2 to atom3
740  //
741  // the angle between u2 and u1 = theta3 = pi - atom1(THETA)
742  // the angle between u2 and u3 = theta1 = pi - atom3(THETA)
743  // the torsion between u1 and u3 along u2 = phi2 = atom2->bonded_dih(1,3)
744  //
745  Real
746  theta1( pi - atom3->dof( THETA ) ),
747  theta3( pi - atom1->dof( THETA ) ),
748  phi2( atom2->dihedral_between_bonded_children( atom1, atom3 ) ),
749  sign_factor( 1.0 );
750  phi2 = basic::periodic_range( phi2, pi_2 );
751  if ( phi2 < 0 ) {
752  sign_factor = -1;
753  phi2 *= -1;
754  }
755  //If bond angle is varied, these angles can sometimes go out of range,
756  // during exploration by minimizer:
757  theta3 = basic::periodic_range( theta3, pi_2 );
758  if ( theta3 < 0 ) {
759  sign_factor *= -1;
760  theta3 *= -1;
761  }
762  theta1 = basic::periodic_range( theta1, pi_2 );
763  if ( theta1 < 0 ) {
764  sign_factor *= -1;
765  theta1 *= -1;
766  }
767  if ( !( 0 <= theta1 && theta1 <= pi &&
768  0 <= theta3 && theta3 <= pi &&
769  0 <= phi2 && phi2 <= pi ) ) {
770  std::cerr << "dof_atom1 " << dof_atom1->id() << std::endl;
771  std::cerr << "atom1 " << atom1->id() << std::endl;
772  std::cerr << "atom2 " << atom2->id() << std::endl;
773  std::cerr << "atom3 " << atom3->id() << std::endl;
774  std::cerr << "atom4 " << atom4->id() << std::endl;
775  std::cerr << "THETA1 " << theta1 << std::endl;
776  std::cerr << "THETA3 " << theta3 << std::endl;
777  std::cerr << "PHI2 " << phi2 << std::endl;
778 
779  utility_exit_with_message
780  ( "AtomTree::torsion_angle_dof_id: angle range error" );
781 
782  }
783  // want to solve for phi3 -- dihedral between u2 and u1 along axis
784  // defined by u3
785  //
786  // spherical law of cosines says:
787  //
788  // cos(theta2) = cos(theta1) * cos(theta3) +
789  // sin(theta1) * sin(theta3) * cos(phi2)
790  //
791  // so we can solve for cos(theta2); then use formula again to solve for
792  // cos(phi3).
793  //
794  Real const cos_theta2 = std::cos( theta1 ) * std::cos( theta3 ) +
795  std::sin( theta1 ) * std::sin( theta3 ) * std::cos( phi2 );
796  Real const theta2 = std::acos( cos_theta2 );
797  assert( 0 <= theta2 && theta2 <= pi );
798 
799  // use formula again interchanging 2 and 3
800  Real cos_phi3 = ( cos( theta3 ) - cos( theta1 ) * cos_theta2 ) /
801  ( sin( theta1 ) * sin( theta2 ) );
802 
803  // PHIL! really should handle degenerate cases more carefully
804  // PHIL! also could reuse some of the trig calculations
805 
806  // dof-torsion: from dof_atom1 to atom4 ~ atom4 - dof_atom1
807  // desired: from atom1 to atom4 ~ atom4 - atom1
808  //
809  // atom4 - atom1 = atom4 - dof_atom1 + ( dof_atom1 - atom1 )
810  //
811  // so offset == dof_atom1 - atom1 ~ dihedral from atom1 to dof_atom1
812  //
813 
814  //
815  Real const dihedral_from_atom1_to_dof_atom1
816  ( sign_factor * std::acos( cos_phi3 ) );
817 
818  offset += dihedral_from_atom1_to_dof_atom1;
819 
820  if ( debug ) { // debugging
821  using basic::periodic_range;
822  using basic::subtract_radian_angles;
823  Real const actual_dihedral_from_atom1_to_dof_atom1
824  ( dihedral_radians( atom1->xyz(), atom2->xyz(), atom3->xyz(),
825  dof_atom1->xyz()) );
826 
827  Real const actual_dihedral_of_interest
828  ( dihedral_radians( atom1_in->xyz(), atom2_in->xyz(),
829  atom3_in->xyz(), atom4_in->xyz()) );
830 
831  ASSERT_ONLY(Real const dev1
832  ( std::abs( subtract_radian_angles
833  ( actual_dihedral_from_atom1_to_dof_atom1,
834  dihedral_from_atom1_to_dof_atom1 ) ) );)
835 
836  ASSERT_ONLY(Real const dev2
837  ( std::abs( subtract_radian_angles( actual_dihedral_of_interest,
838  dof( dof_id ) + offset ) ) );)
839 
840 
841  ASSERT_ONLY(Real const dev3
842  ( std::abs( subtract_radian_angles
843  ( dof( dof_id ),
844  dihedral_radians( atom4->xyz(),
845  atom4->input_stub_atom1()->xyz(),
846  atom4->input_stub_atom2()->xyz(),
847  atom4->input_stub_atom3()->xyz()))));)
848 
849  assert( dev1 < 1e-3 && dev2 < 1e-3 && dev3 < 1e-3 );
850 
851  if ( false ) {
852  TR.Trace << "offset: " << offset << " sgn_fac: " << sign_factor <<
853  ' ' << dihedral_from_atom1_to_dof_atom1 << " =?= " <<
854  actual_dihedral_from_atom1_to_dof_atom1 <<
855  ' ' << periodic_range( dof( dof_id ) + offset, pi_2 ) <<
856  " =?= " << actual_dihedral_of_interest << std::endl;
857  }
858  }
859 
860  return dof_id;
861  }
862 
863  // failure
864  return id::BOGUS_DOF_ID;
865 }
866 
867 
868 
869 /////////////////////////////////////////////////////////////////////////////
870 //
871 /// @details brief set a specific DOF in the tree
872 void
874  DOF_ID const & id,
875  Real const setting
876 )
877 {
879  atom_pointer_[ id.atom_id() ]->set_dof( id.type(), setting, dof_changeset_ );
881 }
882 
883 /////////////////////////////////////////////////////////////////////////////
884 
885 void
887  AtomID const & id,
888  PointPosition const & xyz
889 )
890 {
892  atom_pointer_[ id ]->position( xyz );
894 }
895 
896 /////////////////////////////////////////////////////////////////////////////
897 
898 void
900  utility::vector1<AtomID> const & ids,
902 )
903 {
904  runtime_assert( ids.size() == xyzs.size() );
906  for (core::Size i=1; i<=ids.size(); ++i)
907  atom_pointer_[ ids[i] ]->position( xyzs[i] );
909 }
910 
911 
912 /////////////////////////////////////////////////////////////////////////////
913 /// @note AtomID must point to a JumpAtom, otherwise it will die.
914 void
916  AtomID const & id,
917  Jump const & jump
918 )
919 {
921  atom_pointer_[ id ]->jump( jump, dof_changeset_ );
923 }
924 
925 
926 /////////////////////////////////////////////////////////////////////////////
927 /// @note DEPRICATED. AtomID must point to a JumpAtom, otherwise it will die.
928 /// Hopefully, the new output-sentitive refold will make this method unneccessary
929 void
931  AtomID const & id,
932  Jump const & jump
933 )
934 {
935  /// set_jump_now no longer necessary. Commented-out implementation below is buggy
936  /// because the Conformation does not get its list of changed residues updated; so while
937  /// the coordinates in the atom tree are updated, the coordinates in the Conformation are not.
938  /// Instead of fixing this bug to handle this special case "set now", rely on the functional
939  /// and more efficient output-sensitive "set_jump"
940  set_jump( id, jump );
941 
942  // We use our parent atoms' positions to find our stub,
943  // which we can't do if their positions aren't correct.
944  //if( xyz_coords_need_updating_ ) {
945  // set_jump(id, jump);
946  // return;
947  //}
948  //update_internal_coords();
949  //atom_pointer_[ id ]->jump( jump );
950  //Stub stub( atom_pointer_[ id ]->get_input_stub() );
951  //atom_pointer_[ id ]->update_xyz_coords( stub );
952  // No change to xyz_coords_need_updating_ -- we've done our part,
953  // but previous changes may have invalidated other coords.
954  //xyz_coords_need_updating_ = true;
955 }
956 
957 
958 /////////////////////////////////////////////////////////////////////////////
959 /// @ details it is possible that no DOF can be obtained given these four atoms or the torsion
960 /// does not match exactly the DOF(PHI) angle. In the former case, a BOGUS_DOF_ID is
961 /// returned as indicator and in the latter case, an offset value is deducted from
962 /// input setting to set the real DOF value properly.
965  AtomID const & atom1,
966  AtomID const & atom2,
967  AtomID const & atom3,
968  AtomID const & atom4,
969  Real const setting
970 )
971 {
972 
973  Real offset;
974  DOF_ID const & id
975  ( torsion_angle_dof_id( atom1, atom2, atom3, atom4, offset ) );
976 
977  if ( !id.valid() ) {
978  // couldnt find this angle
979  return id;
980  }
981 
982  // note: offset is defined (see torsion_angle_dof_id) so that
983  //
984  // torsion(atom1,atom2,atom3,atom4) = dof(id) + offset
985  //
986 
987  set_dof( id, setting - offset );
988 
989  return id;
990 }
991 
992 /////////////////////////////////////////////////////////////////////////////
993 
996  AtomID const & atom1,
997  AtomID const & atom2,
998  AtomID const & atom3,
999  Real const setting
1000 )
1001 {
1002 
1003  Real offset(0.0);
1004  DOF_ID const dof_id( bond_angle_dof_id( atom1, atom2, atom3, offset ) );
1005 
1006  if ( dof_id.valid() ) {
1007  assert( offset == 0.0 ); // not handling this case right now
1008 
1009  set_dof( dof_id, numeric::constants::d::pi - setting );
1010  }
1011 
1012  return dof_id;
1013 }
1014 
1015 /////////////////////////////////////////////////////////////////////////////
1016 
1017 Real
1019  AtomID const & atom1,
1020  AtomID const & atom2,
1021  AtomID const & atom3
1022 ) const
1023 {
1024 
1025  Real offset(0.0);
1026  DOF_ID const dof_id( bond_angle_dof_id( atom1, atom2, atom3, offset ) );
1027 
1028  if ( dof_id.valid() ) {
1029  assert( offset == 0.0 ); // not handling this case right now
1030  return numeric::constants::d::pi - dof( dof_id );
1031  } else {
1032  TR << "unable to find DOF_ID for bond_angle: " << atom1 << ' ' << atom2 << ' ' << atom3 << std::endl;
1033  }
1034 
1035  return 0.0;
1036 }
1037 
1038 /////////////////////////////////////////////////////////////////////////////
1039 
1040 id::DOF_ID
1042  AtomID const & atom1_in_id,
1043  AtomID const & atom2_in_id,
1044  AtomID const & atom3_in_id,
1045  Real & offset
1046 ) const
1047 {
1048  offset = 0.0;
1049 
1050  // CASES
1051  // I. the bond angle is the THETA dof of atom3 (atom3's parent is atom2 and atom2's parent is atom1)
1052  // II. the bond angle is the THETA dof of atom1 (atom1's parent is atom2 and atom2's parent is atom3)
1053  // III. the bond angle is set by a torsion offset (atom1's parent is atom2 and atom3's parent is atom2)
1054 
1055  assert( atom_pointer( atom1_in_id ) && atom_pointer( atom2_in_id ) && atom_pointer( atom3_in_id ) );
1056 
1057  AtomCOP
1058  atom1_in( atom_pointer( atom1_in_id ) ),
1059  atom2_in( atom_pointer( atom2_in_id ) ),
1060  atom3_in( atom_pointer( atom3_in_id ) );
1061 
1062  AtomCOP atom1( atom1_in ), atom2( atom2_in ), atom3( atom3_in );
1063 
1064  // reorder the atoms if necessary
1065  // not necessary at all in the current logic
1066  DOF_ID dof_id( id::BOGUS_DOF_ID );
1067 
1068  if ( !atom3->is_jump() &&
1069  !atom3->keep_dof_fixed( THETA ) && // not stub atom2 of a jump
1070  atom3->input_stub_atom1() == atom2 &&
1071  atom3->input_stub_atom2() == atom1 ) {
1072  // case I
1073  dof_id = DOF_ID( atom3->id(), THETA );
1074 
1075  } else if ( !atom1->is_jump() &&
1076  !atom1->keep_dof_fixed( THETA ) && // not stub atom2 of a jump
1077  atom1->input_stub_atom1() == atom2 &&
1078  atom1->input_stub_atom2() == atom3 ) {
1079  // case II, perfect case in reverse, want to reverse the order of the atoms
1080  atom1 = atom3_in;
1081  atom2 = atom2_in;
1082  atom3 = atom1_in;
1083  dof_id = DOF_ID( atom3->id(), THETA );
1084 
1085  } else {
1086  // not handling other cases right now
1087  }
1088 
1089  return dof_id;
1090 }
1091 
1092 /////////////////////////////////////////////////////////////////////////////
1093 
1094 id::DOF_ID
1096  AtomID const & atom1,
1097  AtomID const & atom2,
1098  Real const setting
1099 )
1100 {
1101 
1102  DOF_ID const dof_id( bond_length_dof_id( atom1, atom2 ) );
1103 
1104  if ( dof_id.valid() ) {
1105  set_dof( dof_id, setting );
1106  }
1107 
1108  return dof_id;
1109 }
1110 
1111 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1112 
1113 Real
1115  AtomID const & atom1,
1116  AtomID const & atom2
1117 ) const
1118 {
1119 
1120  DOF_ID const dof_id( bond_length_dof_id( atom1, atom2 ) );
1121 
1122  if ( dof_id.valid() ) {
1123  return dof( dof_id );
1124  } else {
1125  TR << "unable to find DOF_ID for bond_length: " << atom1 << ' ' << atom2 << std::endl;
1126  }
1127 
1128  return 0.0;
1129 }
1130 
1131 /////////////////////////////////////////////////////////////////////////////
1132 
1133 id::DOF_ID
1135  AtomID const & atom1_id,
1136  AtomID const & atom2_id
1137 ) const
1138 {
1139 
1140  assert( atom_pointer( atom1_id ) && atom_pointer( atom2_id ) );
1141 
1142  AtomCOP atom1( atom_pointer( atom1_id ) ), atom2( atom_pointer( atom2_id ) );
1143 
1144  if ( !atom2->is_jump() &&
1145  atom2->input_stub_atom1() == atom1 ) {
1146  // case I
1147  return DOF_ID( atom2->id(), D );
1148 
1149  } else if ( !atom1->is_jump() &&
1150  atom1->input_stub_atom1() == atom2 ) {
1151  // case II
1152  return DOF_ID( atom1->id(), D );
1153 
1154  } else {
1155  // not handling other cases right now
1156  }
1157 
1158  return id::BOGUS_DOF_ID;
1159 }
1160 
1161 /////////////////////////////////////////////////////////////////////////////
1162 ///
1163 /// @note this is NOT calculated straight from atom positions.Instead, it is
1164 /// calculated from interal DOFs. If no DOF can be found from these four atoms,
1165 /// 0.0 will be returned and a warning message is printed.
1166 Real
1168  AtomID const & atom1,
1169  AtomID const & atom2,
1170  AtomID const & atom3,
1171  AtomID const & atom4
1172 ) const
1173 {
1175 
1176  // find the atomtree degree of freedom that corresponds to this torsion
1177  // angle
1178  Real offset;
1179  DOF_ID const & id
1180  ( torsion_angle_dof_id( atom1, atom2, atom3, atom4, offset ) );
1181 
1182  if ( !id.valid() ) {
1183  // couldnt find this angle
1184  TR << "AtomTree::torsion_angle() cant find dof! " <<
1185  atom1 << ' ' << atom2 << ' ' << atom3 << ' ' << atom4 << std::endl;
1186  return 0.0;
1187  }
1188 
1189  // note: offset is defined (see torsion_angle_dof_id) so that
1190  //
1191  // torsion(atom1,atom2,atom3,atom4) = dof(id) + offset
1192  //
1193 
1194  return atom_pointer_[ id.atom_id() ]->dof( id.type() ) + offset;
1195 }
1196 
1197 /////////////////////////////////////////////////////////////////////////////
1198 
1199 ///
1200 /// @details This is done by releasing memories of all atoms including the root atom
1201 ///, and clearing atom_pointer map
1202 void
1204 {
1205  atom_pointer_.clear();
1206  root_ = 0;
1207  external_coordinate_residues_changed_->total_residue(0);
1208 
1209  // anything that depends on the tree topology needs to be updated
1210  set_new_topology();
1211 
1212 }
1213 
1214 /////////////////////////////////////////////////////////////////////////////
1215 /// @note this may trigger a coordinate update of src (access to root atom)
1216 ///
1217 
1218 void
1220  AtomTree const & src
1221 )
1222 {
1223  if ( !root_ ) {
1224  if ( src.root() ) utility_exit_with_message("AtomTree::copy_coords: I'm empty but src is not!");
1225  return;
1226  }
1229 
1230  root_->copy_coords( *(src.root()) );
1232  (*external_coordinate_residues_changed_) = (*src.external_coordinate_residues_changed_);
1233 
1234 }
1235 
1236 ////////////////////////////////////////////////////////////////////////////////////
1237 /// @details domain map is residue-based and indicate which residues stay relatively rigid
1238 /// to each other in one domain since last move and therefore their interaction
1239 /// energy does not have to be recalculated. This function calls atom->update_domain_map
1240 /// from the root atom of the tree.
1241 void
1243  DomainMap & domain_map,
1244  AtomID_Mask const & dof_moved,
1245  AtomID_Mask const & xyz_moved
1246 ) const
1247 {
1248  domain_map = -1;
1249 
1250  int current_color(1), biggest_color(1);
1251  root_->update_domain_map( current_color, biggest_color, domain_map,
1252  dof_moved, xyz_moved );
1253 }
1254 
1255 
1256 /////////////////////////////////////////////////////////////////////////////
1257 // private
1258 void
1260 {
1261  for ( Size i=1, i_end = atom_pointer_.size(); i<= i_end; ++i ) {
1262  for ( Size j=1, j_end = atom_pointer_[i].size(); j<= j_end; ++j ) {
1263  assert( atom_pointer_[i][j] );
1264  if ( atom_pointer_[i][j] ) atom_pointer_[i][j]->id( AtomID(j,i) );
1265  }
1266  }
1267 }
1268 
1269 /////////////////////////////////////////////////////////////////////////////
1270 void
1272  Size const new_size,
1273  utility::vector1< int > const & old2new
1274 )
1275 {
1276  /// ResidueCoordinateChangeList is not setup to handle a remapping. It must
1277  /// be empty, which means the Conformation its tracking moved data for must have
1278  /// already retrieved its moved data.
1279  assert( external_coordinate_residues_changed_->empty() );
1280  external_coordinate_residues_changed_->total_residue( new_size );
1281 
1282  atom_pointer_.update_sequence_numbering( new_size, old2new );
1283 
1285 }
1286 
1287 
1288 /////////////////////////////////////////////////////////////////////////////
1289 /// @details makes a complete copy of another AtomTree src by cloning the root_atom and
1290 /// all its offspring atoms. Also update atom_pointer map.
1291 /// @note clear the content of tree first to release memory before doing the assignment.
1292 AtomTree &
1294 {
1295  if (this == &src) {
1296  return *this;
1297  }
1298 
1299  if ( topological_match_to_() == &src || src.topological_match_to_() == this ) {
1300  /// Why include the second condition: src.topological_match_to_ == this ?
1301  /// As an optimization for the common case when atom trees are being copied
1302  /// back and forth into each other as happens in repeated calls to MC::boltzman.
1303  /// Moreover, "topological match to" is a commutative property.
1304  copy_coords( src );
1305  } else {
1306  // no memory leaks -- notify observers that the topology is changing.
1307  clear();
1308 
1309  // just to get the dimensions right:
1311 
1312  // copy tree (recursive)
1313  if ( src.root_ ) {
1314  root_ = src.root_->clone( 0 /*parent=0*/, atom_pointer_ );
1315  }
1316 
1320 
1321  (*external_coordinate_residues_changed_) = (*src.external_coordinate_residues_changed_);
1322 
1323  }
1324 
1325  if ( topological_match_to_() != & src ) {
1326  if ( topological_match_to_() != 0 ) {
1327  assert( this_weak_ptr_ );
1328  topological_match_to_->detatch_topological_observer( this_weak_ptr_ );
1329  }
1330  /// topological observation only allowed if both this, and src hold weak pointers to themselves.
1331  /// If either AtomTree had been declared on the stack, or if the code that instantiated either one
1332  /// never gave them their weak-pointer-to-selves, then the observer system is bypassed.
1333  if ( this_weak_ptr_ && src.this_weak_ptr_ ) {
1335  }
1336  }
1337  return *this;
1338 
1339 }
1340 
1341 /////////////////////////////////////////////////////////////////////////////
1342 /// @details update_internal_coords would be called in situations where we want
1343 /// to ensure that the internal degrees are valid, eg when we are about
1344 /// to set a new internal DOF.
1345 /// @note private method, const to allow lazy updating of
1346 /// @note see usage in AtomTree.cc
1347 /// @note these guys are const because of the lazy updating scheme we are using:
1348 /// they need to be called from within const accessing functions.
1349 
1350 void
1352 {
1353  // this would be bad:
1355 
1357  if ( !root_ ) utility_exit_with_message("phil how did we get here?-1");
1358 
1359  PROF_START( basic::ATOM_TREE_UPDATE_INTERNAL_COORDS ); // profiling
1360  root_->update_internal_coords( default_stub );
1361  PROF_STOP ( basic::ATOM_TREE_UPDATE_INTERNAL_COORDS );
1362 
1364  }
1365 }
1366 
1367 
1368 
1369 /// @details Set the transform between two stubs
1370 /// Returns the atomid of the jump atom which moved.
1371 /// @note Requires that there be a jump in the atomtree between a pair of atoms in the stubs
1372 id::AtomID
1374  StubID const & stub_id1,
1375  StubID const & stub_id2,
1376  RT const & target_rt
1377 )
1378 {
1379 
1380  // look for the connection between these two stubs
1381  AtomOP jump_atom(0);
1382  int dir(0);
1383  for ( Size i=1; i<= 3; ++i ) {
1384  AtomOP atom1( atom_pointer( stub_id1.atom( i ) ) );
1385  for ( Size j=1; j<= 3; ++j ) {
1386  AtomOP atom2( atom_pointer( stub_id2.atom( j ) ) );
1387  if ( atom1->is_jump() && atom1->parent() == atom2 ) {
1388  assert( !jump_atom );
1389  jump_atom = atom1;
1390  dir = -1;
1391  } else if ( atom2->is_jump() && atom2->parent() == atom1 ) {
1392  assert( !jump_atom );
1393  jump_atom = atom2;
1394  dir = 1;
1395  }
1396  }
1397  }
1398  if ( !jump_atom ) {
1399  utility_exit_with_message( "AtomTree::set_stub_transform: No jump between these atoms!" );
1400  }
1401 
1402  Stub const instub( dir == 1 ? stub_from_id( stub_id1 ) : stub_from_id( stub_id2 ) );
1403  Stub const outstub( dir == 1 ? stub_from_id( stub_id2 ) : stub_from_id( stub_id1 ) );
1404  RT rt( target_rt );
1405  if ( dir == -1 ) rt.reverse();
1406  // now solve for a linear transform that will move outstub so that RT( instub, outstub ) == rt
1407  Stub::Matrix A;
1408  Vector b;
1409  find_stub_transform( instub, outstub, rt, A, b );
1410  jump_atom->transform_Ax_plus_b_recursive( A, b, *external_coordinate_residues_changed_ );
1411  internal_coords_need_updating_ = true; // this could be more efficient!
1412 
1413  // confirm that things worked
1414  assert( RT( stub_from_id( stub_id1 ), stub_from_id( stub_id2 ) ).distance_squared( target_rt ) < 1e-3 );
1415  return jump_atom->id();
1416 }
1417 
1418 /// @brief get the transform between two stubs
1419 RT
1421  StubID const & stub_id1,
1422  StubID const & stub_id2
1423 ) const
1424 {
1425  return RT( stub_from_id( stub_id1 ), stub_from_id( stub_id2 ) );
1426 }
1427 /////////////////////////////////////////////////////////////////////////////
1428 // private
1429 ///\brief update xyz coordinates from internal cooridnates
1430 void
1432 {
1433  // this would be bad:
1435 
1436 
1437  if ( xyz_coords_need_updating_ ) {
1438  if ( !root_ ) utility_exit_with_message("phil how did we get here-2?");
1439 
1440  PROF_START( basic::ATOM_TREE_UPDATE_XYZ_COORDS ); // profiling
1441  for ( Size ii = 1; ii <= dof_changeset_.size(); ++ii ) {
1442  if ( dof_changeset_[ ii ].reached_ ) continue;
1444  }
1445 
1446  for ( Size ii = 1; ii <= dof_changeset_.size(); ++ii ) {
1447  if ( dof_changeset_[ ii ].reached_ ) continue;
1448  //std::cout << "Refold from " << dof_changeset_[ ii ].atomid_.rsd() << std::endl; // << " " << dof_changeset_[ ii ].atomid_.atomno() << " " << dof_changeset_[ ii ].reached_ << std::endl;
1449  atom_pointer_[ dof_changeset_[ ii ].atomid_ ]->update_xyz_coords(); // it must find its own stub.
1450  }
1451  dof_changeset_.clear();
1452  PROF_STOP ( basic::ATOM_TREE_UPDATE_XYZ_COORDS );
1453 
1454  xyz_coords_need_updating_ = false;
1455 
1456  //std::cout << "REFOLD END" << std::endl;
1457 
1458  }
1459 }
1460 
1461 /// @brief The AtomTree provides to the Conformation object a list of residues
1462 /// whose xyz coordinates have changed. When the Conformation has finished reading off
1463 /// residues that have changed from the AtomTree, and has copied the coordinates of
1464 /// those residues into its conformation::Residue objects, it informs the AtomTree
1465 /// to reset this list by a call to mark_changed_residues_registered
1466 ///
1467 /// @details The list of which residues have had coordinate changes is unknown until
1468 /// the DFS has completed. The DFS must be triggered before iterators are given to the
1469 /// Conformation object.
1472 {
1474  return external_coordinate_residues_changed_->residues_moved_begin();
1475 }
1476 
1477 /// @details The list of which residues have had coordinate changes is unknown until
1478 /// the DFS has completed. The DFS must be triggered before iterators are given to the
1479 /// Conformation object.
1482 {
1484  return external_coordinate_residues_changed_->residues_moved_end();
1485 }
1486 
1487 
1488 /// @brief The AtomTree provides a list of residues who's xyz coordinates have changed
1489 /// to the Conformation object. When the Conformation has finished reading off residues
1490 /// that have changed from the AtomTree, and has copied the coordinates of those residues
1491 /// into its conformation::Residue objects, it informs the AtomTree to reset this list
1492 /// by a call to mark_changed_residues_registered
1493 void
1495 {
1497 }
1498 
1499 
1500 /// @brief When an atom tree copies the topology of another atom tree, it must
1501 /// register itself as a topological observer of that other tree. When the other
1502 /// tree changes its topology, then the tree being observed must notify its
1503 /// observers that they are no longer a topological copy of this tree. An atom
1504 /// tree may only be the topological copy of a single other atom tree, though several
1505 /// atom trees may be copies of a single atom tree.
1506 void
1508 {
1509  assert( observer->this_weak_ptr_ && this_weak_ptr_ );
1510  assert( observer->topological_match_to_ == 0 );
1511  bool resize_topo_observers_array_( false );
1512  for ( Size ii = 1; ii <= topological_observers_.size(); ++ii ) {
1513  if ( topological_observers_[ ii ] == 0 ) {
1514  resize_topo_observers_array_ = true;
1515  /// Make sure the observer is not already observing me
1516  assert( topological_observers_[ ii ] != observer );
1517  }
1518  }
1519 
1520  if ( resize_topo_observers_array_ ) {
1521  Size n_valid( 0 );
1522  for ( Size ii = 1; ii <= topological_observers_.size(); ++ii ) {
1523  if ( topological_observers_[ ii ] != 0 ) ++n_valid;
1524  }
1525  utility::vector1< AtomTreeCAP > valid_observers;
1526  valid_observers.reserve( n_valid + 1 );
1527  for ( Size ii = 1; ii <= topological_observers_.size(); ++ii ) {
1528  if ( topological_observers_[ ii ] != 0 ) valid_observers.push_back( topological_observers_[ ii ] );
1529  }
1530  topological_observers_.swap( valid_observers );
1531  }
1532 
1533  topological_observers_.push_back( observer );
1534  observer->topological_match_to_ = this_weak_ptr_;
1535 }
1536 
1537 /// @details The AtomTree being observed calls this notify_topological_change on all
1538 /// of the AtomeTrees that are observing it. The this object "detaches" itself from
1539 /// the observee in this function. In debug mode, this function ensures that this
1540 /// object was actually observing the observee -- if it wasn't, then an internal error
1541 /// has occurred. The observee and the observer have gotten out of sync.
1542 void
1543 AtomTree::notify_topological_change( AtomTreeCAP ASSERT_ONLY( observee ) ) const
1544 {
1545  assert( observee == topological_match_to_ );
1547 }
1548 
1549 /// @details When an AtomTree which was observing this AtomTree changes its
1550 /// topology or is deleted, it must invoke this method on this AtomTree.
1551 /// When this happens, this AtomTree marks the observer's position in
1552 /// its list of observers as null.
1553 void
1555 {
1556  assert( observer->topological_match_to_() == this );
1557  bool found( false );
1558  for ( Size ii = 1; ii <= topological_observers_.size(); ++ii ) {
1559  if ( topological_observers_[ ii ] == observer ) {
1560  found = true;
1561  topological_observers_[ ii ] = 0;
1562  observer->topological_match_to_ = 0;
1563  break;
1564  }
1565  }
1566  assert( found );
1567 }
1568 
1569 /// @details If this tree changes its topology, then its no longer a match in topology
1570 /// to the tree it was copied from, nor are the trees that are a copy of it. Detatch
1571 /// this as an observer of the AtomTree it is observing (if any) and inform all the
1572 /// trees observing this tree that the topology has changed before clearing the
1573 /// topological_observers_ array.
1574 void
1576 {
1577  if ( topological_match_to_ != 0 ) {
1578  topological_match_to_->detatch_topological_observer( this );
1579  }
1580  for ( Size ii = 1; ii <= topological_observers_.size(); ++ii ) {
1581  if ( topological_observers_[ ii ] != 0 ) {
1582  topological_observers_[ ii ]->notify_topological_change( this );
1583  }
1584  }
1585  topological_observers_.clear();
1586 }
1587 
1588 
1589 ////////////////////////////////////////////////////////////////////////////////////////////////////
1590 ////////////////////////////////////////////////////////////////////////////////////////////////////
1591 ////////////////////////////////////////////////////////////////////////////////////////////////////
1592 /////////////// CARTESIAN-COORDINATE FRAGMENT INSERTION ROUTINES ///////////////////////////////////
1593 ////////////////////////////////////////////////////////////////////////////////////////////////////
1594 ////////////////////////////////////////////////////////////////////////////////////////////////////
1595 ////////////////////////////////////////////////////////////////////////////////////////////////////
1596 
1597 void
1599  StubID const & id,
1600  FragXYZ const & frag_xyz,
1601  AtomCOP & frag_atom,
1602  AtomCOP & nonfrag_atom // could be zero if atom1 is root of tree
1603 ) const
1604 {
1605  bool const atom1_in_frag( frag_xyz.count( id.atom1 ) );
1606  bool const atom2_in_frag( frag_xyz.count( id.atom2 ) );
1607 
1608  AtomCOP atom1( atom_pointer( id.atom1 ) );
1609 
1610  if ( atom1->is_jump() ) {
1611  if ( !atom1_in_frag && atom1->parent() && frag_xyz.count( atom1->parent()->atom_id() ) ) {
1612  frag_atom = atom1->parent();
1613  nonfrag_atom = atom1;
1614  return;
1615  } else if ( atom1_in_frag && ( !atom1->parent() || !frag_xyz.count( atom1->parent()->atom_id() ) ) ) {
1616  frag_atom = atom1;
1617  nonfrag_atom = atom1->parent();
1618  return;
1619  }
1620  }
1621 
1622  if ( atom1_in_frag && !atom2_in_frag ) {
1623  frag_atom = atom_pointer( id.atom1 );
1624  nonfrag_atom = atom_pointer( id.atom2 );
1625  return;
1626 
1627  } else if ( atom2_in_frag && !atom1_in_frag ) {
1628  frag_atom = atom_pointer( id.atom2 );
1629  nonfrag_atom = atom_pointer( id.atom1 );
1630  return;
1631 
1632  }
1633  utility_exit_with_message( "AtomTree::get_frag_atoms failed" );
1634 
1635 }
1636 
1637 
1638 /////////////////////////////////////////////////////////////////////////////
1639 /// id is a frag atom
1640 ///
1641 /// look for two more nearby frag atoms to define a pseudo-stub for getting coords for parents or children of this atom
1642 ///
1643 
1644 id::StubID
1646  AtomID const & id,
1647  FragXYZ const & frag_xyz,
1648  bool & fail
1649 ) const
1650 {
1651  assert( frag_xyz.count( id ) );
1652 
1654 
1655  AtomCOP atom( atom_pointer( id ) );
1656  AtomCOP parent( atom->parent() ), child1( atom->get_nonjump_atom(0) ), child2( atom->get_nonjump_atom(1) );
1657 
1658  if ( !atom->is_jump() && parent && frag_xyz.count( parent->atom_id() ) ) {
1659  ids.push_back( parent->atom_id() );
1660  }
1661  if ( child1 && frag_xyz.count( child1->atom_id() ) ) {
1662  ids.push_back( child1->atom_id() );
1663  }
1664  if ( child2 && frag_xyz.count( child2->atom_id() ) ) {
1665  ids.push_back( child2->atom_id() );
1666  }
1667  if ( child1 && frag_xyz.count( child1->atom_id() ) ) {
1668  AtomCOP gchild1( child1->get_nonjump_atom(0) );
1669  if ( gchild1 && frag_xyz.count( gchild1->atom_id() ) ) {
1670  ids.push_back( gchild1->atom_id() );
1671  }
1672  }
1673  if ( child2 && frag_xyz.count( child2->atom_id() ) ) {
1674  AtomCOP gchild2( child2->get_nonjump_atom(0) );
1675  if ( gchild2 && frag_xyz.count( gchild2->atom_id() ) ) {
1676  ids.push_back( gchild2->atom_id() );
1677  }
1678  }
1679  if ( !atom->is_jump() && parent && frag_xyz.count( parent->atom_id() ) ) {
1680  AtomCOP gparent( parent->parent() );
1681  if ( !parent->is_jump() && gparent && frag_xyz.count( gparent->atom_id() ) ) {
1682  ids.push_back( gparent->atom_id() );
1683  }
1684  for ( Size i=0; i<parent->n_children(); ++i ) {
1685  AtomCOP sibling( parent->child(i) );
1686  if ( sibling != atom && !sibling->is_jump() && frag_xyz.count( sibling->atom_id() ) ) {
1687  ids.push_back( sibling->atom_id() );
1688  }
1689  }
1690  }
1691  if ( ids.size() < 2 ) {
1692  fail = true;
1693  return StubID( id, id, id );
1694  }
1695  return StubID( id, ids[1], ids[2] );
1696 }
1697 
1698 
1699 
1700 /////////////////////////////////////////////////////////////////////////////
1701 /// private helper for fragment insertion routines
1702 ///
1703 Stub
1705  StubID const & stubid,
1706  FragXYZ const & frag_xyz,
1707  bool & fail
1708 ) const
1709 {
1710  // first look for special case of stub of frag jump-child:
1711  AtomID const stub_atom1_id( stubid.atom1 ), stub_atom2_id( stubid.atom2 ), stub_atom3_id( stubid.atom3 );
1712  AtomCOP stub_atom1( atom_pointer( stub_atom1_id ) );
1713 
1714  if ( !frag_xyz.count( stub_atom1_id ) && stub_atom1->is_jump() &&
1715  stub_atom1->parent() && frag_xyz.count( stub_atom1->parent()->atom_id()) &&
1716  stub_atom1->stub_atom1_id() == stub_atom1_id &&
1717  stub_atom1->stub_atom2_id() == stub_atom2_id &&
1718  stub_atom1->stub_atom3_id() == stub_atom3_id ) {
1719 
1720  /// special case: handled more easily this way
1721  StubID const instub_id( stub_atom1->input_stub_atom1_id(),
1722  stub_atom1->input_stub_atom2_id(),
1723  stub_atom1->input_stub_atom3_id() );
1724  assert( stub_atom1->input_stub_atom0_id() == stub_atom1->input_stub_atom1_id() );
1725 
1726  // current xyz transform:
1727  RT const current_rt( stub_from_id( instub_id ), stub_from_id( stubid ) );
1728  Stub const instub( get_frag_local_stub( instub_id, frag_xyz, fail ) ); // recursive call
1729  Stub outstub;
1730  TR.Trace << "get_frag_local_stub:: making jump: " <<
1731  stubid.atom1 << ' ' << stubid.atom2 << ' ' << stubid.atom3 << ' ' <<
1732  instub_id.atom1 << ' ' << instub_id.atom2 << ' ' << instub_id.atom3 << std::endl;
1733 
1734  current_rt.make_jump( instub, outstub );
1735  return outstub;
1736  }
1737 
1738 
1739  return Stub( get_frag_local_xyz( stub_atom1_id, frag_xyz, fail ),
1740  get_frag_local_xyz( stub_atom2_id, frag_xyz, fail ),
1741  get_frag_local_xyz( stub_atom3_id, frag_xyz, fail ) );
1742 }
1743 
1744 /////////////////////////////////////////////////////////////////////////////
1745 /// private helper for fragment insertion routines
1746 ///
1747 /// id is either in frag or a child or a gchild or a parent
1748 ///
1749 
1750 Vector
1752  AtomID const & id,
1753  FragXYZ const & frag_xyz,
1754  bool & fail
1755 ) const
1756 {
1757  // easiest case:
1758  if ( frag_xyz.count( id ) ) return frag_xyz.find( id )->second;
1759 
1760  AtomCOP atom( atom_pointer(id) );
1761 
1762  if ( ( atom->parent() && frag_xyz.count( atom->parent()->atom_id() ) ) ||
1763  ( atom->parent() && atom->parent()->parent() && frag_xyz.count( atom->parent()->parent()->atom_id() ) ) ) {
1764  // child or grand child
1765  return get_frag_descendant_local_xyz( atom, frag_xyz, fail );
1766  }
1767 
1768  // now should be parent of frag
1769  AtomCOP child( 0 );
1770  for ( Size i=0; i< atom->n_children(); ++i ) {
1771  if ( frag_xyz.count( atom->child(i)->atom_id() ) ) {
1772  assert( child == 0 );
1773  child = atom->child(i);
1774  }
1775  }
1776  assert( child ); // this is a known hole: could be asked for a grandparent of a frag, not just a parent. fix this phil
1777  return get_frag_parent_local_xyz( child, frag_xyz, fail );
1778 
1779 
1780 }
1781 /////////////////////////////////////////////////////////////////////////////
1782 /// private helper for fragment insertion routines
1783 ///
1784 Vector
1786  AtomCOP atom,
1787  FragXYZ const & frag_xyz,
1788  bool & fail
1789 ) const
1790 {
1791  AtomID const id( atom->atom_id() );
1792  assert( !frag_xyz.count( id ) );
1793  bool const frag_child( atom->parent() && frag_xyz.count( atom->parent()->atom_id() ) );
1794  ASSERT_ONLY(bool const frag_gchild
1795  ( atom->parent() && atom->parent()->parent() && frag_xyz.count( atom->parent()->parent()->atom_id() ) );)
1796  assert( frag_child || frag_gchild );
1797 
1798  AtomID id1( atom->input_stub_atom1_id() );
1799  AtomID id2( atom->input_stub_atom2_id() );
1800  AtomID id3( atom->input_stub_atom3_id() );
1801  assert( atom->input_stub_atom0_id() == id1 ); // cant handle this case yet
1802 
1803  if ( id == id1 || id == id2 || id == id3 ) {
1804  /// circular!!! potential for infinite loop!
1805  if ( frag_child ) {
1806  StubID tmp( get_frag_pseudo_stub_id( atom->parent()->atom_id(), frag_xyz, fail ) );
1807  id1 = tmp.atom1;
1808  id2 = tmp.atom2;
1809  id3 = tmp.atom3;
1810  } else {
1811  StubID tmp( get_frag_pseudo_stub_id( atom->parent()->parent()->atom_id(), frag_xyz, fail ) );
1812  id1 = tmp.atom1;
1813  id2 = tmp.atom2;
1814  id3 = tmp.atom3;
1815  }
1816  if ( fail ) return Vector(0.0);
1817  }
1818 
1819  Stub const current_stub( stub_from_id( StubID( id1, id2, id3) ) );
1820  Stub const local_stub( get_frag_local_stub( StubID( id1, id2, id3 ), frag_xyz, fail ) ); // potentially recursive
1821  return local_stub.local2global( current_stub.global2local( xyz( id ) ) );
1822 }
1823 
1824 /////////////////////////////////////////////////////////////////////////////
1825 /// private helper for fragment insertion routines
1826 ///
1827 Vector
1829  AtomCOP child,
1830  FragXYZ const & frag_xyz,
1831  bool & fail
1832 ) const
1833 {
1834  AtomCOP parent( child->parent() );
1835  //assert( !parent->is_jump() ); // dont think we have to handle this case...
1836  assert( frag_xyz.count( child->atom_id() ) && ! frag_xyz.count( parent->atom_id() ) );
1837 
1838  // build a pseudo-stub for the parent
1839  StubID const pseudo_stubid( get_frag_pseudo_stub_id( child->atom_id(), frag_xyz, fail ) );
1840  if ( fail ) return Vector(0.0);
1841  Stub const current_stub( stub_from_id( pseudo_stubid ) );
1842  Stub const local_stub( get_frag_local_stub( pseudo_stubid, frag_xyz, fail ) );
1843  assert( !fail ); // since pseudo stub atoms are all in the fragment
1844  return local_stub.local2global( current_stub.global2local( xyz( parent->atom_id() ) ) );
1845 }
1846 
1847 
1848 
1849 /////////////////////////////////////////////////////////////////////////////
1850 // a private function
1851 //
1852 // the incoming stub should in fact be the true incoming connection
1853 // and all the outgoing connections should be accounted for.
1854 //
1855 // This is all checked in assert statements.
1856 //
1857 void
1859  StubID const & instub_id,
1860  FragRT const & outstub_transforms,
1861  FragXYZ const & frag_xyz,
1862  utility::vector1< AtomID > & moving_atoms
1863 )
1864 {
1865  // get the incoming stub:
1866  Stub const instub( stub_from_id( instub_id ) );
1867 
1868  AtomCOP instub_frag_atom(0), instub_nonfrag_atom(0);
1869  get_frag_atoms( instub_id, frag_xyz, instub_frag_atom, instub_nonfrag_atom );
1870 
1871  assert( instub_frag_atom->parent() == instub_nonfrag_atom ); // sanity check
1872 
1873  utility::vector1< AtomCOP > outstub_nonfrag_atoms; // just for debugging
1874 
1875  for ( FragRT::const_iterator it= outstub_transforms.begin(), ite= outstub_transforms.end(); it != ite; ++it ) {
1876  StubID const & outstub_id( it->first );
1877  AtomCOP outstub_frag_atom(0), outstub_nonfrag_atom(0);
1878  get_frag_atoms( outstub_id, frag_xyz, outstub_frag_atom, outstub_nonfrag_atom );
1879  outstub_nonfrag_atoms.push_back( outstub_nonfrag_atom ); // for debugging
1880  assert( outstub_nonfrag_atom->parent() == outstub_frag_atom );
1881 
1882  // now transform outstub_nonfrag_atom so that current transform becomes desired transform
1883  //
1884  Stub const & stub1( instub ); // to match names below
1885  Stub const stub2( stub_from_id( outstub_id ) );
1886  RT const & rt( it->second );
1887 
1888  // now things are arranged so that when we transform outstub_nonfrag_atom and children, stub1 stays fixed and
1889  // stub2 moves, and we want RT( stub1, new_stub2 ) == target_rt
1890 
1891  Stub::Matrix const & M1( stub1.M ), M2( stub2.M ), R( rt.get_rotation() );
1892  Vector const & v1( stub1.v ), v2( stub2.v ), t( rt.get_translation() );
1893 
1894  // look for a transformation of the form x |----> A*x + b
1895  //
1896  // this will change stub2 to stub2' with M2' = A * M2, v2' = A*v2 + b
1897  //
1898  // if we let (R,t) be the target RT, then we want
1899  //
1900  // R = M1^T * M2' = M1^T * A * M2 ==> A = M1 * R * M2^T
1901  //
1902  // t = M1^T * ( v2' - v1 ) ==> v2' = M1 * t + v1, which with b = v2' - A*v2 gives b = M1 * t + v1 - A * v2
1903  //
1904 
1905  Stub::Matrix const A( M1 * R * M2.transposed() );
1906  Vector const b( M1 * t + v1 - A * v2 );
1907 
1908  atom_pointer_[ outstub_nonfrag_atom->atom_id() ]->
1909  transform_Ax_plus_b_recursive( A, b, *external_coordinate_residues_changed_ ); // get nonconst version
1911 
1912  moving_atoms.push_back( outstub_nonfrag_atom->atom_id() );
1913  }
1914 
1915 
1916  for ( FragXYZ::const_iterator it=frag_xyz.begin(), ite= frag_xyz.end(); it != ite; ++it ) {
1917  AtomID const & id( it->first );
1918  AtomOP atom( atom_pointer( id ) );
1919 
1920  // update xyz using instub
1921  atom->xyz( instub.local2global( it->second ) );
1922 
1923  { // sanity check/debug
1924  // if parent not in frag, assert this is instub_frag_atom
1925  assert( ( atom->parent() && frag_xyz.count( atom->parent()->atom_id() ) ) || atom == instub_frag_atom );
1926 
1927  // if has a child not in frag, assert child is in outstub_nonfrag_atoms
1928  for ( Size i=0; i< atom->n_children(); ++i ) {
1929  assert( frag_xyz.count( atom->child(i)->atom_id() ) ||
1930  ( std::find( outstub_nonfrag_atoms.begin(), outstub_nonfrag_atoms.end(), atom->child(i) ) !=
1931  outstub_nonfrag_atoms.end()));
1932  }
1933  }
1934  moving_atoms.push_back( id );
1935 
1936  }
1938 
1939 
1940  // now debug transforms
1941  for ( FragRT::const_iterator it= outstub_transforms.begin(), ite= outstub_transforms.end(); it != ite; ++it ) {
1942  assert( RT( instub, stub_from_id( it->first )).distance_squared( it->second ) < 1e-3 );
1943  }
1944 
1945 
1946 }
1947 
1948 
1949 /////////////////////////////////////////////////////////////////////////////
1950 void
1952  StubID const & id
1953 )
1954 {
1955  update_xyz_coords(); // since we will need to recalculate all the internal dofs when we're done
1956 
1957  AtomOP atom1( atom_pointer( id.atom1 ) );
1958  AtomOP atom2( atom_pointer( id.atom2 ) );
1959  AtomOP atom3( atom_pointer( id.atom3 ) );
1960  if ( !atom1->is_jump() || atom2->is_jump() || atom3->is_jump() ||
1961  atom2->parent() != atom1 || atom3->parent() != atom2 ) {
1962  utility_exit_with_message( "set_jump_atom_stub_id failed!" );
1963  }
1964 
1965  atom1->delete_atom( atom2 );
1966  atom1->insert_atom( atom2 ); // goes to head of line
1967  atom2->delete_atom( atom3 );
1968  atom2->insert_atom( atom3 ); // goes to head of line
1969 
1971 
1972  assert( atom1->stub_atom1() == atom1 && atom1->stub_atom2() == atom2 && atom1->stub_atom3() == atom3 );
1973 
1974 }
1975 
1976 
1977 /////////////////////////////////////////////////////////////////////////////
1978 // completely new plan
1979 //
1980 void
1982  StubID const & instub_id,
1983  FragRT const & outstub_transforms,
1984  FragXYZ const & frag_xyz,
1985  utility::vector1< AtomID > & moving_atoms
1986 )
1987 {
1988  // first compile a list of incoming/outgoing connections
1989 
1990  // look for more incoming and/or outgoing connections:
1991 
1992  utility::vector1< AtomCOP > incoming_stub_frag_atoms, outgoing_stub_nonfrag_atoms;
1993  utility::vector1< Stub > incoming_local_stubs, outgoing_local_stubs;
1994  utility::vector1< StubID > incoming_stub_ids, outgoing_stub_ids;
1995 
1996  {
1997  AtomCOP frag_atom, nonfrag_atom;
1998  get_frag_atoms( instub_id, frag_xyz, frag_atom, nonfrag_atom );
1999  if ( frag_atom->parent() == nonfrag_atom ) {
2000  TR.Trace << "AtomTree::insert_fragment: instub is incoming" << std::endl;
2001  incoming_stub_frag_atoms.push_back( frag_atom );
2002  incoming_local_stubs.push_back( Stub() );
2003  incoming_stub_ids.push_back( instub_id );
2004  } else if ( nonfrag_atom && nonfrag_atom->parent() == frag_atom ) {
2005  TR.Trace << "AtomTree::insert_fragment: instub is outgoing" << std::endl;
2006  outgoing_stub_nonfrag_atoms.push_back( nonfrag_atom );
2007  outgoing_local_stubs.push_back( Stub() );
2008  outgoing_stub_ids.push_back( instub_id );
2009  }
2010  } // scope
2011 
2012  for ( FragRT::const_iterator it= outstub_transforms.begin(), ite= outstub_transforms.end(); it != ite; ++it ) {
2013  StubID const & outstub_id( it->first );
2014  AtomCOP frag_atom, nonfrag_atom;
2015  get_frag_atoms( outstub_id, frag_xyz, frag_atom, nonfrag_atom );
2016  if ( nonfrag_atom && nonfrag_atom->parent() == frag_atom ) {
2017  TR.Trace << "AtomTree::insert_fragment: outstub is outgoing" << std::endl;
2018  outgoing_stub_nonfrag_atoms.push_back( nonfrag_atom );
2019  outgoing_local_stubs.push_back( Stub( it->second ) );
2020  outgoing_stub_ids.push_back( outstub_id );
2021  } else if ( frag_atom->parent() == nonfrag_atom ) {
2022  TR.Trace << "AtomTree::insert_fragment: outstub is incoming" << std::endl;
2023  incoming_stub_frag_atoms.push_back( frag_atom );
2024  incoming_local_stubs.push_back( Stub( it->second ) );
2025  incoming_stub_ids.push_back( outstub_id );
2026  }
2027  }
2028 
2029  for ( FragXYZ::const_iterator it=frag_xyz.begin(), ite= frag_xyz.end(); it != ite; ++it ) {
2030  //AtomID const & id( it->first );
2031  AtomOP atom( atom_pointer( it->first ) );
2032  if ( ( atom->parent() == 0 || !frag_xyz.count( atom->parent()->atom_id() ) ) &&
2033  ( std::find( incoming_stub_frag_atoms.begin(), incoming_stub_frag_atoms.end(), atom ) ==
2034  incoming_stub_frag_atoms.end() ) ) {
2035  // found a new incoming connection!
2036  TR.Trace << "AtomTree::insert_fragment: found new incoming connection: " << atom->atom_id() << std::endl;
2037  // now want to generate a StubID for this guy as well as a local stub
2038  if ( atom->is_jump() ) {
2039  // incoming jump-atom connection -- or root of tree??
2040  // get local coords for all the stub atoms
2041  bool fail( false );
2042  StubID const stubid( atom->stub_atom1_id(), atom->stub_atom2_id(), atom->stub_atom3_id() );
2043  Stub const stub( get_frag_local_stub( stubid, frag_xyz, fail ) );
2044  if ( !fail ) {
2045  incoming_stub_frag_atoms.push_back( atom );
2046  incoming_local_stubs.push_back( stub );
2047  incoming_stub_ids.push_back( stubid );
2048  }
2049  assert( !fail ); // could fail
2050  } else {
2051  // incoming bonded-atom connection
2052  bool fail( false );
2053  StubID const stubid( get_frag_pseudo_stub_id( atom->atom_id(), frag_xyz, fail ) );
2054  if ( !fail ) {
2055  incoming_stub_frag_atoms.push_back( atom );
2056  incoming_stub_ids.push_back( stubid );
2057  incoming_local_stubs.push_back( get_frag_local_stub( stubid, frag_xyz, fail ) );
2058  assert( !fail ); // shouldnt fail for a frag_pseudo_stub -- all atoms are already in frag
2059  }
2060  assert( !fail ); // could fail
2061  }
2062  }
2063 
2064  // look for outgoing connections:
2065  for ( Size i=0; i< atom->n_children(); ++i ) {
2066  AtomOP child( atom->child(i) );
2067  if ( !frag_xyz.count( child->atom_id() ) &&
2068  ( std::find( outgoing_stub_nonfrag_atoms.begin(), outgoing_stub_nonfrag_atoms.end(), child ) ==
2069  outgoing_stub_nonfrag_atoms.end() ) ) {
2070  // new outgoing connection!
2071  TR.Trace << "AtomTree::insert_fragment: found new outgoing connection: " << atom->atom_id() << std::endl;
2072  bool fail( false );
2073  StubID const stubid( child->stub_atom1_id(), child->stub_atom2_id(), child->stub_atom3_id() );
2074  Stub const outstub( get_frag_local_stub( stubid, frag_xyz, fail ) );
2075  if ( !fail ) {
2076  outgoing_stub_nonfrag_atoms.push_back( child );
2077  outgoing_stub_ids.push_back( stubid );
2078  outgoing_local_stubs.push_back( outstub );
2079  }
2080  assert( !fail );
2081  }
2082  }
2083  }
2084 
2085 
2086  /// Now associate outgoing stubs and frag atoms with the incoming stubs, call insert_single_fragment once for each
2087  /// incoming stub.
2088  ///
2089  for ( Size i=1; i<= incoming_stub_frag_atoms.size(); ++i ) {
2090  AtomCOP instub_atom( incoming_stub_frag_atoms[i] );
2091  Stub const & local_instub( incoming_local_stubs[ i ] );
2092  FragXYZ new_frag_xyz;
2093  FragRT new_outstub_transforms;
2094  // get frag atoms that depend on this guy:
2095  for ( FragXYZ::const_iterator it=frag_xyz.begin(), ite= frag_xyz.end(); it != ite; ++it ) {
2096  AtomID const & id( it->first );
2097  AtomCOP frag_atom( atom_pointer( id ) );
2098  if ( frag_atom->atom_is_on_path_from_root( instub_atom ) ) {
2099  new_frag_xyz[ id ] = local_instub.global2local( it->second );
2100  }
2101  }
2102  for ( Size j=1; j<= outgoing_stub_nonfrag_atoms.size(); ++j ) {
2103  AtomCOP outstub_atom( outgoing_stub_nonfrag_atoms[j] );
2104  if ( outstub_atom->atom_is_on_path_from_root( instub_atom ) ) {
2105  new_outstub_transforms[ outgoing_stub_ids[j] ] = RT( local_instub, outgoing_local_stubs[j] );
2106  }
2107  }
2108 
2109  TR.Trace << "AtomTree::insert_fragment: inserting single fragment nout= " << new_outstub_transforms.size() <<
2110  " natoms= " << new_frag_xyz.size() << std::endl;
2111 
2112  insert_single_fragment( incoming_stub_ids[i], new_outstub_transforms, new_frag_xyz, moving_atoms );
2113  }
2114 
2115 
2116 }
2117 
2118 
2119 /// @details Useful for guaranteeing that a stub remains within a single residue
2120 void
2122 {
2123  update_xyz_coords(); // since we are about to invalidate the internal coords
2124 
2125  AtomOP parent( atom_pointer( parent_atom_id ) );
2126  tree::AtomOP sameresidue_child( 0 );
2127  for ( Size i=0; i< parent->n_nonjump_children(); ++i ) {
2128  tree::AtomOP child( atom_pointer( parent->get_nonjump_atom( i )->id() ) ); // want nonconst, use atom_pointer
2129  if ( child->id().rsd() == parent->id().rsd() ) {
2130  sameresidue_child = child;
2131  break;
2132  }
2133  }
2134  if ( sameresidue_child ) {
2135  assert( !sameresidue_child->is_jump() );
2136  parent->delete_atom( sameresidue_child );
2137  parent->insert_atom( sameresidue_child );
2138  } else {
2139  TR.Warning << "promote_sameresidue_nonjump_child failed, parent has no non-jump, same-residue children!" <<
2140  std::endl;
2141  }
2142 
2144  set_new_topology();
2145 }
2146 
2147 
2148 
2149 
2150 // while ( it != path1.end() &&
2151 // std::find( stub1_ids.begin(), stub1_ids.end(), (*it)->parent()->atom_id() ) != stub1_ids.end() ) ++it;
2152 // if ( it == path1.end() ) {
2153 // it = path2.begin();
2154 // while ( it != path2.end() &&
2155 // std::find( stub2_ids.begin(), stub2_ids.end(), (*it)->parent()->atom_id() ) != stub2_ids.end() ) ++it;
2156 // if ( it == path2.end() ) {
2157 // utility_exit_with_message( "AtomTree::make_stub_transform: Unable to find bond to cut!" );
2158 // }
2159 // }
2160 // }
2161 
2162 
2163 } // namespace kinematics
2164 } // namespace core
2165 // // we use the internal dof's if necessary to calculate the offset
2166 // assert( !internal_coords_need_updating_ );
2167 
2168 // offset = 0.0;
2169 
2170 // assert( atom_pointer_[ atom_id1 ] && atom_pointer_[ atom_id2 ] &&
2171 // atom_pointer_[ atom_id3 ] && atom_pointer_[ atom_id4 ] );
2172 
2173 // // STUART -- (low priority) I'd like to be able to cache
2174 // // the results of this calculation to allow faster access.
2175 
2176 
2177 // // reorder the atoms if necessary so that atom2 is the parent of atom3
2178 // // and atom3 is the parent of atom4
2179 // AtomOPatom1( 0 ), *atom2( 0 ), *atom3( 0 ), *atom4( 0 );
2180 
2181 // if ( atom_pointer_[ atom_id3 ]->parent()->atom_id() == atom_id2 ) {
2182 // atom1 = atom_pointer_[ atom_id1 ];
2183 // atom2 = atom_pointer_[ atom_id2 ];
2184 // atom3 = atom_pointer_[ atom_id3 ];
2185 // atom4 = atom_pointer_[ atom_id4 ];
2186 // } else if ( atom_pointer_[ atom_id2 ]->parent()->atom_id() == atom_id3 ) {
2187 // atom1 = atom_pointer_[ atom_id4 ];
2188 // atom2 = atom_pointer_[ atom_id3 ];
2189 // atom3 = atom_pointer_[ atom_id2 ];
2190 // atom4 = atom_pointer_[ atom_id1 ];
2191 // } else {
2192 // // no good!
2193 // return BOGUS_DOF_ID;
2194 // }
2195 // assert( atom3->parent() == atom2 );
2196 // if ( atom4->parent() != atom3 ) {
2197 // // also no good
2198 // return BOGUS_DOF_ID;
2199 // } else if ( atom4->is_jump() ) {
2200 // // also no good
2201 // return BOGUS_DOF_ID;
2202 // }
2203 
2204 
2205 // Atom const
2206 // *dof_atom1( atom2->parent() ),
2207 // *dof_atom4( atom3->get_nonjump_atom(0) ); // guaranteed not a jump
2208 
2209 // // this is the answer:
2210 // DOF_ID dof_id( dof_atom4->atom_id(), PHI );
2211 
2212 
2213 // ///////////////////////////////////////////////////////////////////////////
2214 // // handle the easiest case: perfect match with an atomtree DOF
2215 // //
2216 // if ( dof_atom1 == atom1 &&
2217 // dof_atom4 == atom4 ) {
2218 // assert( &(atom4->input_stub_atom0()) == atom3 &&
2219 // &(atom4->input_stub_atom1()) == atom3 &&
2220 // &(atom4->input_stub_atom2()) == atom2 &&
2221 // &(atom4->input_stub_atom3()) == atom1 );
2222 
2223 // offset = 0.0;
2224 // return dof_id;
2225 // }
2226 
2227 // // now calculate the offset
2228 // // by summing contributions from both ends
2229 // offset = 0.0;
2230 
2231 // // handle offset between atom4 and atom3's first child
2232 // // note that we already know that atom4 is one of atom3's children
2233 // // ( see above )
2234 // //
2235 // if ( dof_atom4 != atom4 ) {
2236 
2237 // // recall: torsion(atom1-4) = dof(dof_id) + offset
2238 // //
2239 // offset += atom3->dihedral_between_bonded_children( dof_atom4, atom4 );
2240 // }
2241 
2242 
2243 // // handle offset between atom1 and true atom1
2244 // // the only case we can do is if atom1->parent() == atom2
2245 // //
2246 // // this will happen, eg for chi1 if we are folding c2n:
2247 // //
2248 // // atom1 = N while dof_atom1 = parent(atom2) = C
2249 // // atom2 = CA
2250 // // atom3 = CB
2251 // // atom4 = CG
2252 // //
2253 // if ( dof_atom1 != atom1 ) {
2254 // if ( atom1->parent() != atom2 || atom1->is_jump() ) {
2255 // // no good!
2256 // return BOGUS_DOF_ID;
2257 // }
2258 
2259 // // a little tricky: we don't want to access the positions,
2260 // // since we can't be sure that they are up to date in a routine
2261 // // that would be called inside dof setting and getting routines
2262 // //
2263 // //
2264 // // need to use some spherical geometry
2265 // //
2266 // // we've got three unit vectors:
2267 // //
2268 // // u1 -- from atom2 to atom1
2269 // // u2 -- from dof_atom1 to atom2
2270 // // u3 -- from atom2 to atom3
2271 // //
2272 // // the angle between u2 and u1 = theta1 = atom1(THETA)
2273 // // the angle between u2 and u3 = theta3 = atom3(THETA)
2274 // // the torsion between u1 and u3 along u2 = phi2 = atom2->bonded_dih(1,3)
2275 // //
2276 // Real
2277 // theta1( atom1->dof( THETA ) ),
2278 // theta3( atom3->dof( THETA ) ),
2279 // phi2( atom2->dihedral_between_bonded_children( atom1, atom3 ) );
2280 
2281 // // want to solve for phi3 -- dihedral between u2 and u1 along axis
2282 // // defined by u3
2283 // //
2284 // // spherical law of cosines says:
2285 // //
2286 // // cos(theta2) = cos(theta1) * cos(theta3) +
2287 // // sin(theta1) * sin(theta3) * cos(phi2)
2288 // //
2289 // // so we can solve for cos(theta2); then use formula again to solve for
2290 // // cos(phi3).
2291 // //
2292 // Real cos_theta2 = std::cos( theta1 ) * std::cos( theta3 ) +
2293 // std::sin( theta1 ) * std::sin( theta3 ) * std::cos( phi2 );
2294 
2295 // Real sin_theta2 = std::sqrt( 1 - cos_theta2 * cos_theta2 );
2296 
2297 // // use formula again interchanging 2 and 3
2298 // Real cos_phi3 = ( cos( theta3 ) - cos( theta1 ) * cos_theta2 ) /
2299 // ( sin( theta1 ) * sin_theta2 );
2300 
2301 // // PHIL! really should handle degenerate cases more carefully
2302 // // PHIL! also could reuse some of the trig calculations
2303 
2304 
2305 // std::cout << "PHIL: calculate the sign factor in AtomTree::torsion_angle_dof_id!" << std::endl;
2306 
2307 // Real sign_factor( 1.0 ); // this is not correct
2308 
2309 // offset += sign_factor * std::acos( cos_phi3 );
2310 
2311 // }
2312 
2313 // // offset is passed out by reference
2314 // return dof_id;
2315 // }
2316 // /////////////////////////////////////////////////////////////////////////////
2317 // /// tmp hack
2318 
2319 // class AtomBondChecker {
2320 // public:
2321 // typedef id::BondID BondID;
2322 
2323 // public:
2324 
2325 // AtomBondChecker( utility::vector1< BondID > const & bonds_in ):
2326 // bonds_( bonds_in )
2327 // {}
2328 
2329 
2330 // bool
2331 // operator()( AtomCOP const & atom )
2332 // {
2333 // BondID id( atom->atom_id(), atom->parent()->atom_id() );
2334 // if ( std::find( bonds_.begin(), bonds_.end(), id ) == bonds_.end() ) id.reverse();
2335 
2336 // // return true if bond between atom and parent is in the list:
2337 // return ( std::find( bonds_.begin(), bonds_.end(), id ) != bonds_.end() );
2338 // }
2339 
2340 // private:
2341 // utility::vector1< BondID > bonds_;
2342 
2343 
2344 // };
2345 
2346 // vector1< id::StubID > const & outstub_ids,
2347 // vector1< RT > const & outstub_transforms,
2348 // vector1< AtomID > const & frag_ids,
2349 // vector1< Vector > const & frag_xyz, // or use std::map< AtomID, Vector > ??
2350 // AtomID id1( child.atom_id() ),id2,id3;
2351 // if ( child->n_nonjump_children() == 0 ) {
2352 // fail = true;
2353 // return Vector(0.0);
2354 // } else if ( child->n_nonjump_children() == 1 ) {
2355 // AtomCOP gchild( child->get_nonjump_atom( 0 ) ); // frag or child of frag
2356 // id2 = gchild->atom_id();
2357 // if ( gchild->n_nonjump_children() == 0 ) {
2358 // fail = true;
2359 // return Vector(0.0);
2360 // } else {
2361 // id3 = gchild->get_nonjump_atom(0)->atom_id(); // frag or child of frag or grandchild of frag
2362 // }
2363 // } else {
2364 // id2 = child->get_nonjump_atom(0)->atom_id(); // frag or child of frag
2365 // id3 = child->get_nonjump_atom(1)->atom_id(); // frag or child of frag
2366 // }
2367 // /////////////////////////////////////////////////////////////////////////////
2368 // /////////////////////////////////////////////////////////////////////////////
2369 // // private, called recursively
2370 // //
2371 // void
2372 // AtomTree::insert_stub_transforms(
2373 // id::StubID const & instub_id,
2374 // utility::vector1< id::StubID > const & outstub_ids,
2375 // utility::vector1< RT > const & transforms,
2376 // id::AtomID_Mask & exclude,
2377 // utility::vector1< id::AtomID > & moved_atoms
2378 // )
2379 // {
2380 // assert( outstub_ids.size() == transforms.size() );
2381 // Size const nstub( outstub_ids.size() );
2382 
2383 // // build vector of stub atom ids
2384 
2385 // // trim stub atom ids to exclude overlapping atoms
2386 
2387 // vector1< vector1< AtomCOP > > paths( nstub );
2388 // for ( Size i=1; i<= nstub; ++i ) {
2389 // get_atom_path( out_atom_ids[i][1], in_atom_ids[1], paths[i] );
2390 // sizes.push_back( paths[i].size () );
2391 // }
2392 
2393 // ///
2394 // Size const stub_index( argmin( sizes ) ); // see rotamer_trials.cc
2395 // vector1< AtomCOP > stub_path( paths[ stub_index ] );
2396 
2397 
2398 // /// choose an atom to move ///////////////////////////////////////////////
2399 // AtomOP moving_atom( 0 );
2400 // // first look for jump atom:
2401 // for ( Size i=1; i<= stub_path.size(); ++i ) {
2402 // AtomID const & id( stub_path[i]->atom_id() );
2403 // if ( !excluded[ id ] && stub_path[i]->is_jump() ) {
2404 // moving_atom = atom_pointer_[ id ];
2405 // break;
2406 // }
2407 // }
2408 // for ( Size i=1; i<= stub_path.size(); ++i ) {
2409 // AtomID const & id( stub_path[i]->atom_id() );
2410 // if ( !excluded[ id ] ) {
2411 // excluded[ id ] = true;
2412 // if ( !moving_atom ) moving_atom = atom_pointer_[ id ];
2413 // break;
2414 // }
2415 // }
2416 // if ( !moving_atom ) utility_exit_with_message( "AtomTree stub fragment insertion failed!!" );
2417 
2418 // bool const moving_atom_on_incoming_root_path( my_path.back()->atom_is_on_root_path( moving_atom ) );
2419 // assert( moving_atom_on_incoming_root_path || my_path.front()->atom_is_on_root_path( moving_atom ) );
2420 
2421 // //// now figure out what transform we need to apply
2422 // Stub stub1( xyz( stub1_id.atom1 ), xyz( stub1_id.atom2 ), xyz( stub1_id.atom3 ) );
2423 // Stub stub2( xyz( stub2_id.atom1 ), xyz( stub2_id.atom2 ), xyz( stub2_id.atom3 ) );
2424 // RT rt( target_rt );
2425 // if ( moving_atom_on_path1 ) {
2426 // // in this case when we transform the atom we will actually move the stub1 atoms, so reverse for consistency
2427 // rt.reverse();
2428 // Stub const tmp( stub1 );
2429 // stub1 = stub2;
2430 // stub2 = tmp;
2431 // }
2432 
2433 // // now things are arranged so that when we transform moving_atom and children, stub1 stays fixed and stub2 moves.
2434 // // and we want RT( stub1, new_stub2 ) == target_rt
2435 
2436 // Stub::Matrix const & M1( stub1.M ), M2( stub2.M ), R( rt.get_rotation() );
2437 // Vector const & v1( stub1.v ), v2( stub2.v ), t( rt.get_translation() );
2438 
2439 // // look for a transformation of the form x |----> A*x + b
2440 // //
2441 // // this will change stub2 to stub2' with M2' = A * M2, v2' = A*v2 + b
2442 // //
2443 // // if we let (R,t) be the target RT, then we want
2444 // //
2445 // // R = M1^T * M2' = M1^T * A * M2 ==> A = M1 * R * M2^T
2446 // //
2447 // // t = M1^T * ( v2' - v1 ) ==> v2' = M1 * t + v1, which with b = v2' - A*v2 gives b = M1 * t + v1 - A * v2
2448 // //
2449 
2450 // Stub::Matrix const A( M1 * R * M2.transposed() );
2451 // Vector const b( M1 * t + v1 - A * v2 );
2452 
2453 // update_xyz_coords();
2454 
2455 // moving_atom->transform_Ax_plus_b_recursive( A, b );
2456 // internal_coords_need_updating_ = true;
2457 
2458 
2459 // { // debug
2460 // Stub const new_stub1( xyz( stub1_id.atom1 ), xyz( stub1_id.atom2 ), xyz( stub1_id.atom3 ) );
2461 // Stub const new_stub2( xyz( stub2_id.atom1 ), xyz( stub2_id.atom2 ), xyz( stub2_id.atom3 ) );
2462 // RT const new_rt( new_stub1, new_stub2 );
2463 // std::cout << "debugRTD: " << new_rt.distance_squared( target_rt ) << std::endl;
2464 
2465 // assert( new_rt.distance_squared( target_rt ) < 1e-3 );
2466 // }
2467 
2468 // //// tell the outside world which atom we moved (ie subtree rooted at this atom has moved)
2469 // return moving_atom->atom_id();
2470 
2471 // }
2472 
2473 
2474 // /////////////////////////////////////////////////////////////////////////////
2475 
2476 // id::AtomID
2477 // AtomTree::make_stub_transform(
2478 // id::StubID const & stub1_id, // triplet of atomids
2479 // id::StubID const & stub2_id, // triplet of atomids
2480 // RT const & target_rt,
2481 // utility::vector1< id::BondID > const & preferred_bonds
2482 // )
2483 // {
2484 // //using tree::Atom;
2485 
2486 // //// get path between origin atoms of both stubs /////////////////////
2487 // utility::vector1< AtomCOP > path1, path2;
2488 
2489 // AtomOP const stub1_atom1( atom_pointer_[ stub1_id.atom1 ] );
2490 // AtomOP const stub2_atom1( atom_pointer_[ stub2_id.atom1 ] );
2491 
2492 
2493 // stub1_atom1->get_path_from_root( path1 );
2494 // stub2_atom1->get_path_from_root( path2 );
2495 
2496 // assert( path1.front() == root_ && path2.front() == root_ &&
2497 // path1.back () == stub1_atom1 && path2.back () == stub2_atom1 );
2498 
2499 // //// Now remove all the common ancestors, and reverse the paths so they start at stub origin atoms
2500 // {
2501 // Size lcai(1); // last_common_ancestor_index
2502 // Size const s1( path1.size() );
2503 // Size const s2( path2.size() );
2504 // while ( lcai < s1 && lcai < s2 ) {
2505 // ++lcai;
2506 // if ( path1[ lcai ] != path2[ lcai ] ) {
2507 // --lcai;
2508 // break;
2509 // }
2510 // }
2511 // path1.erase( path1.begin(), path1.begin() + lcai );
2512 // path2.erase( path2.begin(), path2.begin() + lcai );
2513 // assert( path1.empty() || path2.empty() ||
2514 // ( path1[ 1 ] != path2[ 1 ] && path1[ 1 ]->parent() == path2[ 1 ]->parent() ) );
2515 // std::reverse( path1.begin(), path1.end() );
2516 // std::reverse( path2.begin(), path2.end() );
2517 // assert( path1.empty() || path1[ 1 ] == stub1_atom1 );
2518 // assert( path2.empty() || path2[ 1 ] == stub2_atom1 );
2519 
2520 
2521 // // trim backward to get past all stub atoms
2522 // utility::vector1< AtomID > stub1_ids, stub2_ids;
2523 // stub1_ids.push_back( stub1_id.atom1 );
2524 // stub1_ids.push_back( stub1_id.atom2 );
2525 // stub1_ids.push_back( stub1_id.atom3 );
2526 // stub2_ids.push_back( stub2_id.atom1 );
2527 // stub2_ids.push_back( stub2_id.atom2 );
2528 // stub2_ids.push_back( stub2_id.atom3 );
2529 // while ( !path1.empty() &&
2530 // std::find( stub1_ids.begin(), stub1_ids.end(), path1.front()->parent()->atom_id() ) != stub1_ids.end() ) {
2531 // path1.erase( path1.begin() );
2532 // }
2533 // while ( !path2.empty() &&
2534 // std::find( stub2_ids.begin(), stub2_ids.end(), path2.front()->parent()->atom_id() ) != stub2_ids.end() ) {
2535 // path2.erase( path2.begin() );
2536 // }
2537 // }
2538 
2539 
2540 // // use this to find atoms whose bond to a parent is in preferred_bond_ids
2541 // AtomBondChecker bond_checker( preferred_bonds );
2542 
2543 // //// first look for a jump on either path that matches the preferred_bonds set
2544 
2545 // // make paths with just the jump atoms
2546 // utility::vector1< AtomCOP > path1_jumps, path2_jumps;
2547 // for ( Size i=1; i<= path1.size(); ++i ) if ( path1[i]->is_jump() ) path1_jumps.push_back( path1[i] );
2548 // for ( Size i=1; i<= path2.size(); ++i ) if ( path2[i]->is_jump() ) path2_jumps.push_back( path2[i] );
2549 
2550 // utility::vector1< AtomCOP >::iterator it = find_if( path1_jumps.begin(), path1_jumps.end(), bond_checker );
2551 // if ( it == path1_jumps.end() ) it = find_if( path2_jumps.begin(), path2_jumps.end(), bond_checker );
2552 // if ( it == path2_jumps.end() ) it = find_if( path1.begin(), path1.end(), bond_checker );
2553 // if ( it == path1.end() ) it = find_if( path2.begin(), path2.end(), bond_checker );
2554 // if ( it == path2.end() ) {
2555 // // no atoms matched the preferred bonds set
2556 // // choose a jump if it exists
2557 // // otherwise choose ...
2558 
2559 // if ( !path1_jumps.empty() ) {
2560 // it = path1_jumps.begin();
2561 // } else if ( ! path2_jumps.empty() ) {
2562 // it = path2_jumps.begin();
2563 // } else if ( !path1.empty() ) {
2564 // it = path1.begin();
2565 // } else if ( !path2.empty() ) {
2566 // it = path2.begin();
2567 // } else {
2568 // utility_exit_with_message( "AtomTree::make_stub_transform: Unable to find bond to cut!" );
2569 // }
2570 // }
2571 
2572 // AtomOP moving_atom( atom_pointer_[ (*it)->atom_id() ] ); // get nonconst version
2573 // bool const moving_atom_on_path1( std::find( path1.begin(), path1.end(), *it ) != path1.end() );;
2574 
2575 // //// now figure out what transform we need to apply
2576 // Stub stub1( xyz( stub1_id.atom1 ), xyz( stub1_id.atom2 ), xyz( stub1_id.atom3 ) );
2577 // Stub stub2( xyz( stub2_id.atom1 ), xyz( stub2_id.atom2 ), xyz( stub2_id.atom3 ) );
2578 // RT rt( target_rt );
2579 // if ( moving_atom_on_path1 ) {
2580 // // in this case when we transform the atom we will actually move the stub1 atoms, so reverse for consistency
2581 // rt.reverse();
2582 // Stub const tmp( stub1 );
2583 // stub1 = stub2;
2584 // stub2 = tmp;
2585 // }
2586 
2587 // // now things are arranged so that when we transform moving_atom and children, stub1 stays fixed and stub2 moves.
2588 // // and we want RT( stub1, new_stub2 ) == target_rt
2589 
2590 // Stub::Matrix const & M1( stub1.M ), M2( stub2.M ), R( rt.get_rotation() );
2591 // Vector const & v1( stub1.v ), v2( stub2.v ), t( rt.get_translation() );
2592 
2593 // // look for a transformation of the form x |----> A*x + b
2594 // //
2595 // // this will change stub2 to stub2' with M2' = A * M2, v2' = A*v2 + b
2596 // //
2597 // // if we let (R,t) be the target RT, then we want
2598 // //
2599 // // R = M1^T * M2' = M1^T * A * M2 ==> A = M1 * R * M2^T
2600 // //
2601 // // t = M1^T * ( v2' - v1 ) ==> v2' = M1 * t + v1, which with b = v2' - A*v2 gives b = M1 * t + v1 - A * v2
2602 // //
2603 
2604 // Stub::Matrix const A( M1 * R * M2.transposed() );
2605 // Vector const b( M1 * t + v1 - A * v2 );
2606 
2607 // update_xyz_coords();
2608 
2609 // moving_atom->transform_Ax_plus_b_recursive( A, b );
2610 // internal_coords_need_updating_ = true;
2611 
2612 
2613 // { // debug
2614 // Stub const new_stub1( xyz( stub1_id.atom1 ), xyz( stub1_id.atom2 ), xyz( stub1_id.atom3 ) );
2615 // Stub const new_stub2( xyz( stub2_id.atom1 ), xyz( stub2_id.atom2 ), xyz( stub2_id.atom3 ) );
2616 // RT const new_rt( new_stub1, new_stub2 );
2617 // std::cout << "debugRTD: " << new_rt.distance_squared( target_rt ) << std::endl;
2618 
2619 // assert( new_rt.distance_squared( target_rt ) < 1e-3 );
2620 // }
2621 
2622 // //// tell the outside world which atom we moved (ie subtree rooted at this atom has moved)
2623 // return moving_atom->atom_id();
2624 
2625 // }
2626 
2627