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