IMP  2.1.0
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-2013 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_GET_AS_DECL(UCName, lcname, CAPSNAME) \
27  UCName get_as_##lcname() const;
28 
29 // figure out how to inline
30 #define IMP_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_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_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_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_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 significant. 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 hierarchy are from the same model
164  - all Atoms has a Residue for as 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 in of a particle appear in order of their
170  AtomType
171 
172  The get_is_valid() method checks some of these properties. Any
173  method taking a hierarchy as an argument should do
174  \code
175  IMP_USAGE_CHECK(h.get_is_valid(), "Invalid hierarchy as input");
176  \endcode
177  to make sure the hierarchy makes sense.
178 
179  A number of decorator types are associated with the Hierarchy
180  to store the information associated with that node in the
181  hierarchy. Examples include Residue, Atom, XYZ, Chain, XYZR,
182  Mass, Domain, Molecule etc.
183  We provide a get_as_x() function for each such decorator which
184  returns either X() (a null type) if the node is not a particle
185  of type x, or an X decorator wrapping the current particle if
186  it is.
187 
188  \see Atom
189  \see Residue
190  \see Chain
191  \see Molecule
192  \see Domain
193  \see Fragment
194  \see Mass
195  */
196 class IMPATOMEXPORT Hierarchy : public core::Hierarchy {
197  typedef core::Hierarchy H;
198 
199  public:
200 #ifndef IMP_DOXYGEN
201  typedef boost::false_type DecoratorHasTraits;
202 
203  //! cast a particle which has the needed attributes
205  if (get_is_setup(p))
206  return Hierarchy(p);
207  else
208  return Hierarchy();
209  }
210  /** Setup the particle as a hierarchy and add the passed particles
211  as children. */
214  H::setup_particle(p, get_traits());
215  Hierarchy ret(p);
216  for (unsigned int i = 0; i < children.size(); ++i) {
217  if (!get_is_setup(p->get_model(), children[i])) {
218  setup_particle(p->get_model(), children[i]);
219  }
220  ret.add_child(Hierarchy(p->get_model(), children[i]));
221  }
222  return ret;
223  }
224 
226  return setup_particle(p->get_model(), p->get_index());
227  }
228 
229  static bool particle_is_instance(kernel::Particle *p) {
230  return H::get_is_setup(p, get_traits());
231  }
232  static bool get_is_setup(kernel::Particle *p) {
233  return H::get_is_setup(p, get_traits());
234  }
236  return H::get_is_setup(m->get_particle(p), get_traits());
237  }
238 #endif
239 
241  : H(m, pi, get_traits()) {}
242 
244  : H(pi.get_model(), pi.get_particle_index(), get_traits()) {}
245 
246  //! null constructor
248 
249  //! The traits must match
250  explicit Hierarchy(IMP::core::Hierarchy h) : H(h) {
252  h != IMP::core::Hierarchy() || h.get_decorator_traits() == get_traits(),
253  "Cannot construct a IMP.atom.Hierarchy from a general "
254  " IMP.core.Hierarchy");
255  }
256 
257  /** Create a Hierarchy of level t by adding the needed
258  attributes. */
262  H::setup_particle(m, pi, get_traits());
263  Hierarchy ret(m, pi);
264  for (unsigned int i = 0; i < children.size(); ++i) {
265  if (!get_is_setup(m, children[i])) {
266  setup_particle(m, children[i]);
267  }
268  ret.add_child(Hierarchy(m, children[i]));
269  }
270  return ret;
271  }
272 
273  /** Check if the particle has the needed attributes for a
274  cast to succeed */
276  return H::get_is_setup(m->get_particle(p), get_traits());
277  }
278 
279  //! Return true if the hierarchy is valid.
280  /** Print information about the hierarchy if print_info is
281  true and things are invalid.
282  \note Returning true only means that no problems were
283  found, it can't check everything.*/
284  bool get_is_valid(bool print_info) const;
285  //! Add a child and check that the types are appropriate
286  /** A child must have a type that is listed before the parent in the
287  Type enum list.
288  */
290  IMP_USAGE_CHECK(o != *this, "Can't add something as its own child");
291  H::add_child(o);
292  }
293 
294 #ifndef IMP_DOXYGEN
295  void show(std::ostream &out, std::string delimiter) const;
296 #endif
297 
298  /** Get the ith child based on the order they were added. */
299  Hierarchy get_child(unsigned int i) const {
300  H hd = H::get_child(i);
301  return Hierarchy(hd);
302  }
303  //! Return the children in the order they were added
305  Hierarchies ret(get_number_of_children());
306  for (unsigned int i = 0; i < get_number_of_children(); ++i) {
307  ret[i] = get_child(i);
308  }
309  return ret;
310  }
311 
312  //! Get the children in a container of your choosing, eg kernel::ParticlesTemp
313  template <class C>
314  C get_children() const {
315  C ret(get_number_of_children());
316  for (unsigned int i = 0; i < get_number_of_children(); ++i) {
317  ret[i] = get_child(i);
318  }
319  return ret;
320  }
321 
322  /** Get the parent particle. */
324  H hd = H::get_parent();
325  if (hd == H()) {
326  return Hierarchy();
327  } else {
328  return Hierarchy(hd);
329  }
330  }
331 
332  /** \name Methods to get associated decorators
333 
334  We provide a number of helper methods to get associated
335  decorators for the current node in the hierarchy. As an
336  example, if the particle decorated by this decorator is
337  a Residue particle, then get_as_residue() return
338  Residue(get_particle()), if not it returns Residue().
339  @{
340  */
341  IMP_FOREACH_HIERARCHY_TYPE_FUNCTIONS(IMP_GET_AS_DECL);
342  /** @} */
343 
344  //! Get the molecular hierarchy HierararchyTraits.
345  static const IMP::core::HierarchyTraits &get_traits();
346 
347  // swig overwrites __repr__ if it is inherited
349 };
350 
351 IMP_DECORATORS_DEF(Hierarchy, Hierarchies);
352 
353 #ifdef IMP_DOXYGEN
354 /** The different types which can be passed to get_by_type()
355  */
356 enum GetByType {
357  ATOM_TYPE,
358  RESIDUE_TYPE,
359  CHAIN_TYPE,
360  MOLECULE_TYPE.DOMAIN_TYPE,
361  FRAGMENT_TYPE,
362  XYZ_TYPE,
363  XYZR_TYPE,
364  MASS_TYPE
365 };
366 #else
367 enum GetByType {
368  IMP_FOREACH_HIERARCHY_TYPE_LIST(IMP_CAPS_NAME)
369 };
370 #endif
371 
372 /**
373  Gather all the molecular particles of a certain level
374  in the molecular hierarchy.
375 */
376 IMPATOMEXPORT Hierarchies get_by_type(Hierarchy mhd, GetByType t);
377 
378 //! Get the residue with the specified index
379 /** Find the leaf containing the residue with the appropriate index.
380  This is the PDB index, not the offset in the chain (if they are different).
381 
382  The function returns a Hierarchy, rather than a Residue since the
383  residue may not be explicitly represented and may just be part of some
384  fragment.
385 
386  \throw ValueException if mhd's type is not one of CHAIN, PROTEIN, NUCLEOTIDE
387  \return Hierarchy() if that residue is not found.
388 
389  See Hierarchy
390  */
391 IMPATOMEXPORT Hierarchy get_residue(Hierarchy mhd, unsigned int index);
392 
393 //! Create a fragment containing the specified nodes
394 /** A particle representing the fragment is created and initialized.
395 
396  The Fragment is inserted as a child of the parent (and the particles are
397  removed). The particles become children of the fragment.
398 
399  \throw ValueException If all the particles do not have the same parent.
400  See Hierarchy
401  */
402 IMPATOMEXPORT Hierarchy create_fragment(const Hierarchies &ps);
403 
404 //! Get the bonds internal to this tree
405 /** See Hierarchy
406  \see Bond
407  See Bond
408  */
409 IMPATOMEXPORT Bonds get_internal_bonds(Hierarchy mhd);
410 
411 //! Return the root of the hierarchy
412 /** See Hierarchy */
414  while (h.get_parent()) {
415  h = h.get_parent();
416  }
417  return h;
418 }
419 
420 /** See Hierarchy */
423 }
424 
425 /** See Hierarchy */
428  for (unsigned int i = 0; i < h.size(); ++i) {
429  core::GenericHierarchies cur = IMP::core::get_leaves(h[i]);
430  ret.insert(ret.end(), cur.begin(), cur.end());
431  }
432  return get_as<Hierarchies>(ret);
433 }
434 
435 //! Print out a molecular hierarchy
436 /** See Hierarchy
437  */
438 inline void show(Hierarchy h, std::ostream &out = std::cout) {
439  IMP::core::show<Hierarchy>(h, out);
440 }
441 
442 //! Rigidify a molecule or collection of molecules.
443 /** The rigid body created has all the leaves as members and a
444  member rigid body for each internal node in the tree. The
445  particle created to be the rigid body is returned.
446 
447  A name can be passed as it is not easy to automatically pick
448  a decent name.
449  \see create_aligned_rigid_body()
450  See Hierarchy
451  See IMP::core::RigidBody
452 */
454  const Hierarchies &h, std::string name = std::string("created rigid body"));
455 
456 /** \see create_rigid_body(const Hierarchies&)
457  */
458 IMPATOMEXPORT IMP::core::RigidBody create_rigid_body(Hierarchy h);
459 
460 //! Rigidify a molecule or collection of molecules.
461 /** This method is identical to create_rigid_body() except that
462  the chosen reference frame is aligned with that of reference
463  (which must have exactly the same set of particles). This allows
464  one to make sure the rigid body is equivalent when you have several
465  copies of the same molecule.
466 
467  See Hierarchy
468  See IMP::core::RigidBody
469 */
471  Hierarchy h, Hierarchy reference);
472 
473 #ifndef IMP_DOXYGEN
474 IMPATOMEXPORT IMP::core::RigidBody setup_as_rigid_body(Hierarchy h);
475 #endif
476 
477 //! Return true if the piece of hierarchy should be classified as a heterogen
478 /** For the purposes of classification, a heterogen is anything that
479  - is a heterogen atom (one whose name starts with HET:)
480  - is or is part of a Residue that is not a normal protein, rna or
481  dna residue
482  - or is not part of a Chain
483  For the moment, this can only be called on residues or atoms.
484 */
485 IMPATOMEXPORT bool get_is_heterogen(Hierarchy h);
486 
487 //! Clone the Hierarchy
488 /** This method copies the Bond, Bonded, Atom,
489  Residue, and Domain data and the particle name to the
490  new copies in addition to the Hierarchy relationships.
491 
492  See Hierarchy
493 */
494 IMPATOMEXPORT Hierarchy create_clone(Hierarchy d);
495 
496 //! Clone the node in the Hierarchy
497 /** This method copies the Atom,
498  Residue, Chain and Domain data and the particle name.
499 
500  See Hierarchy
501 */
502 IMPATOMEXPORT Hierarchy create_clone_one(Hierarchy d);
503 
504 //! Delete the Hierarchy
505 /** All bonds connecting to these atoms are destroyed as are
506  hierarchy links in the Hierarchy and the particles are
507  removed from the kernel::Model. If this particle has a parent, it is
508  removed from the parent.
509  See Hierarchy
510 */
511 IMPATOMEXPORT void destroy(Hierarchy d);
512 
513 //! Get a bounding box for the Hierarchy
514 /** This bounding box is that of the highest (in the CS sense of a tree
515  growing down from the root) cut
516  through the tree where each node in the cut has x,y,z, and r.
517  That is, if the root has x,y,z,r then it is the bounding box
518  of that sphere. If only the leaves have radii, it is the bounding
519  box of the leaves. If no such cut exists, the behavior is undefined.
520  See Hierarchy
521  See IMP::algebra::BoundingBoxD
522  */
523 IMPATOMEXPORT algebra::BoundingBoxD<3> get_bounding_box(const Hierarchy &h);
524 
525 /** See get_bounding_box() for more details.
526  See Hierarchy
527  */
528 IMPATOMEXPORT algebra::Sphere3D get_bounding_sphere(const Hierarchy &h);
529 
530 IMPATOM_END_NAMESPACE
531 
532 #endif /* IMPATOM_HIERARCHY_H */
Hierarchies get_leaves(Hierarchy h)
Decorator for helping deal with a hierarchy.
Various important functionality for implementing decorators.
static bool particle_is_instance(::IMP::kernel::Particle *p, const HierarchyTraits &tr=get_default_traits())
Hierarchy get_parent() const
algebra::Sphere3D get_bounding_sphere(const Hierarchy &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.
static bool get_is_setup(kernel::Model *m, kernel::ParticleIndex p)
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.
Residue get_residue(Atom d, bool nothrow=false)
Return the Residue containing this atom.
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
IMP::core::RigidBody create_rigid_body(const Hierarchies &h, std::string name=std::string("created rigid body"))
Rigidify a molecule or collection of molecules.
Decorator for a sphere-like particle.
Hierarchy(IMP::core::Hierarchy h)
The traits must match.
Class for storing model, its restraints, constraints, and particles.
BoundingBoxD< D > get_bounding_box(const BoundingBoxD< D > &g)
Definition: BoundingBoxD.h:160