IMP logo
atom/Hierarchy.h
Go to the documentation of this file.
1 /**
2  * \file atom/Hierarchy.h
3  * \brief Decorator for helping deal with a hierarchy of molecules.
4  *
5  * Copyright 2007-2012 IMP Inventors. All rights reserved.
6  *
7  */
8 
9 #ifndef IMPATOM_HIERARCHY_H
10 #define IMPATOM_HIERARCHY_H
11 
12 #include "atom_config.h"
13 #include <IMP/core/utility.h>
14 #include <IMP/core/Hierarchy.h>
15 #include "bond_decorators.h"
16 #include "atom_macros.h"
17 #include <IMP/core/XYZR.h>
18 #include <IMP/core/rigid_bodies.h>
19 
20 #include <IMP/Particle.h>
21 #include <IMP/Model.h>
22 
23 #include <vector>
24 #include <deque>
25 
26 
27 #define IMP_GET_AS_DECL(UCName, lcname, CAPSNAME) \
28  UCName get_as_##lcname() const;
29 
30 // figure out how to inline
31 #define IMP_GET_AS_DEF(UCName, lcname, CAPSNAME) \
32  UCName Hierarchy::get_as_##lcname() const { \
33  if (UCName::particle_is_instance(get_particle())) { \
34  return UCName(get_particle()); \
35  } else { \
36  return UCName(); \
37  } \
38  }
39 
40 // DOMAIN is defined to be 1 by a fedora math header
41 #define IMP_FOREACH_HIERARCHY_TYPE_LIST(macro) \
42  macro(Atom, atom, ATOM_TYPE), \
43  macro(Residue, residue, RESIDUE_TYPE), \
44  macro(Chain, chain, CHAIN_TYPE), \
45  macro(Molecule, molecule, MOLECULE_TYPE), \
46  macro(Domain, domain, DOMAIN_TYPE), \
47  macro(Fragment, fragment, FRAGMENT_TYPE), \
48  macro(core::XYZ, xyz, XYZ_TYPE), \
49  macro(core::XYZR, xyzr, XYZR_TYPE), \
50  macro(Mass, mass, MASS_TYPE)
51 
52 // DOMAIN is defined to be 1 by a fedora math header
53 #define IMP_FOREACH_HIERARCHY_TYPE_STATEMENTS(macro) \
54  macro(Atom, atom, ATOM_TYPE); \
55  macro(Residue, residue, RESIDUE_TYPE); \
56  macro(Chain, chain, CHAIN_TYPE); \
57  macro(Molecule, molecule, MOLECULE_TYPE); \
58  macro(Domain, domain, DOMAIN_TYPE); \
59  macro(Fragment, fragment, FRAGMENT_TYPE); \
60  macro(core::XYZ, xyz, XYZ_TYPE); \
61  macro(core::XYZR, xyzr, XYZR_TYPE); \
62  macro(Mass, mass, MASS_TYPE)
63 
64 // DOMAIN is defined to be 1 by a fedora math header
65 #define IMP_FOREACH_HIERARCHY_TYPE_FUNCTIONS(macro) \
66  macro(Atom, atom, ATOM_TYPE) \
67  macro(Residue, residue, RESIDUE_TYPE) \
68  macro(Chain, chain, CHAIN_TYPE) \
69  macro(Molecule, molecule, MOLECULE_TYPE) \
70  macro(Domain, domain, DOMAIN_TYPE) \
71  macro(Fragment, fragment, FRAGMENT_TYPE) \
72  macro(core::XYZ, xyz, XYZ_TYPE) \
73  macro(core::XYZR, xyzr, XYZR_TYPE) \
74  macro(Mass, mass, MASS_TYPE) \
75  IMP_REQUIRE_SEMICOLON_NAMESPACE
76 
77 
78 #define IMP_CAPS_NAME(UCName, lcname, CAPSNAME) \
79  CAPSNAME
80 
81 
82 IMPATOM_BEGIN_NAMESPACE
83 class Atom;
84 class Residue;
85 class Domain;
86 class Fragment;
87 class Chain;
88 class Molecule;
89 class Mass;
90 
91 IMP_DECORATORS_DECL(Hierarchy, Hierarchies);
92 
93 
94 //! The standard decorator for manipulating molecular structures.
95 /** \imp represents molecular structures using the Hierachy decorator.
96  Molecules and collections of molecules each are stored as a
97  hierarchy (or tree) where the resolution of the representation increases
98  as you move further from the root. That is, if a parent has
99  some particular property (eg, marks out a volume by having
100  a x,y,z coordinates and a radius), then the children should have
101  a higher resolution form of that information (eg, mark out a more
102  detailed excluded volume by defining a set of balls which having
103  approximately the same total volume).
104 
105  \section tree_basics Tree Basics
106  In a tree you have a set of nodes, represented by Hierarchy particles.
107  Each node can have a node can have at most one parent. The node with no
108  parent is known as the root of the tree.
109 
110  Here is a simple example with a protein with three residues. Two of the
111  residues have atoms, where as the third is coarse grained.
112  \dotgraph{\dot
113  digraph example {
114  node [shape=record\, fontname= Helvetica\, fontsize=10]
115  a [label="Protein A (the root)"];
116  b [label="Residue 0"\, URL="Residue"];
117  c [label="Residue 1"];
118  cp [label="Residue 2"];
119  d0 [label="CA"];
120  e0 [label="CA"];
121  d1 [label="C"];
122  e1 [label="C"];
123  d2 [label="N"];
124  e2 [label="N"];
125  a -> b [arrowhead="open"];
126  a -> c [arrowhead="open"]
127  a -> cp [arrowhead="open"];
128  b -> d0 [arrowhead="open"];
129  c -> e0 [arrowhead="open"];
130  b -> d1 [arrowhead="open"];
131  c -> e1 [arrowhead="open"];
132  b -> d2 [arrowhead="open"];
133  c -> e2 [arrowhead="open"];
134  }
135  \enddot
136  }
137 
138 
139  The nodes in the hierarchy can correspond to arbitrary bits of a
140  molecule and do not need to have any biological significant. For
141  example we could introduce a fragment containing residues 0 and 1:
142  \dotgraph{\dot
143  digraph example {
144  node [shape=record\, fontname= Helvetica\, fontsize=10]
145  a [label="Protein A (the root)"\, URL="\ref B"];
146  aa [label="Fragment 0"];
147  b [label="Residue 0"];
148  c [label="Residue 1"];
149  cp [label="Residue 2"];
150  d0 [label="CA"];
151  e0 [label="CA"];
152  d1 [label="C"];
153  e1 [label="C"];
154  d2 [label="N"];
155  e2 [label="N"];
156  a -> aa [arrowhead="open"];
157  aa -> b [arrowhead="open"];
158  aa -> c [arrowhead="open"]
159  a -> cp [arrowhead="open"];
160  b -> d0 [arrowhead="open"];
161  c -> e0 [arrowhead="open"];
162  b -> d1 [arrowhead="open"];
163  c -> e1 [arrowhead="open"];
164  b -> d2 [arrowhead="open"];
165  c -> e2 [arrowhead="open"];
166  }
167  \enddot}
168 
169 
170  A hierarchy can have any tree structure as long as:
171  - the type of the parent makes sense for the child: eg a Residue
172  cannot be the parent of a Chain.
173  - the leaves always have coordinates, radius and mass
174  - all particles in hierarchy are from the same model
175  - all Atoms has a Residue for as parent
176  - any Atom with a non-heterogen atom type is part of a protein,
177  DNA or RNA molecule.
178  - all Residue children of a particle appear in order based
179  on their index
180  - all Atom children in of a particle appear in order of their
181  AtomType
182 
183  The get_is_valid() method checks some of these properties. Any
184  method taking a hierarchy as an argument should do
185  \code
186  IMP_USAGE_CHECK(h.get_is_valid(), "Invalid hierarchy as input");
187  \endcode
188  to make sure the hierarchy makes sense.
189 
190  A number of decorator types are associated with the Hierarchy
191  to store the information associated with that node in the
192  hierarchy. Examples include Residue, Atom, XYZ, Chain, XYZR,
193  Mass, Domain, Molecule etc.
194  We provide a get_as_x() function for each such decorator which
195  returns either X() (a null type) if the node is not a particle
196  of type x, or an X decorator wrapping the current particle if
197  it is.
198 
199  \ingroup hierarchy
200  \ingroup decorators
201  \see Atom
202  \see Residue
203  \see Chain
204  \see Molecule
205  \see Domain
206  \see Fragment
207  \see Mass
208  */
209 class IMPATOMEXPORT Hierarchy: public core::Hierarchy
210 {
211  typedef core::Hierarchy H;
212 public:
213  IMP_NO_DOXYGEN(typedef boost::false_type DecoratorHasTraits);
214  explicit Hierarchy(Particle *p): H(p, get_traits()) {
215  }
216 
217  Hierarchy(Model *m, ParticleIndex pi): H(m, pi, get_traits()) {
218  }
219 
220  //! null constructor
221  Hierarchy() {}
223  //! cast a particle which has the needed attributes
224  static Hierarchy decorate_particle(Particle *p) {
225  H::decorate_particle(p, get_traits());
226  return Hierarchy(p);
227  }
228 
229  //! The traits must match
230  explicit Hierarchy(IMP::core::Hierarchy h): H(h) {
232  || h.get_traits() == get_traits(),
233  "Cannot construct a IMP.atom.Hierarchy from a general "
234  " IMP.core.Hierarchy");
235  }
236 
237  /** Create a Hierarchy of level t by adding the needed
238  attributes. */
240  const ParticlesTemp &children
241  = ParticlesTemp()) {
242  H::setup_particle(p, get_traits());
243  Hierarchy ret(p);
244  for (unsigned int i=0; i< children.size(); ++i) {
245  if (!particle_is_instance(children[i])) {
246  setup_particle(children[i]);
247  }
248  ret.add_child(Hierarchy(children[i]));
249  }
250  return ret;
251  }
252 
253  /** Check if the particle has the needed attributes for a
254  cast to succeed */
255  static bool particle_is_instance(Particle *p){
256  return H::particle_is_instance(p, get_traits());
257  }
258 
259  //! Return true if the hierarchy is valid.
260  /** Print information about the hierarchy if print_info is
261  true and things are invalid.
262  \note Returning true only means that no problems were
263  found, it can't check everything.*/
264  bool get_is_valid(bool print_info) const;
265  //! Add a child and check that the types are appropriate
266  /** A child must have a type that is listed before the parent in the
267  Type enum list.
268  */
269  void add_child(Hierarchy o) {
270  IMP_USAGE_CHECK(o != *this, "Can't add something as its own child");
271  H::add_child(o);
272  }
273 
274  /** Get the ith child based on the order they were added. */
275  Hierarchy get_child(unsigned int i) const {
276  H hd= H::get_child(i);
277  return Hierarchy(hd);
278  }
279  //! Return the children in the order they were added
280  Hierarchies get_children() const {
281  Hierarchies ret(get_number_of_children());
282  for (unsigned int i=0; i< get_number_of_children(); ++i) {
283  ret[i]= get_child(i);
284  }
285  return ret;
286  }
287 
288  //! Get the children in a container of your choosing, eg ParticlesTemp
289  template <class C>
290  C get_children() const {
291  C ret(get_number_of_children());
292  for (unsigned int i=0; i< get_number_of_children(); ++i) {
293  ret[i]= get_child(i);
294  }
295  return ret;
296  }
297 
298  /** Get the parent particle. */
299  Hierarchy get_parent() const {
300  H hd= H::get_parent();
301  if (hd == H()) {
302  return Hierarchy();
303  } else {
304  return Hierarchy(hd);
305  }
306  }
307 
308  /** \name Methods to get associated decorators
309 
310  We provide a number of helper methods to get associated
311  decorators for the current node in the hierarchy. As an
312  example, if the particle decorated by this decorator is
313  a Residue particle, then get_as_residue() return
314  Residue(get_particle()), if not it returns Residue().
315  @{
316  */
317  IMP_FOREACH_HIERARCHY_TYPE_FUNCTIONS(IMP_GET_AS_DECL);
318  /** @} */
319 
320  //! Get the molecular hierarchy HierararchyTraits.
321  static const IMP::core::HierarchyTraits& get_traits();
322 
323  // swig overwrites __repr__ if it is inherited
324  IMP_SHOWABLE(Hierarchy);
325 };
327 IMP_DECORATORS_DEF(Hierarchy, Hierarchies);
328 
329 
330 #ifdef IMP_DOXYGEN
331 /** The different types which can be passed to get_by_type()
332  */
333 enum GetByType {ATOM_TYPE, RESIDUE_TYPE, CHAIN_TYPE, MOLECULE_TYPE.
334  DOMAIN_TYPE, FRAGMENT_TYPE,
335  XYZ_TYPE,XYZR_TYPE,MASS_TYPE};
336 #else
337 enum GetByType {
338  IMP_FOREACH_HIERARCHY_TYPE_LIST(IMP_CAPS_NAME)
339 };
340 #endif
341 
342 /**
343  Gather all the molecular particles of a certain level
344  in the molecular hierarchy.
345  \ingroup hierarchy
346  \relatesalso Hierarchy
347 */
348 IMPATOMEXPORT Hierarchies
349 get_by_type(Hierarchy mhd, GetByType t);
350 
352 //! Get the residue with the specified index
353 /** Find the leaf containing the residue with the appropriate index.
354  This is the PDB index, not the offset in the chain (if they are different).
355 
356  The function returns a Hierarchy, rather than a Residue since the
357  residue may not be explicitly represented and may just be part of some
358  fragment.
359 
360  \throw ValueException if mhd's type is not one of CHAIN, PROTEIN, NUCLEOTIDE
361  \return Hierarchy() if that residue is not found.
362 
363  \ingroup hierarchy
364  \relatesalso Hierarchy
365  */
366 IMPATOMEXPORT Hierarchy
367 get_residue(Hierarchy mhd, unsigned int index);
368 
369 
370 //! Create a fragment containing the specified nodes
371 /** A particle representing the fragment is created and initialized.
372 
373  The Fragment is inserted as a child of the parent (and the particles are
374  removed). The particles become children of the fragment.
375 
376  \throw ValueException If all the particles do not have the same parent.
377  \ingroup hierarchy
378  \relatesalso Hierarchy
379  */
380 IMPATOMEXPORT Hierarchy
381 create_fragment(const Hierarchies &ps);
382 
383 //! Get the bonds internal to this tree
384 /** \relatesalso Hierarchy
385  \see Bond
386  \relatesalso Bond
387  */
388 IMPATOMEXPORT Bonds
390 
391 
392 //! Return the root of the hierarchy
393 /** \relatesalso Hierarchy */
394 inline Hierarchy get_root(Hierarchy h) {
395  while (h.get_parent()) {
396  h= h.get_parent();
397  }
398  return h;
399 }
400 
401 /** \relatesalso Hierarchy */
402 inline Hierarchies get_leaves(Hierarchy h) {
403  return Hierarchies(IMP::core::get_leaves(h));
404 }
405 
406 /** \relatesalso Hierarchy */
407 inline Hierarchies get_leaves(const Hierarchies& h) {
408  ParticlesTemp ret;
409  for (unsigned int i=0; i< h.size(); ++i) {
410  core::GenericHierarchies cur=IMP::core::get_leaves(h[i]);
411  ret.insert(ret.end(), cur.begin(), cur.end());
412  }
413  return get_as<Hierarchies>(ret);
414 }
415 
416 //! Print out a molecular hierarchy
417 /** \relatesalso Hierarchy
418  */
419 inline void show(Hierarchy h, std::ostream &out=std::cout) {
420  IMP::core::show<Hierarchy>(h, out);
421 }
422 
423 //! Rigidify a molecule or collection of molecules.
424 /** The rigid body created has all the leaves as members and a
425  member rigid body for each internal node in the tree. The
426  particle created to be the rigid body is returned.
427 
428  A name can be passed as it is not easy to automatically pick
429  a decent name.
430  \see create_aligned_rigid_body()
431  \relatesalso Hierarchy
432  \relatesalso IMP::core::RigidBody
433 */
434 IMPATOMEXPORT IMP::core::RigidBody create_rigid_body(const Hierarchies& h,
435  std::string name=std::string("created rigid body"));
436 
437 /** \see create_rigid_body(const Hierarchies&)
438  */
439 IMPATOMEXPORT IMP::core::RigidBody create_rigid_body(Hierarchy h);
440 
441 //! Rigidify a molecule or collection of molecules.
442 /** This method is identical to create_rigid_body() except that
443  the chosen reference frame is aligned with that of reference
444  (which must have exactly the same set of particles). This allows
445  one to make sure the rigid body is equivalent when you have several
446  copies of the same molecule.
447 
448  \relatesalso Hierarchy
449  \relatesalso IMP::core::RigidBody
450 */
451 IMPATOMEXPORT IMP::core::RigidBody create_compatible_rigid_body(Hierarchy h,
452  Hierarchy reference);
453 
454 
455 #ifndef IMP_DOXYGEN
456 IMPATOMEXPORT IMP::core::RigidBody setup_as_rigid_body(Hierarchy h);
457 #endif
458 
459 //! Return true if the piece of hierarchy should be classified as a heterogen
460 /** For the purposes of classification, a heterogen is anything that
461  - is a heterogen atom (one whose name starts with HET:)
462  - is or is part of a Residue that is not a normal protein, rna or
463  dna residue
464  - or is not part of a Chain
465  For the moment, this can only be called on residues or atoms.
466 */
467 IMPATOMEXPORT bool get_is_heterogen(Hierarchy h);
468 
469 //! Clone the Hierarchy
470 /** This method copies the Bond, Bonded, Atom,
471  Residue, and Domain data and the particle name to the
472  new copies in addition to the Hierarchy relationships.
473 
474  \relatesalso Hierarchy
475 */
476 IMPATOMEXPORT
477 Hierarchy create_clone(Hierarchy d);
478 
479 //! Clone the node in the Hierarchy
480 /** This method copies the Atom,
481  Residue, Chain and Domain data and the particle name.
482 
483  \relatesalso Hierarchy
484 */
485 IMPATOMEXPORT
486 Hierarchy create_clone_one(Hierarchy d);
487 
488 
489 //! Delete the Hierarchy
490 /** All bonds connecting to these atoms are destroyed as are
491  hierarchy links in the Hierarchy and the particles are
492  removed from the Model.
493  \relatesalso Hierarchy
494 */
495 IMPATOMEXPORT
496 void destroy(Hierarchy d);
497 
498 
499 
500 //! Get a bounding box for the Hierarchy
501 /** This bounding box is that of the highest (in the CS sense of a tree
502  growing down from the root) cut
503  through the tree where each node in the cut has x,y,z, and r.
504  That is, if the root has x,y,z,r then it is the bounding box
505  of that sphere. If only the leaves have radii, it is the bounding
506  box of the leaves. If no such cut exists, the behavior is undefined.
507  \relatesalso Hierarchy
508  \relatesalso IMP::algebra::BoundingBoxD
509  */
510 IMPATOMEXPORT
511 algebra::BoundingBoxD<3> get_bounding_box(const Hierarchy &h);
512 
513 
514 /** See get_bounding_box() for more details.
515  \relatesalso Hierarchy
516  */
517 IMPATOMEXPORT
518 algebra::Sphere3D get_bounding_sphere(const Hierarchy &h);
519 
520 
521 IMPATOM_END_NAMESPACE
522 
523 
524 #endif /* IMPATOM_HIERARCHY_H */

Generated on Tue May 22 2012 23:33:14 for IMP by doxygen 1.8.1