IMP  2.1.0
The Integrative Modeling Platform
kernel/Decorator.h
Go to the documentation of this file.
1 /**
2  * \file IMP/kernel/Decorator.h \brief The base class for decorators.
3  *
4  * Copyright 2007-2013 IMP Inventors. All rights reserved.
5  *
6  */
7 
8 #ifndef IMPKERNEL_DECORATOR_H
9 #define IMPKERNEL_DECORATOR_H
10 
11 #include <IMP/kernel/kernel_config.h>
12 #include "base_types.h"
13 #include <IMP/base/Object.h>
14 #include <IMP/base/WeakPointer.h>
15 #include "Model.h"
16 #include "utility.h"
17 #include "Constraint.h"
18 #include "internal/utility.h"
20 #include <IMP/base/Vector.h>
21 #include <IMP/base/Value.h>
22 
23 IMPKERNEL_BEGIN_NAMESPACE
24 class ParticleAdaptor;
25 
26 /**
27 Representation of the structure in \imp is via a collection of
28 Particle objects. However, since particles are general purpose, they
29 provide a basic set of tools for managing the data (e.g.
30 IMP::kernel::Model::add_attribute(), IMP::kernel::Model::get_value()
31 etc). Decorators wrap (or \quote{decorate}) particles to provide a much
32 richer interface. For example, most particles have Cartesian
33 coordinates. The class IMP::core::XYZ decorates such a particle to
34 provide functions to get and set the Cartesian coordinates as well as
35 compute distances between particles.
36 \code
37 d0= IMP.core.XYZ(p0)
38 d1= IMP.core.XYZ(p1)
39 print IMP.core.distance(d0,d1)
40 print d0.get_coordinates()
41 \endcode
42 
43 \par Decorator basics
44 
45 \note The `get_is_setup()` and `setup_particle()` functions mentioned below
46 can take any of either an IMP::kernel::Model* and IMP::kernel::ParticleIndex
47 pair, an IMP::kernel::Paricle* or another decorator to identify the particle.
48 We use various of those below.
49 
50 Dealing with decorators and particles has two main parts
51 -# setting up the particle to be used with that decorator
52 -# decorating the particle.
53 
54 To set up a particle to be used with the IMP::core::XYZ decorator we do
55 \code
56 d0= IMP.core.XYZ.setup_particle(m, pi, IMP.algebra.Vector3D(0,2,3))
57 \endcode
58 The method calls also decorates the particle and returns the decorator
59 which can now be used to manipulate the particle. For example we can
60 access the coordinates \c (0,2,3) by doing
61 \code
62 print d0.get_coordinates()
63 \endcode
64 We now say the particle is an XYZ particle. If that particle is
65 encountered later when we do not have the existing decorator available,
66 we can decorate it again (since it is already set up) by doing
67 \code
68 d1= IMP.core.XYZ(m, pi)
69 \endcode
70 
71 If you do not know if \c p has been set up for the XYZ decorator, you can
72 ask with
73 \code
74 if IMP.core.XYZ.get_is_setup(m, pi):
75 \endcode
76 
77 More abstractly, decorators can be used to
78 - maintain invariants: e.g. an IMP::atom::Bond particle always connects
79  two other particles, both of which are IMP::atom::Bonded particles.
80 - add functionality: e.g. you can get the coordinates as an
81  IMP::algebra::Vector3D
82 - provide uniform names for attributes: so you do not use \quote{x} some places
83 and \quote{X} other places
84 
85 To see a list of all available decorators and to see what functions
86 all decorators have, look at the list of classes which inherit from
87 IMP::Decorator, below.
88 
89 See the IMP::example::ExampleDecorator %example for how to implement a
90 simple decorator.
91 
92 \note Decorator objects are ordered based on the address of the wrapped
93 particle. Like pointers, they are logical values so can be in \c if
94 statements.
95 
96 \implementation{Decorator, IMP_DECORATOR, IMP::example::ExampleDecorator}
97 \n\n For efficiency reasons attribute keys should always be created
98 lazily (at the time of the first use), and not be created as static
99 variables. The reason for this is that initialized attribute keys result
100 in space being allocated in decorators, even before they are used.\n\n
101 Implementors should consult IMP::example::ExampleDecorator,
102 IMP_DECORATOR_METHODS(), IMP_DECORATOR_WITH_TRAITS(), IMP_DECORATOR_GET().
103 
104 A decorator can be cast to a IMP::kernel::Particle* in C++. You have to
105 use the Decorator::get_particle() function in Python.
106 
107 \note It is undefined behavior to use a decorator constructed on
108 a particle that is no longer part of a model. Since constructing
109 decorators is very cheap, you probably should not store decorators,
110 and then would not have this problem.
111 
112 See example::ExampleDecorator to see what a minimal decorator looks like.
113 */
114 class IMPKERNELEXPORT Decorator : public base::Value {
115  private:
117  ParticleIndex pi_;
118  int compare(base::Object* o) const {
119  if (o < get_particle())
120  return -1;
121  else if (o > get_particle())
122  return 1;
123  else
124  return 0;
125  }
126 
127  protected:
129  Decorator();
130 
131 #ifndef IMP_DOXYGEN
132  public:
133 #endif
134  explicit Decorator(ParticleAdaptor p);
135 
136  public:
137  ParticleIndex get_particle_index() const { return pi_; }
138 #ifdef _MSC_VER
139  typedef Particle* ParticleP;
140 #endif
141 #ifndef IMP_DOXYGEN
142  bool __eq__(base::Object* o) const { return operator==(o); }
143  bool __ne__(base::Object* o) const { return operator!=(o); }
144  bool __lt__(base::Object* o) const { return operator<(o); }
145  bool __gt__(base::Object* o) const { return operator>(o); }
146  bool __ge__(base::Object* o) const { return operator>=(o); }
147  bool __le__(base::Object* o) const { return operator<=(o); }
148 #ifndef SWIG
149  bool operator==(base::Object* o) const { return (compare(o) == 0); }
150  bool operator!=(base::Object* o) const { return (compare(o) != 0); }
151  bool operator<(base::Object* o) const { return (compare(o) < 0); }
152  bool operator>(base::Object* o) const { return (compare(o) > 0); }
153  bool operator>=(base::Object* o) const { return !(compare(o) < 0); }
154  bool operator<=(base::Object* o) const { return !(compare(o) > 0); }
155 
156  bool operator==(Particle* o) const { return (compare(o) == 0); }
157  bool operator!=(Particle* o) const { return (compare(o) != 0); }
158  bool operator<(Particle* o) const { return (compare(o) < 0); }
159  bool operator>(Particle* o) const { return (compare(o) > 0); }
160  bool operator>=(Particle* o) const { return !(compare(o) < 0); }
161  bool operator<=(Particle* o) const { return !(compare(o) > 0); }
162 #endif
163 #endif
164 
165  /** \name Methods provided by the Decorator class
166  The following methods are provided by the Decorator class.
167  @{
168  */
169 
170  /** Returns the particle decorated by this decorator.*/
171  /** Returns the particle decorated by this decorator.*/
173  if (!model_)
174  return nullptr;
175  else {
176  IMP_USAGE_CHECK(model_->get_particle(pi_),
177  "Particle " << pi_ << " is no longer part of the model.");
178  return model_->get_particle(pi_);
179  }
180  }
181 
182 #if !defined(IMP_DOXYGEN) && !defined(SWIG)
183  operator Particle*() const { return get_particle(); }
184  Particle* operator->() const { return get_particle(); }
185  operator ParticleIndex() const { return get_particle_index(); }
186 #endif
187 
188  /** \brief Returns the Model containing the particle. */
189  Model* get_model() const { return model_; }
190  // here just to make the docs symmetric
191  private:
192  IMP_ONLY_DOXYGEN(int blah_);
193  //! @}
194  public:
195  IMP_HASHABLE_INLINE(Decorator, return boost::hash_value(get_particle()););
196 #ifdef IMP_DOXYGEN
197 
198  /** \name Methods that all decorators must have
199  All decorators must have the following methods. Decorators
200  which are parameterized (for example IMP::core::XYZR)
201  take an (optional) extra parameter after the Particle in
202  setup_particle(), and get_is_setup().
203  \note these are
204  not actually methods of the Decorator class itself.
205  @{
206  */
207  /** \brief Return true if the particle can be cast to the decorator.
208 
209  That is, if get_is_setup() returns \c true, then it is
210  legal to construct an instance of the decorator with that particle.
211  If not, setup_particle() must be called first.
212  \code
213  IMP::kernel::Particle *p = new IMP::kernel::Particle(m);
214  // it is false
215  std::cout << IMP::core::XYZ::get_is_setup(p) << std::endl;
216  // As a result this is an error
217  IMP::core::XYZ d(p);
218  // now set it up
219  IMP::core::XYZ(p);
220  // now it is true
221  std::cout << IMP::core::XYZ::get_is_setup(p) << std::endl;
222  // and now this code is OK
223  IMP::core::XYZ d(p);
224  \endcode
225  */
226  static bool get_is_setup(Particle* p);
227 
228  /** Create an instance of the Decorator from the particle that has
229  already been set up. The particle must have been set up already
230  (eg get_is_setup(p) must be true), but this is not
231  necessarily checked.
232  */
233  Decorator(Particle* p);
234  /** The default constructor must be defined and create a nullptr decorator,
235  analogous to a \c nullptr pointer in C++ or a \c None object in Python.
236  */
237  Decorator();
238 //! @}
239 #endif
240 #if !defined(IMP_DOXYGEN) && !defined(SWIG)
241  typedef boost::false_type DecoratorHasTraits;
242 #endif
243 };
244 
245 #ifndef IMP_DOXYGEN
246 
248  : model_(m), pi_(pi) {};
249 inline Decorator::Decorator() : pi_(-1) {}
250 
251 #define IMP_CONSTRAINT_DECORATOR_DECL(Name) \
252  private: \
253  static ObjectKey get_constraint_key(); \
254  static void set_constraint(SingletonModifier* before, \
255  SingletonDerivativeModifier* after, Model* m, \
256  ParticleIndex pi); \
257  \
258  public: \
259  Constraint* get_constraint() const { \
260  return dynamic_cast<Constraint*>( \
261  get_particle()->get_value(get_constraint_key())); \
262  } \
263  IMP_REQUIRE_SEMICOLON_CLASS(constraint)
264 
265 #define IMP_CONSTRAINT_DECORATOR_DEF(Name) \
266  ObjectKey Name::get_constraint_key() { \
267  static ObjectKey ret(#Name " score state"); \
268  return ret; \
269  } \
270  void Name::set_constraint(SingletonModifier* before, \
271  SingletonDerivativeModifier* after, Model* m, \
272  ParticleIndex pi) { \
273  if (!after && !before) { \
274  if (m->get_has_attribute(get_constraint_key(), pi)) { \
275  m->remove_score_state(dynamic_cast<ScoreState*>( \
276  m->get_attribute(get_constraint_key(), pi))); \
277  m->remove_attribute(get_constraint_key(), pi); \
278  } \
279  } else { \
280  Constraint* ss = new core::SingletonConstraint( \
281  before, after, m, pi, \
282  std::string(#Name "updater for ") + m->get_particle_name(pi)); \
283  m->add_attribute(get_constraint_key(), pi, ss); \
284  m->add_score_state(ss); \
285  } \
286  } \
287  IMP_REQUIRE_SEMICOLON_NAMESPACE
288 
289 #endif
290 
291 #ifndef SWIG
292 /** Register a function that can be used to check that the particle
293  is valid with respect to the decorator. The function should take
294  a Particle* as an argument and return a bool. It should throw
295  an exception if something is wrong.
296 
297  This macro should only be used in a .cpp file.
298 */
299 #define IMP_CHECK_DECORATOR(Name, function) \
300  IMP::kernel::internal::ParticleCheck Name##pc(Name::get_is_setup, function);
301 #endif
302 
303 #ifndef IMP_DOXYGEN
304 /** Check that the particle satisfies invariants registered by decorators.
305  */
306 IMPKERNELEXPORT void check_particle(Particle* p);
307 #endif
308 
309 IMPKERNEL_END_NAMESPACE
310 
311 #if !defined(SWIG) && !defined IMP_DOXYGEN
312 IMPKERNEL_BEGIN_INTERNAL_NAMESPACE
313 inline void unref(Decorator d) {
314  return base::internal::unref(static_cast<Particle*>(d));
315 }
316 inline void release(Decorator d) {
317  return base::internal::release(static_cast<Particle*>(d));
318 }
319 inline void ref(Decorator d) {
320  return base::internal::ref(static_cast<Particle*>(d));
321 }
322 
323 IMPKERNEL_END_INTERNAL_NAMESPACE
324 
325 #endif
326 
327 #endif /* IMPKERNEL_DECORATOR_H */
Particle * get_particle() const
Basic types used by IMP.
Model * get_model() const
Returns the Model containing the particle.
#define IMP_HASHABLE_INLINE(name, hashret)
#define IMP_USAGE_CHECK(expr, message)
A runtime test for incorrect usage of a class or method.
Basic types used by IMP.
#define IMP_ONLY_DOXYGEN(x)
Only show something to doxygen.
int compare(const VectorD< D > &a, const VectorD< D > &b)
lexicographic comparison of two vectors
Definition: VectorD.h:371
A class for storing lists of IMP items.
Various general useful macros for IMP.
Class to handle individual model particles.
Storage of a model, its restraints, constraints and particles.
Common base class for heavy weight IMP objects.
A base class for constraints.
A nullptr-initialized pointer to an Object.
IMP::kernel::Particle Particle
For backwards compatibility.
A shared base class to help in debugging and things.
IMP::kernel::Decorator Decorator
IMP::kernel::ParticleIndex ParticleIndex
Class for storing model, its restraints, constraints, and particles.