IMP logo
IMP Reference Guide  2.17.0
The Integrative Modeling Platform
Decorator.h
Go to the documentation of this file.
1 /**
2  * \file IMP/Decorator.h \brief The base class for decorators.
3  *
4  * Copyright 2007-2022 IMP Inventors. All rights reserved.
5  *
6  */
7 
8 #ifndef IMPKERNEL_DECORATOR_H
9 #define IMPKERNEL_DECORATOR_H
10 
11 #include <IMP/kernel_config.h>
12 #include "base_types.h"
13 #include <IMP/Object.h>
14 #include <IMP/WeakPointer.h>
15 #include "Model.h"
16 #include "Particle.h"
17 #include "utility.h"
18 #include "Constraint.h"
19 #include "internal/utility.h"
20 #include <IMP/utility_macros.h>
21 #include <IMP/Vector.h>
22 #include <IMP/Value.h>
23 
24 IMPKERNEL_BEGIN_NAMESPACE
25 class ParticleAdaptor;
26 
27 //! Interface to specialized Particle types (e.g. atoms)
28 /**
29 Representation of the structure in \imp is via a collection of
30 Particle objects. However, since particles are general purpose, they
31 provide a basic set of tools for managing the data (e.g.
32 IMP::Model::add_attribute(), IMP::Model::get_value()
33 etc). Decorators wrap (or \quote{decorate}) particles to provide a much
34 richer interface. For example, most particles have Cartesian
35 coordinates. The class IMP::core::XYZ decorates such a particle to
36 provide functions to get and set the Cartesian coordinates as well as
37 compute distances between particles.
38 \code
39 d0= IMP.core.XYZ(p0)
40 d1= IMP.core.XYZ(p1)
41 print IMP.core.distance(d0,d1)
42 print d0.get_coordinates()
43 \endcode
44 
45 \par Decorator basics
46 
47 \note The `get_is_setup()` and `setup_particle()` functions mentioned below
48 can take any of either an IMP::Model* and IMP::ParticleIndex
49 pair, an IMP::Particle* or another decorator to identify the particle.
50 We use various of those below.
51 
52 Dealing with decorators and particles has two main parts
53 -# setting up the particle to be used with that decorator
54 -# decorating the particle.
55 
56 To set up a particle to be used with the IMP::core::XYZ decorator we do
57 \code
58 d0= IMP.core.XYZ.setup_particle(m, pi, IMP.algebra.Vector3D(0,2,3))
59 \endcode
60 The method call decorates the particle and also returns the decorator
61 which can now be used to manipulate the particle. For example we can
62 access the coordinates \c (0,2,3) by doing
63 \code
64 print(d0.get_coordinates())
65 \endcode
66 We now say the particle is an XYZ particle. If that particle is
67 encountered later when we do not have the existing decorator available,
68 we can decorate it again (since it is already set up) by doing
69 \code
70 d1= IMP.core.XYZ(m, pi)
71 \endcode
72 
73 If you do not know if \c pi has been set up for the XYZ decorator, you can
74 ask with
75 \code
76 if IMP.core.XYZ.get_is_setup(m, pi):
77 \endcode
78 
79 More abstractly, decorators can be used to
80 - maintain invariants: e.g. an IMP::atom::Bond particle always connects
81  two other particles, both of which are IMP::atom::Bonded particles.
82 - add functionality: e.g. you can get the coordinates as an
83  IMP::algebra::Vector3D.
84 - provide uniform names for attributes: so you do not use \quote{x} in
85  some places and \quote{X} in other places.
86 
87 To see a list of all available decorators and to see what functions
88 all decorators have, look at the list of classes which inherit from
89 IMP::Decorator, below.
90 
91 See the IMP::example::ExampleDecorator %example for how to implement a
92 simple decorator.
93 
94 \note Decorator objects are ordered based on the address of the wrapped
95 particle. Like pointers, they are logical values so can be in \c if
96 statements.
97 
98 \implementation{Decorator, IMP_DECORATOR, IMP::example::ExampleDecorator}
99 \n\n For efficiency reasons attribute keys should always be created
100 lazily (at the time of the first use), and not be created as static
101 variables. The reason for this is that initialized attribute keys result
102 in space being allocated in decorators, even before they are used.\n\n
103 Implementers should consult IMP::example::ExampleDecorator,
104 IMP_DECORATOR_METHODS(), IMP_DECORATOR_WITH_TRAITS_METHODS(),
105 IMP_DECORATOR_GET().
106 
107 A decorator can be cast to a IMP::Particle* in C++. In Python Decorator objects
108 can be used anywhere where Particle or ParticleIndex objects are expected
109 (use the get_particle() method to get the Particle itself).
110 
111 \note It is undefined behavior to use a decorator constructed on
112 a particle that is no longer part of a model. Since constructing
113 decorators is very cheap, you probably should not store decorators,
114 and then would not have this problem.
115 
116 See example::ExampleDecorator to see what a minimal decorator looks like.
117 */
118 class IMPKERNELEXPORT Decorator : public Value {
119  private:
120  WeakPointer<Model> model_;
121  ParticleIndex pi_;
122  bool is_valid_; // false if constructed with default constructor
123  int compare(Object* o) const {
124  if (o < get_particle())
125  return -1;
126  else if (o > get_particle())
127  return 1;
128  else
129  return 0;
130  }
131 
132  protected:
134  : model_(m), pi_(pi), is_valid_(true) {}
135  Decorator() : is_valid_(false) {}
136 
137 #ifndef IMP_DOXYGEN
138  public:
139 #endif
140  explicit Decorator(ParticleAdaptor p);
141 
142  public:
143 #ifdef _MSC_VER
144  typedef Particle* ParticleP;
145 #endif
146 #ifndef IMP_DOXYGEN
147  bool __eq__(Object* o) const { return operator==(o); }
148  bool __ne__(Object* o) const { return operator!=(o); }
149  bool __lt__(Object* o) const { return operator<(o); }
150  bool __gt__(Object* o) const { return operator>(o); }
151  bool __ge__(Object* o) const { return operator>=(o); }
152  bool __le__(Object* o) const { return operator<=(o); }
153 #ifndef SWIG
154  bool operator==(Decorator d) const { return (compare(d) == 0); }
155 
156  bool operator==(Object* o) const { return (compare(o) == 0); }
157  bool operator!=(Object* o) const { return (compare(o) != 0); }
158  bool operator<(Object* o) const { return (compare(o) < 0); }
159  bool operator>(Object* o) const { return (compare(o) > 0); }
160  bool operator>=(Object* o) const { return !(compare(o) < 0); }
161  bool operator<=(Object* o) const { return !(compare(o) > 0); }
162 
163  bool operator==(Particle* o) const { return (compare(o) == 0); }
164  bool operator!=(Particle* o) const { return (compare(o) != 0); }
165  bool operator<(Particle* o) const { return (compare(o) < 0); }
166  bool operator>(Particle* o) const { return (compare(o) > 0); }
167  bool operator>=(Particle* o) const { return !(compare(o) < 0); }
168  bool operator<=(Particle* o) const { return !(compare(o) > 0); }
169 #endif
170 #endif
171 
172  //! Returns the particle decorated by this decorator.
174  if (!model_)
175  return nullptr;
176  else {
177  IMP_USAGE_CHECK(model_->get_particle(pi_),
178  "Particle " << pi_ << " is no longer part of the model.");
179  return model_->get_particle(pi_);
180  }
181  }
182 
183 #if !defined(SWIG)
184  operator Particle*() const { return get_particle(); }
185  Particle* operator->() const { return get_particle(); }
186  operator ParticleIndex() const { return get_particle_index(); }
187 #endif
188 
189  //! Returns the particle index decorated by this decorator.
190  ParticleIndex get_particle_index() const { return pi_; }
191 
192  //! Returns the Model containing the particle.
193  Model* get_model() const { return model_; }
194 
195  //! Returns true if constructed with a non-default constructor.
196  /**
197  @note It is guaranteed that this is a very fast method.
198  However, this method might return false if the particle itself
199  was invalidated after construction - use check_particle()
200  in that case.
201  */
202  bool get_is_valid() const { return is_valid_; }
203 
204  IMP_HASHABLE_INLINE(Decorator, return boost::hash_value(get_particle()););
205 
206 #if !defined(IMP_DOXYGEN) && !defined(SWIG)
207  typedef boost::false_type DecoratorHasTraits;
208 #endif
209 };
210 
211 #ifndef IMP_DOXYGEN
212 //! Check that the particle satisfies invariants registered by decorators.
213 IMPKERNELEXPORT void check_particle(Model *m, ParticleIndex pi);
214 #endif
215 
216 IMPKERNEL_END_NAMESPACE
217 
218 #endif /* IMPKERNEL_DECORATOR_H */
ParticleIndex get_particle_index() const
Returns the particle index decorated by this decorator.
Definition: Decorator.h:190
Basic types used by IMP.
Smart pointer to Object-derived classes that does not refcount.
Definition: WeakPointer.h:76
#define IMP_HASHABLE_INLINE(name, hashret)
Definition: hash_macros.h:18
Model * get_model() const
Returns the Model containing the particle.
Definition: Decorator.h:193
Storage of a model, its restraints, constraints and particles.
Index< ParticleIndexTag > ParticleIndex
Definition: base_types.h:161
Class for storing model, its restraints, constraints, and particles.
Definition: Model.h:73
Base class for a simple primitive-like type.
Definition: Value.h:23
Common base class for heavy weight IMP objects.
Definition: Object.h:106
int compare(const VectorD< D > &a, const VectorD< D > &b)
lexicographic comparison of two vectors
Definition: VectorD.h:179
Various general useful macros for IMP.
A weak pointer to an Object or RefCountedObject.
A base class for constraints.
A class for storing lists of IMP items.
For backwards compatibility.
bool get_is_valid() const
Returns true if constructed with a non-default constructor.
Definition: Decorator.h:202
Particle * get_particle() const
Returns the particle decorated by this decorator.
Definition: Decorator.h:173
Interface to specialized Particle types (e.g. atoms)
Definition: Decorator.h:118
Classes to handle individual model particles. (Note that implementation of inline functions is in int...
A shared base class to help in debugging and things.
Base class for a simple primitive-like type.
Class to handle individual particles of a Model object.
Definition: Particle.h:41
#define IMP_USAGE_CHECK(expr, message)
A runtime test for incorrect usage of a class or method.
Definition: check_macros.h:168