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