00001 /** 00002 * \file atom/Hierarchy.h 00003 * \brief Decorator for helping deal with a hierarchy of molecules. 00004 * 00005 * Copyright 2007-2011 IMP Inventors. All rights reserved. 00006 * 00007 */ 00008 00009 #ifndef IMPATOM_HIERARCHY_H 00010 #define IMPATOM_HIERARCHY_H 00011 00012 #include "atom_config.h" 00013 #include <IMP/core/utility.h> 00014 #include <IMP/core/Hierarchy.h> 00015 #include "bond_decorators.h" 00016 #include "atom_macros.h" 00017 #include <IMP/core/XYZR.h> 00018 #include <IMP/core/rigid_bodies.h> 00019 00020 #include <IMP/Particle.h> 00021 #include <IMP/Model.h> 00022 00023 #include <vector> 00024 #include <deque> 00025 00026 00027 #define IMP_GET_AS_DECL(UCName, lcname, CAPSNAME) \ 00028 UCName get_as_##lcname() const; 00029 00030 // figure out how to inline 00031 #define IMP_GET_AS_DEF(UCName, lcname, CAPSNAME) \ 00032 UCName Hierarchy::get_as_##lcname() const { \ 00033 if (UCName::particle_is_instance(get_particle())) { \ 00034 return UCName(get_particle()); \ 00035 } else { \ 00036 return UCName(); \ 00037 } \ 00038 } 00039 00040 // DOMAIN is defined to be 1 by a fedora math header 00041 #define IMP_FOREACH_HIERARCHY_TYPE_LIST(macro) \ 00042 macro(Atom, atom, ATOM_TYPE), \ 00043 macro(Residue, residue, RESIDUE_TYPE), \ 00044 macro(Chain, chain, CHAIN_TYPE), \ 00045 macro(Molecule, molecule, MOLECULE_TYPE), \ 00046 macro(Domain, domain, DOMAIN_TYPE), \ 00047 macro(Fragment, fragment, FRAGMENT_TYPE), \ 00048 macro(core::XYZ, xyz, XYZ_TYPE), \ 00049 macro(core::XYZR, xyzr, XYZR_TYPE), \ 00050 macro(Mass, mass, MASS_TYPE) 00051 00052 // DOMAIN is defined to be 1 by a fedora math header 00053 #define IMP_FOREACH_HIERARCHY_TYPE_STATEMENTS(macro) \ 00054 macro(Atom, atom, ATOM_TYPE); \ 00055 macro(Residue, residue, RESIDUE_TYPE); \ 00056 macro(Chain, chain, CHAIN_TYPE); \ 00057 macro(Molecule, molecule, MOLECULE_TYPE); \ 00058 macro(Domain, domain, DOMAIN_TYPE); \ 00059 macro(Fragment, fragment, FRAGMENT_TYPE); \ 00060 macro(core::XYZ, xyz, XYZ_TYPE); \ 00061 macro(core::XYZR, xyzr, XYZR_TYPE); \ 00062 macro(Mass, mass, MASS_TYPE) 00063 00064 // DOMAIN is defined to be 1 by a fedora math header 00065 #define IMP_FOREACH_HIERARCHY_TYPE_FUNCTIONS(macro) \ 00066 macro(Atom, atom, ATOM_TYPE) \ 00067 macro(Residue, residue, RESIDUE_TYPE) \ 00068 macro(Chain, chain, CHAIN_TYPE) \ 00069 macro(Molecule, molecule, MOLECULE_TYPE) \ 00070 macro(Domain, domain, DOMAIN_TYPE) \ 00071 macro(Fragment, fragment, FRAGMENT_TYPE) \ 00072 macro(core::XYZ, xyz, XYZ_TYPE) \ 00073 macro(core::XYZR, xyzr, XYZR_TYPE) \ 00074 macro(Mass, mass, MASS_TYPE) \ 00075 IMP_REQUIRE_SEMICOLON_NAMESPACE 00076 00077 00078 #define IMP_CAPS_NAME(UCName, lcname, CAPSNAME) \ 00079 CAPSNAME 00080 00081 00082 IMPATOM_BEGIN_NAMESPACE 00083 class Atom; 00084 class Residue; 00085 class Domain; 00086 class Fragment; 00087 class Chain; 00088 class Molecule; 00089 class Mass; 00090 00091 class Hierarchy; 00092 00093 00094 #ifdef IMP_DOXYGEN 00095 00096 #else 00097 typedef IMP::Decorators< Hierarchy, 00098 IMP::core::GenericHierarchies> Hierarchies; 00099 typedef IMP::Decorators< Hierarchy, 00100 IMP::core::GenericHierarchiesTemp> HierarchiesTemp; 00101 #endif 00102 00103 //! The standard decorator for manipulating molecular structures. 00104 /** \imp represents molecular structures using the Hierachy decorator. 00105 Molecules and collections of molecules each are stored as a 00106 hierarchy (or tree) where the resolution of the representation increases 00107 as you move further from the root. That is, if a parent has 00108 some particular property (eg, marks out a volume by having 00109 a x,y,z coordinates and a radius), then the children should have 00110 a higher resolution form of that information (eg, mark out a more 00111 detailed excluded volume by defining a set of balls which having 00112 approximately the same total volume). 00113 00114 \section tree_basics Tree Basics 00115 In a tree you have a set of nodes, represented by Hierarchy particles. 00116 Each node can have a node can have at most one parent. The node with no 00117 parent is known as the root of the tree. 00118 00119 Here is a simple example with a protein with three residues. Two of the 00120 residues have atoms, where as the third is coarse grained. 00121 \dotgraph{\dot 00122 digraph example { 00123 node [shape=record\, fontname= Helvetica\, fontsize=10] 00124 a [label="Protein A (the root)"]; 00125 b [label="Residue 0"\, URL="Residue"]; 00126 c [label="Residue 1"]; 00127 cp [label="Residue 2"]; 00128 d0 [label="CA"]; 00129 e0 [label="CA"]; 00130 d1 [label="C"]; 00131 e1 [label="C"]; 00132 d2 [label="N"]; 00133 e2 [label="N"]; 00134 a -> b [arrowhead="open"]; 00135 a -> c [arrowhead="open"] 00136 a -> cp [arrowhead="open"]; 00137 b -> d0 [arrowhead="open"]; 00138 c -> e0 [arrowhead="open"]; 00139 b -> d1 [arrowhead="open"]; 00140 c -> e1 [arrowhead="open"]; 00141 b -> d2 [arrowhead="open"]; 00142 c -> e2 [arrowhead="open"]; 00143 } 00144 \enddot 00145 } 00146 00147 00148 The nodes in the hierarchy can correspond to arbitrary bits of a 00149 molecule and do not need to have any biological significant. For 00150 example we could introduce a fragment containing residues 0 and 1: 00151 \dotgraph{\dot 00152 digraph example { 00153 node [shape=record\, fontname= Helvetica\, fontsize=10] 00154 a [label="Protein A (the root)"\, URL="\ref B"]; 00155 aa [label="Fragment 0"]; 00156 b [label="Residue 0"]; 00157 c [label="Residue 1"]; 00158 cp [label="Residue 2"]; 00159 d0 [label="CA"]; 00160 e0 [label="CA"]; 00161 d1 [label="C"]; 00162 e1 [label="C"]; 00163 d2 [label="N"]; 00164 e2 [label="N"]; 00165 a -> aa [arrowhead="open"]; 00166 aa -> b [arrowhead="open"]; 00167 aa -> c [arrowhead="open"] 00168 a -> cp [arrowhead="open"]; 00169 b -> d0 [arrowhead="open"]; 00170 c -> e0 [arrowhead="open"]; 00171 b -> d1 [arrowhead="open"]; 00172 c -> e1 [arrowhead="open"]; 00173 b -> d2 [arrowhead="open"]; 00174 c -> e2 [arrowhead="open"]; 00175 } 00176 \enddot} 00177 00178 00179 A hierarchy can have any tree structure as long as: 00180 - the type of the parent makes sense for the child: eg a Residue 00181 cannot be the parent of a Chain. 00182 - the leaves always have coordinates, radius and mass 00183 - all particles in hierarchy are from the same model 00184 - all Atoms has a Residue for as parent 00185 - any Atom with a non-heterogen atom type is part of a protein, 00186 DNA or RNA molecule. 00187 - all Residue children of a particle appear in order based 00188 on their index 00189 - all Atom children in of a particle appear in order of their 00190 AtomType 00191 00192 The get_is_valid() method checks some of these properties. Any 00193 method taking a hierarchy as an argument should do 00194 \code 00195 IMP_USAGE_CHECK(h.get_is_valid(), "Invalid hierarchy as input"); 00196 \endcode 00197 to make sure the hierarchy makes sense. 00198 00199 A number of decorator types are associated with the Hierarchy 00200 to store the information associated with that node in the 00201 hierarchy. Examples include Residue, Atom, XYZ, Chain, XYZR, 00202 Mass, Domain, Molecule etc. 00203 We provide a get_as_x() function for each such decorator which 00204 returns either X() (a null type) if the node is not a particle 00205 of type x, or an X decorator wrapping the current particle if 00206 it is. 00207 00208 \ingroup hierarchy 00209 \ingroup decorators 00210 \see Atom 00211 \see Residue 00212 \see Chain 00213 \see Molecule 00214 \see Domain 00215 \see Fragment 00216 \see Mass 00217 */ 00218 class IMPATOMEXPORT Hierarchy: public core::Hierarchy 00219 { 00220 typedef core::Hierarchy H; 00221 public: 00222 IMP_NO_DOXYGEN(typedef boost::false_type DecoratorHasTraits); 00223 explicit Hierarchy(Particle *p): H(p, get_traits()) { 00224 } 00225 00226 //! null constructor 00227 Hierarchy() {} 00228 00229 //! cast a particle which has the needed attributes 00230 static Hierarchy decorate_particle(Particle *p) { 00231 H::decorate_particle(p, get_traits()); 00232 return Hierarchy(p); 00233 } 00234 00235 //! The traits must match 00236 Hierarchy(IMP::core::Hierarchy h): H(h) { 00237 IMP_USAGE_CHECK(h.get_traits() == get_traits(), 00238 "Cannot construct a IMP.atom.Hierarchy from a general " 00239 " IMP.core.Hierarchy"); 00240 } 00241 00242 /** Create a Hierarchy of level t by adding the needed 00243 attributes. */ 00244 static Hierarchy setup_particle(Particle *p) { 00245 H::setup_particle(p, get_traits()); 00246 return Hierarchy(p); 00247 } 00248 00249 /** Check if the particle has the needed attributes for a 00250 cast to succeed */ 00251 static bool particle_is_instance(Particle *p){ 00252 return H::particle_is_instance(p, get_traits()); 00253 } 00254 00255 //! Return true if the hierarchy is valid. 00256 /** Print information about the hierarchy if print_info is 00257 true and things are invalid. 00258 \note Returning true only means that no problems were 00259 found, it can't check everything.*/ 00260 bool get_is_valid(bool print_info) const; 00261 //! Add a child and check that the types are appropriate 00262 /** A child must have a type that is listed before the parent in the 00263 Type enum list. 00264 */ 00265 unsigned int add_child(Hierarchy o) { 00266 IMP_USAGE_CHECK(o != *this, "Can't add something as its own child: " 00267 << o); 00268 return H::add_child(o); 00269 } 00270 00271 //! Add a child and check that the types are appropriate 00272 /** A child must have a type that is listed before the parent in the 00273 Type enum list. 00274 */ 00275 void add_child_at(Hierarchy o, unsigned int i) { 00276 IMP_USAGE_CHECK(o != *this, "Can't add something as its own child: " 00277 << o); 00278 H::add_child_at(o, i); 00279 } 00280 00281 /** Get the ith child */ 00282 Hierarchy get_child(unsigned int i) const { 00283 H hd= H::get_child(i); 00284 return Hierarchy(hd); 00285 } 00286 HierarchiesTemp get_children() const { 00287 HierarchiesTemp ret(get_number_of_children()); 00288 for (unsigned int i=0; i< get_number_of_children(); ++i) { 00289 ret[i]= get_child(i); 00290 } 00291 return ret; 00292 } 00293 00294 00295 /** Get the parent particle. */ 00296 Hierarchy get_parent() const { 00297 H hd= H::get_parent(); 00298 if (hd == H()) { 00299 return Hierarchy(); 00300 } else { 00301 return Hierarchy(hd); 00302 } 00303 } 00304 00305 /** \name Methods to get associated decorators 00306 00307 We provide a number of helper methods to get associated 00308 decorators for the current node in the hierarchy. As an 00309 example, if the particle decorated by this decorator is 00310 a Residue particle, then get_as_residue() return 00311 Residue(get_particle()), if not it returns Residue(). 00312 @{ 00313 */ 00314 IMP_FOREACH_HIERARCHY_TYPE_FUNCTIONS(IMP_GET_AS_DECL); 00315 /** @} */ 00316 00317 //! Get the molecular hierarchy HierararchyTraits. 00318 static const IMP::core::HierarchyTraits& get_traits(); 00319 00320 // swig overwrites __repr__ if it is inherited 00321 IMP_SHOWABLE(Hierarchy); 00322 }; 00323 00324 IMP_OUTPUT_OPERATOR(Hierarchy); 00325 00326 00327 00328 #ifdef IMP_DOXYGEN 00329 /** The different types which can be passed to get_by_type() 00330 */ 00331 enum GetByType {ATOM_TYPE, RESIDUE_TYPE, CHAIN_TYPE, MOLECULE_TYPE. 00332 DOMAIN_TYPE, FRAGMENT_TYPE, 00333 XYZ_TYPE,XYZR_TYPE,MASS_TYPE}; 00334 #else 00335 enum GetByType { 00336 IMP_FOREACH_HIERARCHY_TYPE_LIST(IMP_CAPS_NAME) 00337 }; 00338 #endif 00339 00340 /** 00341 Gather all the molecular particles of a certain level 00342 in the molecular hierarchy 00343 \ingroup hierarchy 00344 \relatesalso Hierarchy 00345 */ 00346 IMPATOMEXPORT HierarchiesTemp 00347 get_by_type(Hierarchy mhd, GetByType t); 00348 00349 00350 //! Get the residue with the specified index 00351 /** Find the leaf containing the residue with the appropriate index. 00352 This is the PDB index, not the offset in the chain (if they are different). 00353 00354 The function returns a Hierarchy, rather than a Residue since the 00355 residue may not be explicitly represented and may just be part of some 00356 fragment. 00357 00358 \throw ValueException if mhd's type is not one of CHAIN, PROTEIN, NUCLEOTIDE 00359 \return Hierarchy() if that residue is not found. 00360 00361 \ingroup hierarchy 00362 \relatesalso Hierarchy 00363 */ 00364 IMPATOMEXPORT Hierarchy 00365 get_residue(Hierarchy mhd, unsigned int index); 00366 00367 00368 //! Create a fragment containing the specified nodes 00369 /** A particle representing the fragment is created and initialized. 00370 00371 The Fragment is inserted as a child of the parent (and the particles are 00372 removed). The particles become children of the fragment. 00373 00374 \throw ValueException If all the particles do not have the same parent. 00375 \ingroup hierarchy 00376 \relatesalso Hierarchy 00377 */ 00378 IMPATOMEXPORT Hierarchy 00379 create_fragment(const HierarchiesTemp &ps); 00380 00381 //! Get the bonds internal to this tree 00382 /** \relatesalso Hierarchy 00383 \see Bond 00384 \relatesalso Bond 00385 */ 00386 IMPATOMEXPORT Bonds 00387 get_internal_bonds(Hierarchy mhd); 00388 00389 00390 //! Return the root of the hierarchy 00391 /** \relatesalso Hierarchy */ 00392 inline Hierarchy get_root(Hierarchy h) { 00393 while (h.get_parent()) { 00394 h= h.get_parent(); 00395 } 00396 return h; 00397 } 00398 00399 /** \relatesalso Hierarchy */ 00400 inline HierarchiesTemp get_leaves(Hierarchy h) { 00401 return HierarchiesTemp(IMP::core::get_leaves(h)); 00402 } 00403 00404 //! Print out a molecular hierarchy 00405 /** \relatesalso Hierarchy 00406 */ 00407 inline void show(Hierarchy h, std::ostream &out=std::cout) { 00408 IMP::core::show<Hierarchy>(h, out); 00409 } 00410 00411 //! Rigidify a molecule or collection of molecules. 00412 /** The rigid body created has all the leaves as members and a 00413 member rigid body for each internal node in the tree. 00414 00415 A name can be passed as it is not easy to automatically pick 00416 a decent name. 00417 \see create_aligned_rigid_body() 00418 \relatesalso Hierarchy 00419 \relatesalso IMP::core::RigidBody 00420 */ 00421 IMPATOMEXPORT IMP::core::RigidBody create_rigid_body(const Hierarchies& h, 00422 std::string name=std::string("created rigid body")); 00423 00424 /** \see create_rigid_body(const HierarchiesTemp&) 00425 */ 00426 IMPATOMEXPORT IMP::core::RigidBody create_rigid_body(Hierarchy h); 00427 00428 //! Rigidify a molecule or collection of molecules. 00429 /** This method is identical to create_rigid_body() except that 00430 the chosen reference frame is aligned with that of reference 00431 (which must have exactly the same set of particles). This allows 00432 one to make sure the rigid body is equivalent when you have several 00433 copies of the same molecule. 00434 00435 \relatesalso Hierarchy 00436 \relatesalso IMP::core::RigidBody 00437 */ 00438 IMPATOMEXPORT IMP::core::RigidBody create_compatible_rigid_body(Hierarchy h, 00439 Hierarchy reference); 00440 00441 00442 #ifndef IMP_DOXYGEN 00443 IMPATOMEXPORT IMP::core::RigidBody setup_as_rigid_body(Hierarchy h); 00444 #endif 00445 00446 //! Return true if the piece of hierarchy should be classified as a heterogen 00447 /** For the purposes of classification, a heterogen is anything that 00448 - is a heterogen atom (one whose name starts with HET:) 00449 - is or is part of a Residue that is not a normal protein, rna or 00450 dna residue 00451 - or is not part of a Chain 00452 For the moment, this can only be called on residues or atoms. 00453 */ 00454 IMPATOMEXPORT bool get_is_heterogen(Hierarchy h); 00455 00456 //! Clone the Hierarchy 00457 /** This method copies the Bond, Bonded, Atom, 00458 Residue, and Domain data and the particle name to the 00459 new copies in addition to the Hierarchy relationships. 00460 00461 \relatesalso Hierarchy 00462 */ 00463 IMPATOMEXPORT 00464 Hierarchy create_clone(Hierarchy d); 00465 00466 //! Clone the node in the Hierarchy 00467 /** This method copies the Atom, 00468 Residue, Chain and Domain data and the particle name. 00469 00470 \relatesalso Hierarchy 00471 */ 00472 IMPATOMEXPORT 00473 Hierarchy create_clone_one(Hierarchy d); 00474 00475 00476 //! Delete the Hierarchy 00477 /** All bonds connecting to these atoms are destroyed as are 00478 hierarchy links in the Hierarchy and the particles are 00479 removed from the Model. 00480 \relatesalso Hierarchy 00481 */ 00482 IMPATOMEXPORT 00483 void destroy(Hierarchy d); 00484 00485 00486 00487 //! Get a bounding box for the Hierarchy 00488 /** This bounding box is that of the highest (in the CS sense of a tree 00489 growing down from the root) cut 00490 through the tree where each node in the cut has x,y,z, and r. 00491 That is, if the root has x,y,z,r then it is the bounding box 00492 of that sphere. If only the leaves have radii, it is the bounding 00493 box of the leaves. If no such cut exists, the behavior is undefined. 00494 \relatesalso Hierarchy 00495 \relatesalso IMP::algebra::BoundingBoxD 00496 */ 00497 IMPATOMEXPORT 00498 algebra::BoundingBoxD<3> get_bounding_box(const Hierarchy &h); 00499 00500 00501 /** See get_bounding_box() for more details. 00502 \relatesalso Hierarchy 00503 */ 00504 IMPATOMEXPORT 00505 algebra::SphereD<3> get_bounding_sphere(const Hierarchy &h); 00506 00507 00508 IMPATOM_END_NAMESPACE 00509 00510 00511 #endif /* IMPATOM_HIERARCHY_H */