Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Atom_.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/tree/Atom_.cc
11 /// @brief Kinematics Atom abstract base class
12 /// @author Phil Bradley
13 
14 
15 // Unit headers
17 
18 // Package headers
21 // AUTO-REMOVED #include <core/id/AtomID_Mask.hh>
22 
23 // ObjexxFCL headers
24 #include <ObjexxFCL/FArray1D.hh>
25 
26 // Utility headers
27 #include <utility/exit.hh>
28 #include <basic/Tracer.hh>
29 #include <ObjexxFCL/format.hh>
30 
31 // C++ headers
32 #include <iostream>
33 
34 #include <core/id/AtomID_Map.hh>
35 #include <core/kinematics/Stub.hh>
36 #include <core/kinematics/types.hh>
37 #include <utility/vector1.hh>
38 #include <numeric/xyz.functions.hh>
39 
40 namespace core {
41 namespace kinematics {
42 namespace tree {
43 
44 static basic::Tracer TR("core.kinematics.tree.Atom_");
45 
46 void
48  AtomAP weak_ptr
49 )
50 {
51  assert( weak_ptr() == this );
52  this_weak_ptr_ = weak_ptr;
53 }
54 
55 /////////////////////////////////////////////////////////////////////////////
56 /// @details get the input stub for building this atom first
57 void
59 {
60  Stub stub( get_input_stub() );
61  update_xyz_coords( stub );
62 }
63 
64 
65 /////////////////////////////////////////////////////////////////////////////
66 /// @details get the input stub for building this atom first
67 void
69  bool const recursive
70 )
71 {
72  Stub stub( get_input_stub() );
73  update_internal_coords( stub, recursive );
74 }
75 
76 
77 /////////////////////////////////////////////////////////////////////////////
78 /// @details When this atom is added, it will call this function recursively for all its
79 /// children atoms first. The end condition is for those tip atoms in the tree,
80 /// i.e., without children. After this function is finished, this atom and all its
81 /// children (and their children) should be updated properly in the map
82 // void
83 // Atom_::update_atom_pointer(
84 // AtomPointers & atom_pointer,
85 // bool const allow_overwriting // = false
86 // )
87 // {
88 // // our atom_id shouldn't exist in the map yet, unless allowing overwriting
89 // assert( allow_overwriting || ! atom_pointer.has( atom_id_ ) || atom_pointer[ atom_id_ ] == 0 );
90 // atom_pointer.set( atom_id_, this ); // slow
91 // for ( Atoms::const_iterator a = atoms_.begin(), a_end = atoms_.end(); a != a_end; ++a ) {
92 // (*a)->update_atom_pointer( atom_pointer, allow_overwriting );
93 // }
94 // }
95 
96 
97 /////////////////////////////////////////////////////////////////////////////
98 /// @details first this atom, then its parent and then recursively all its children
99 void
100 Atom_::show() const
101 {
102  std::cout << "ATOM: " << atom_id_ << std::endl;
103  std::cout << " PARENT: ";
104  if ( parent_ ) {
105  std::cout << parent_->id() << std::endl;
106  std::cout << " GRAND PARENT: ";
107  if ( static_cast< Atom_* >( parent_() )->parent_ ) {
108  std::cout << static_cast< Atom_* >( parent_() )->parent_->id() << std::endl;
109  } else {
110  std::cout << " NULL" << std::endl;
111  }
112 
113  } else {
114  std::cout << " NULL" << std::endl;
115  }
116 
117  std::cout << " CHILDREN: ";
118  for ( Atoms::const_iterator it= atoms_.begin(), it_end = atoms_.end(); it != it_end; ++it ) {
119  std::cout << (*it)->id() << ' ';
120  }
121  std::cout << std::endl;
122  for ( Atoms::const_iterator it= atoms_.begin(), it_end = atoms_.end(); it != it_end; ++it ) {
123  (*it)->show();
124  }
125 }
126 
127 /////////////////////////////////////////////////////////////////////////////
128 /// @details first this atom, then its parent and then recursively all its children up to n_level
129 void
130 Atom_::show(int const & n_level) const
131 {
132  using namespace ObjexxFCL::fmt;
133  TR << "ATOM: " << atom_id_ << std::endl;
134  TR << "POSITION: " << F(8,3,x()) << F(8,3,y()) << F(8,3,z()) << std::endl;
135  TR << " PARENT: ";
136  if ( parent_ ) {
137  TR << parent_->id() << std::endl;
138  TR << " GRAND PARENT: ";
139  if ( static_cast< Atom_* >( parent_() )->parent_ ) {
140  TR << static_cast< Atom_* >( parent_() )->parent_->id() << std::endl;
141  } else {
142  TR << " NULL" << std::endl;
143  }
144 
145  } else {
146  TR << " NULL" << std::endl;
147  }
148 
149  TR << " CHILDREN: ";
150  for ( Atoms::const_iterator it= atoms_.begin(), it_end = atoms_.end(); it != it_end; ++it ) {
151  TR << (*it)->id() << ' ';
152  }
153  TR << std::endl;
154 
155  //TR << "Yifan debug: " << n_level << std::endl;
156  if (n_level > 0) {
157  int const next_level(n_level - 1);
158  for ( Atoms::const_iterator it= atoms_.begin(), it_end = atoms_.end(); it != it_end; ++it ) {
159  (*it)->show(next_level);
160  }
161  }
162 }
163 
164 
165 
166 /////////////////////////////////////////////////////////////////////////////
167 /// @details update domain map for this atom and all its offspring
168 /// consider this like a graph coloring problem. we are recursively (depth-first)
169 /// assigning a color to each atom.
170 //
171 // this should probably be debugged more thoroughly
172 //
173 void
175  int & current_color,
176  int & biggest_color,
177  DomainMap & domain_map,
178  AtomID_Mask const & dof_moved,
179  AtomID_Mask const & atom_moved
180 ) const
181 {
182  int color( current_color );
183 
184  bool const my_dof_moved( dof_moved[ atom_id_ ] );
185  bool const my_xyz_moved( atom_moved[ atom_id_ ] );
186 
187  if ( my_dof_moved ) {
188  ++biggest_color;
189  if ( !is_jump() ) {
190  // propagates through atoms after me in the list of my parent's childrn
191  // that's assuming its the phi-torsion that's changed
192  // note that current_color is passed by reference
193  current_color = biggest_color;
194  // but if my D or THETA dof's are changing then myself
195  // and my children will be on a different rigid-body from
196  // my younger siblings
197  ++biggest_color;
198  }
199  color = biggest_color;
200  }
201 
202  // update domain_map
203  int const current_map( domain_map( atom_id_.rsd() ) );
204  if ( !my_dof_moved && my_xyz_moved ) {
205  // no propagating change, but my xyz coords have changed
206  domain_map( atom_id_.rsd() ) = 0;
207  } else if ( current_map < 0 ) {
208  // unassigned
209  domain_map( atom_id_.rsd() ) = color;
210  } else if ( current_map == 0 || current_map == color ) {
211  // leave the same
212  } else {
213  // color change within a residue
214  domain_map( atom_id_.rsd() ) = 0;
215  }
216 
217 
218  for ( Atoms::const_iterator it= atoms_.begin(), it_end = atoms_.end(); it != it_end; ++it ) {
219  (*it)->update_domain_map( color, biggest_color, domain_map, dof_moved, atom_moved );
220  }
221 }
222 
223 
224 /////////////////////////////////////////////////////////////////////////////
225 /// @details if the child atom is a jump atom, put it before all the non-jump children
226 /// atoms but after all the children jump atoms. Otherwise, put it at the end
227 /// of the children atom list.
228 void
230  AtomOP const atom
231 )
232 {
233  assert( this_weak_ptr_ );
234  atom->parent( this_weak_ptr_ ); // Note: You cannot give "this" to the child atom, or you will loose the reference-count information using boost::weak_ptr
235  if ( atom->is_jump() ) {
236  atoms_.insert( nonjump_atoms_begin(), atom );
237  } else {
238  atoms_.push_back(atom);
239  }
240 }
241 
242 /////////////////////////////////////////////////////////////////////////////
243 /// @details only unlink the child atom from this atom (parent). No recursive operation or
244 /// freeing memory( use Atom_::erase() to free up memory for an atom and all its
245 /// children
246 void
248  AtomOP const child
249 )
250 {
251  Atoms::iterator const iter( std::find( atoms_.begin(), atoms_.end(), child ) );
252  if ( iter == atoms_.end() ) {
253  std::cerr << "child not present in atoms list! " << atoms_.size() << std::endl;
254  utility_exit();
255  }
256  atoms_.erase( iter );
257 }
258 
259 /////////////////////////////////////////////////////////////////////////////
260 /// @details if the child atom is a jump atom, put it before all jump children atoms;
261 /// otherwise, put it before all non-jump children atoms; Different from
262 /// Atom_::append_atom in that it put the new child atom before instead after
263 /// the other existing child atoms.
264 void
266  AtomOP const atom
267 )
268 {
269  assert( this_weak_ptr_ );
270  atom->parent( this_weak_ptr_ ); // Note: you cannot give "this" to the child, or the reference-count information will be lost with boost::weak_ptr.
271  if ( atom->is_jump() ) {
272  atoms_.insert( atoms_.begin(), atom );
273  } else {
274  atoms_.insert( nonjump_atoms_begin(), atom );
275  }
276 }
277 
278 /////////////////////////////////////////////////////////////////////////////
279 /// @details insert the child atom in a specified position. If the specified postion is
280 /// out of range, put it either at the beginning or the end of the child atom list.
281 /// note that jump child atoms are always listed before non-jump atoms and the
282 /// index must be a non-negative integer.
283 void
285  AtomOP const atom,
286  int const index
287 )
288 {
289  assert( this_weak_ptr_ );
290  atom->parent( this_weak_ptr_ ); // Note: you cannot give "this" to the child, or the reference-count information will be lost with boost::weak_ptr
291 
292  assert( index >= 0 );
293  Atoms::iterator pos( atoms_.begin() + index );
294  if ( atom->is_jump() ) {
295  if ( pos > nonjump_atoms_begin() ) pos = nonjump_atoms_begin();
296  } else {
297  if ( pos < nonjump_atoms_begin() ) {
298  pos = nonjump_atoms_begin();
299  //if ( keep_1st_child_pos() ) ++pos;
300  }
301  if ( pos > atoms_.end() ) pos = atoms_.end();
302  }
303 
304 
305  atoms_.insert( pos, atom );
306 }
307 
308 /////////////////////////////////////////////////////////////////////////////
309 /// @details old atom and new atom need to belong to the same type ( either both jump
310 /// atoms or both non-jump atoms. New atom is inserted at the position of old
311 /// atom.
312 void
314  AtomOP const old_atom,
315  AtomOP const new_atom
316 )
317 {
318  assert( ( old_atom->is_jump() && new_atom->is_jump() ) ||
319  ( !old_atom->is_jump() && !new_atom->is_jump() ) );
320 
321  Atoms::iterator iter( std::find( atoms_.begin(), atoms_.end(), old_atom ) );
322  if ( iter == atoms_.end() ) {
323  std::cout << "old_atom not present in atoms list! " <<
324  atoms_.size() << std::endl;
325  assert( false );
326  utility_exit();
327  }
328  new_atom->parent( this_weak_ptr_ ); // Note: you cannot give "this" to the child atom, or the reference-count data will be lost with boost::weak_ptr
329  iter = atoms_.insert( iter, new_atom );
330  // std::cout << (*iter == new_atom) << ' ' <<
331  // (*iter == old_atom) << std::endl;
332  ++iter;
333  assert( *iter == old_atom );
334  atoms_.erase( iter );
335 }
336 
337 
338 /////////////////////////////////////////////////////////////////////////////
339 /// @details returns 0 if atom doesnt exist
340 AtomCOP
342  Size const index
343 ) const
344 {
345  Atoms::const_iterator iter( nonjump_atoms_begin() );
346  iter += index;
347  if ( iter >= atoms_.end() ) {
348  return 0;
349  } else {
350  return *iter;
351  }
352 }
353 
354 
355 /////////////////////////////////////////////////////////////////////////////
356 /// @details delete an atom (free memory) and recursively for all its children.
357 /// reset its children's list.
358 // void
359 // Atom_::erase()
360 // {
361 // for ( Atoms::iterator it = atoms_.begin(), it_end = atoms_.end(); it != it_end; ++it ) {
362 // (*it)->erase();
363 // delete *it;
364 // }
365 // atoms_.clear();
366 // }
367 
368 /////////////////////////////////////////////////////////////////////////////
369 Size
371 {
372  return atoms_.size();
373 }
374 
375 /////////////////////////////////////////////////////////////////////////////
376 AtomCOP
377 Atom_::child( Size const k ) const
378 {
379  return atoms_[k];
380 }
381 
382 
383 /////////////////////////////////////////////////////////////////////////////
384 AtomOP
385 Atom_::child( Size const k )
386 {
387  return atoms_[k];
388 }
389 
390 /////////////////////////////////////////////////////////////////////////////
391 /// @details the atom-index of this child
392 Size
394 {
395  assert( child->parent()() == this );
396  for ( Size k=0; k< atoms_.size(); ++k ) {
397  if ( atoms_[k] == child ) return k;
398  }
399  utility_exit_with_message( "problemo in Atom_'s atom list" );
400  return Size(-1);
401 }
402 
403 /////////////////////////////////////////////////////////////////////////////
404 /// @details the improper dihedral from child1 to child2 about my x-axis
405 /// (ie, axis defined by me and my parent for nonjump atoms). Since phi_ for
406 /// a non-first branched atom is defined as the improper angle offset with
407 /// respect to its previous sibling, we just need to add up all the offsets
408 /// between them.
409 ///
410 Real
412  AtomCOP child1,
413  AtomCOP child2
414 ) const
415 {
416  // debug args
417  if ( child1->parent()() != this || child2->parent()() != this ) {
418  utility_exit_with_message("Atom_::dihedral_between_bonded_children: atoms are not both my children!");
419  }
420  if ( child1->is_jump() || child2->is_jump() ) {
421  utility_exit_with_message("Atom_::dihedral_between_bonded_children: one of the atoms is a JumpAtom!");
422  }
423 
424  // keep track of which atoms we've seen and in what order
425  AtomCOP first_atom( 0 ), second_atom( 0 );
426 
427  Real phi_offset(0.0);
428 
430  it_end=atoms_end(); it != it_end; ++it ) {
431  if ( first_atom ) phi_offset += (*it)->dof(PHI);
432 
433  if ( *it == child1 || *it == child2 ) {
434  if ( first_atom ) {
435  second_atom = *it; // seen both
436  break;
437  } else {
438  first_atom = *it;
439  }
440  }
441  } // loop over nonjump atoms
442 
443  if ( !second_atom ) {
444  utility_exit_with_message("Atom_::dihedral_between_bonded_children: atoms not found!");
445  }
446  if ( second_atom == child1 ) phi_offset *= -1.0;
447  return phi_offset;
448 }
449 
450 
451 /////////////////////////////////////////////////////////////////////////////
452 // I don't know where this routine is used...
453 //
454 // I don't think it even works in trunk.
455 //
456 bool
458 {
459  for ( int ii=0, ie= n_children(); ii < ie; ++ii ) {
460  if ( child(ii) == atom1 ) {
461  return true;
462  } else {
463  if ( child(ii)->downstream( atom1 ) ) return true;
464  }
465  }
466  return false;
467 }
468 
469 
470 /////////////////////////////////////////////////////////////////////////////
471 /// @details my stub is center at myself. Normally for bonded atom, X direction is
472 /// from my parent to me; Z direction is perpendicular to the plane defined
473 /// by myself, my parent and my parent's parent
474 
475 Stub
477 {
478  return Stub(
479  position(),
480  stub_atom1()->position(),
481  stub_atom2()->position(),
482  stub_atom3()->position()
483  );
484 }
485 
486 
487 /////////////////////////////////////////////////////////////////////////////
488 /// @details the stub that is passed to me during folding, which is normally the stub
489 /// centered at the parent atom.
490 Stub
492 {
493  if ( parent_ ) {
494 // std::cout << "Get input stub: ";
495 // std::cout << "(0: " << input_stub_atom0()->atom_id().rsd() << ", "<< input_stub_atom0()->atom_id().atomno() << ") ";
496 // std::cout << "(1: " << input_stub_atom1()->atom_id().rsd() << ", "<< input_stub_atom1()->atom_id().atomno() << ") ";
497 // std::cout << "(2: " << input_stub_atom2()->atom_id().rsd() << ", "<< input_stub_atom2()->atom_id().atomno() << ") ";
498 // std::cout << "(3: " << input_stub_atom3()->atom_id().rsd() << ", "<< input_stub_atom3()->atom_id().atomno() << ") " << std::endl;
499  return Stub(
504  );
505  } else {
506  return default_stub;
507  }
508 }
509 
510 
511 /////////////////////////////////////////////////////////////////////////////
512 /// @details call parent's previous_child method to get its previous sibling; return 0
513 /// if no parent is present.
514 AtomCOP
516 {
517  if ( parent_ != 0 ) {
518  assert( this_weak_ptr_ );
519  return parent_->previous_child( this );
520  } else {
521  return 0;
522  }
523 }
524 
525 /////////////////////////////////////////////////////////////////////////////
526 /// @details return 0 if the input child is the first child in the list
527 AtomCOP
529  AtomCOP child
530 ) const
531 {
532  //std::cout << "atoms_.size() = " << atoms_.size() << std::endl;
533  Atoms::const_iterator iter( std::find( atoms_.begin(), atoms_.end(), child ) );
534  if ( iter == atoms_.end() ) {
535  std::cerr << "child not present in atoms list! " << atoms_.size() << std::endl;
536  utility_exit();
537  }
538  if ( iter == atoms_.begin() ) {
539  return 0;
540  } else {
541  --iter;
542  return *iter;
543  }
544 }
545 
546 /////////////////////////////////////////////////////////////////////////////
547 /// @details return 0 if the input child is the last child in the list
548 AtomOP
550  AtomCOP child
551 )
552 {
553  //std::cout << "atoms_.size() = " << atoms_.size() << std::endl;
554  Atoms::const_iterator iter( std::find( atoms_.begin(), atoms_.end(), child ) );
555  if ( iter == atoms_.end() ) {
556  std::cerr << "child not present in atoms list! " << atoms_.size() << std::endl;
557  utility_exit();
558  }
559  ++iter;
560  if ( iter == atoms_.end() ) {
561  return 0;
562  } else {
563  return *iter;
564  }
565 }
566 
567 
568 /////////////////////////////////////////////////////////////////////////////
569 /// @details
570 /// - bonded-atom always has its stub defined (from its parent)
571 /// - jump-atom needs to have at least three atoms (including itself) at its
572 /// end to define a stub, such as three linearly bonded atoms or two children
573 /// atoms bonded to itself.
574 bool
576 {
577  // have to handle a couple of cases here:
578 
579  // note -- in counting dependent atoms, exclude JumpAtom's
580  //
581 
582  // 1. no dependent atoms --> no way to define new coord sys
583  // on this end. ergo take parent's M and my xyz
584  //
585  // 2. one dependent atom --> no way to define unique coord
586  // on this end, still take parent's M and my xyz
587  //
588  // 3. two or more dependent atoms
589  // a) if my first atom has a dependent atom, use
590  // myself, my first atom, and his first atom
591  //
592  // b) otherwise, use
593  // myself, my first atom, my second atom
594  //
595 
596  if ( is_jump() ) {
597  AtomCOP first = get_nonjump_atom(0);
598  if ( first != 0 &&
599  ( first->get_nonjump_atom(0) != 0 || get_nonjump_atom(1) != 0 ) ) {
600  return true;
601  } else {
602  return false;
603  }
604  } else {
605  return true;
606  }
607 }
608 
609 
610 /////////////////////////////////////////////////////////////////////////////
611 /// @details the coordinates of the atom "*child" -- one of my children -- have
612 /// changed. This routine updates the torsions to reflect this. Useful
613 /// if we have just repacked or rotamer-trialed, ie sidechain atoms_
614 /// have moved but the backbone is still the same, more efficient than
615 /// calling update_internal_coords on the entire tree...
616 ///
617 /// @note update_internal_coords is called recursively on all of *child's
618 /// children.
619 ///
620 void
622  AtomOP const child
623 )
624 {
625  Stub my_stub( this->get_stub() );
626  bool found( false );
627  for ( Atoms::iterator it = atoms_.begin(), it_end = atoms_.end(); it != it_end; ++it ) {
628  if ( *it == child ) {
629  (*it)->update_internal_coords( my_stub );
630  // phi torsion for the atom after child may have changed
631  ++it;
632  if ( it != it_end ) {
633  (*it)->update_internal_coords( my_stub, false /* not recursive */ );
634  }
635  found = true;
636  break;
637  } else {
638  // just advances the stub as if we had called update_internal_coords
639  (*it)->update_stub( my_stub );
640  }
641  }
642  if ( !found ) {
643  std::cerr << "update_child_torsions:: child not in atoms list" <<
644  atom_id_ << ' ' << child->id() << std::endl;
645  utility_exit();
646  }
647 }
648 
649 
650 /////////////////////////////////////////////////////////////////////////////
651 /// @details Keep track of any residue that moves so that the Conformation object
652 /// may be correctly updated.
653 void
655  Matrix const & A,
656  Vector const & b,
657  ResidueCoordinateChangeList & res_change_list
658 )
659 {
660  position_ = A * position_ + b;
661 
662  for ( Atoms::iterator it = atoms_.begin(), it_end = atoms_.end(); it != it_end; ++it ) {
663  (*it)->transform_Ax_plus_b_recursive( A, b, res_change_list );
664  }
665  res_change_list.mark_residue_moved( atom_id_ );
666 }
667 
668 
669 /////////////////////////////////////////////////////////////////////////////
670 void
672 {
673  if ( parent_ ) parent_->get_path_from_root( path );
674  path.push_back( this );
675 }
676 
677 
678 /////////////////////////////////////////////////////////////////////////////
679 bool
681 {
682  return ( atm() == this || ( parent_ && parent_->atom_is_on_path_from_root( atm ) ) );
683 }
684 
685 
686 /////////////////////////////////////////////////////////////////////////////
689 {
690  Atoms::const_iterator iter( atoms_.begin() );
691  while ( iter != atoms_.end() && (*iter)->is_jump() ) ++iter;
692  return iter;
693 }
694 
695 
696 /////////////////////////////////////////////////////////////////////////////
699 {
700  Atoms::iterator iter( atoms_.begin() );
701  while ( iter != atoms_.end() && (*iter)->is_jump() ) ++iter;
702  return iter;
703 }
704 
705 /// @details the "start atom index" is used to determine which subtrees have already
706 /// been examined. The atom tree guarantees that the dfs's occur in increasing order
707 /// by dof refold indices. If this atom has a dof refold index less than the start
708 /// atom index, then a dfs has previously been launched from this node and the recursion
709 /// must stop: subtrees must be visited at most once, or running time grows quadratically
710 /// in the number of atoms in the tree. The atom is responsible for handing the
711 /// start atom index down to its children in the recursion (if it continues recursing).
712 void
714  AtomDOFChangeSet & changeset,
715  ResidueCoordinateChangeList & res_change_list,
716  Size const start_atom_index
717 ) const
718 {
719  res_change_list.mark_residue_moved( atom_id_ );
720  if ( start_atom_index == dof_refold_index_ ) {
721  /// This is the root atom for a new subtree dfs.
722  for ( Atoms_ConstIterator iter = atoms_.begin(), iter_e = atoms_.end(); iter != iter_e; ++iter ) {
723  (*iter)->dfs( changeset, res_change_list, start_atom_index );
724  }
725 
726  } else if ( dof_refold_index_ != 0 ) {
727  changeset[ dof_refold_index_ ].reached_ = true;
728  if ( dof_refold_index_ > start_atom_index ) {
729  //recurse -- the subtree rooted from here won't be reached otherwise.
730  for ( Atoms_ConstIterator iter = atoms_.begin(), iter_e = atoms_.end(); iter != iter_e; ++iter ) {
731  (*iter)->dfs( changeset, res_change_list, start_atom_index );
732  }
733  }
734  } else { // dof_refold_index() == 0 -- recurse.
735  for ( Atoms_ConstIterator iter = atoms_begin(), iter_e = atoms_end(); iter != iter_e; ++iter ) {
736  (*iter)->dfs( changeset, res_change_list, start_atom_index );
737  }
738  }
739 }
740 
741 /// @details Records this atom as an atom with one-or-more changed dofs in the input
742 /// AtomDOFChangeSet if this is first DOF on this atom to change; if it is not the
743 /// first DOF on this atom that has changed, then this atom is already in set and
744 /// this atom is recorded at position dof_refold_index_.
745 void
747  AtomDOFChangeSet & changset
748 )
749 {
750  if ( dof_refold_index_ == 0 ) {
751  /// This is the first dof on this atom to change. Add it to the list of atoms that
752  /// have had DOFs change, and record the position of this atom in that list.
753 
754  changset.push_back( AtomWithDOFChange( atom_id_ ) );
755  dof_refold_index_ = changset.size();
756  } else {
757  assert( changset[ dof_refold_index_].atomid_ == atom_id_ );
758  }
759 }
760 
761 
762 void
764 {
765  std::cerr << "kinematics::Atom bad method call in Atom hierarchy!" << std::endl;
766  utility_exit();
767 }
768 
769 
770 }
771 } // namespace kinematics
772 } // namespace core