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