IMP logo
IMP Reference Guide  2.7.0
The Integrative Modeling Platform
decorator_macros.h
Go to the documentation of this file.
1 /**
2  * \file IMP/decorator_macros.h
3  * \brief Various general useful macros for IMP.
4  *
5  * Copyright 2007-2017 IMP Inventors. All rights reserved.
6  *
7  */
8 
9 #ifndef IMPKERNEL_DECORATOR_MACROS_H
10 #define IMPKERNEL_DECORATOR_MACROS_H
11 #include <IMP/kernel_config.h>
12 #include "particle_index.h"
13 #include "Particle.h"
14 #include "Decorator.h"
15 #include <IMP/check_macros.h>
16 #include <IMP/log_macros.h>
17 #include <IMP/showable_macros.h>
18 #include <IMP/warning_macros.h>
19 
20 
21 
22 /** Implement the needed methods for a decorator based on
23  - setup_particle()
24  - get_is_setup()
25  methods that you provide.
26 */
27 #define IMP_DECORATOR_METHODS(Name, Parent) \
28  public: \
29  /* Should be private but SWIG accesses it through the
30  comparison
31  macros*/ IMP_NO_DOXYGEN( \
32  typedef Parent ParentDecorator); \
33  Name() : Parent() {} \
34  Name(::IMP::Model *m, ::IMP::ParticleIndex id) \
35  : Parent(m, id) { \
36  IMP_INTERNAL_CHECK( \
37  get_is_setup(m, id), \
38  "Particle " << m->get_particle_name(id) \
39  << " missing required attributes for decorator " \
40  << #Name); \
41  } \
42  explicit Name(const IMP::ParticleAdaptor &d) : Parent(d) { \
43  IMP_INTERNAL_CHECK( \
44  get_is_setup(d.get_model(), d.get_particle_index()), \
45  "Particle " << d.get_model()->get_particle_name( \
46  d.get_particle_index()) \
47  << " missing required attributes for decorator " \
48  << #Name); \
49  } \
50  static bool get_is_setup(const IMP::ParticleAdaptor &p) { \
51  return get_is_setup(p.get_model(), p.get_particle_index()); \
52  } \
53  IMP_SHOWABLE(Name)
54 
55 
56 
57 /** Implement the needed methods for a decorator based on
58  - setup_particle()
59  - get_is_setup()
60  methods that you provide.
61 */
62 #define IMP_DECORATOR_WITH_TRAITS_METHODS(Name, Parent, TraitsType, \
63  traits_name, default_traits) \
64  private: \
65  TraitsType traits_; \
66  \
67  public: \
68  typedef TraitsType DecoratorTraits; \
69  const DecoratorTraits &get_decorator_traits() const { return traits_; } \
70  static const DecoratorTraits &get_default_decorator_traits() { \
71  static TraitsType dt = default_traits; \
72  return dt; \
73  } \
74  /* Should be private but SWIG accesses it through the
75  comparison
76  macros*/ IMP_NO_DOXYGEN( \
77  typedef Parent ParentDecorator); \
78  IMP_NO_DOXYGEN(typedef boost::true_type DecoratorHasTraits); \
79  Name() : Parent() {} \
80  Name(::IMP::Model *m, ::IMP::ParticleIndex id, \
81  const TraitsType &tr = default_traits) \
82  : Parent(m, id), traits_(tr) { \
83  IMP_INTERNAL_CHECK( \
84  get_is_setup(m, id, tr), \
85  "Particle " << m->get_particle_name(id) \
86  << " missing required attributes for decorator " \
87  << #Name); \
88  } \
89  explicit Name(const IMP::ParticleAdaptor &d, \
90  const TraitsType &tr = default_traits) \
91  : Parent(d), traits_(tr) { \
92  IMP_INTERNAL_CHECK( \
93  get_is_setup(d.get_model(), d.get_particle_index(), tr), \
94  "Particle " << d.get_model()->get_particle_name( \
95  d.get_particle_index()) \
96  << " missing required attributes for decorator " \
97  << #Name); \
98  } \
99  static bool get_is_setup(const IMP::ParticleAdaptor &p, \
100  const TraitsType &tr = default_traits) { \
101  return get_is_setup(p.get_model(), p.get_particle_index(), tr); \
102  } \
103  IMP_SHOWABLE(Name)
104 
105 /** Decorators need to be able to be set up from Particles, ParticleIndexes
106  and other Decorators. To help keep things uniform, we provide macros
107  to declare the setup functions. These macros expect that an appropriate
108  `do_setup_particle(Model *, ParticleIndex, args...)` function is
109  defined.
110 */
111 #define IMP_DECORATOR_SETUP_0(Name) \
112  /** Setup the particle so it can be used with this decorator. */ \
113  static Name setup_particle(Model *m, ParticleIndex pi) { \
114  IMP_USAGE_CHECK(!get_is_setup(m, pi), \
115  "Particle " << m->get_particle_name(pi) \
116  << " already set up as " << #Name); \
117  do_setup_particle(m, pi); \
118  return Name(m, pi); \
119  } \
120  static Name setup_particle(IMP::ParticleAdaptor decorator) { \
121  return setup_particle(decorator.get_model(), \
122  decorator.get_particle_index()); \
123  }
124 /** \see IMP_DECORATOR_SETUP_0() */
125 #define IMP_DECORATOR_SETUP_1(Name, FirstArgumentType, first_argument_name) \
126  /** Setup the particle so that it can be used with this decorator */ \
127  static Name setup_particle(Model *m, ParticleIndex pi, \
128  FirstArgumentType first_argument_name) { \
129  IMP_USAGE_CHECK(!get_is_setup(m, pi), \
130  "Particle " << m->get_particle_name(pi) \
131  << " already set up as " << #Name); \
132  do_setup_particle(m, pi, first_argument_name); \
133  return Name(m, pi); \
134  } \
135  /** \see setup_particle(m, pi, first_argument_name) */ \
136  static Name setup_particle(IMP::ParticleAdaptor decorator, \
137  FirstArgumentType first_argument_name) { \
138  return setup_particle(decorator.get_model(), \
139  decorator.get_particle_index(), \
140  first_argument_name); \
141  }
142 
143 /** \see IMP_DECORATOR_SETUP_0() */
144 #define IMP_DECORATOR_SETUP_2(Name, FirstArgumentType, first_argument_name, \
145  SecondArgumentType, second_argument_name) \
146  /** Setup the particle so it can be used with this decorator. */ \
147  static Name setup_particle(Model *m, ParticleIndex pi, \
148  FirstArgumentType first_argument_name, \
149  SecondArgumentType second_argument_name) { \
150  IMP_USAGE_CHECK(!get_is_setup(m, pi), \
151  "Particle " << m->get_particle_name(pi) \
152  << " already set up as " << #Name); \
153  do_setup_particle(m, pi, first_argument_name, second_argument_name); \
154  return Name(m, pi); \
155  } \
156  static Name setup_particle(IMP::ParticleAdaptor decorator, \
157  FirstArgumentType first_argument_name, \
158  SecondArgumentType second_argument_name) { \
159  return setup_particle(decorator.get_model(), \
160  decorator.get_particle_index(), first_argument_name, \
161  second_argument_name); \
162  }
163 /** \see IMP_DECORATOR_SETUP_0() */
164 #define IMP_DECORATOR_SETUP_3(Name, FirstArgumentType, first_argument_name, \
165  SecondArgumentType, second_argument_name, \
166  ThirdArgumentType, third_argument_name) \
167  /** Setup the particle so it can be used with this decorator. */ \
168  static Name setup_particle(Model *m, ParticleIndex pi, \
169  FirstArgumentType first_argument_name, \
170  SecondArgumentType second_argument_name, \
171  ThirdArgumentType third_argument_name) { \
172  IMP_USAGE_CHECK(!get_is_setup(m, pi), \
173  "Particle " << m->get_particle_name(pi) \
174  << " already set up as " << #Name); \
175  do_setup_particle(m, pi, first_argument_name, second_argument_name, \
176  third_argument_name); \
177  return Name(m, pi); \
178  } \
179  static Name setup_particle(IMP::ParticleAdaptor decorator, \
180  FirstArgumentType first_argument_name, \
181  SecondArgumentType second_argument_name, \
182  ThirdArgumentType third_argument_name) { \
183  return setup_particle(decorator.get_model(), \
184  decorator.get_particle_index(), first_argument_name, \
185  second_argument_name, third_argument_name); \
186  }
187 /** \see IMP_DECORATOR_SETUP_0() */
188 #define IMP_DECORATOR_SETUP_4(Name, FirstArgumentType, first_argument_name, \
189  SecondArgumentType, second_argument_name, \
190  ThirdArgumentType, third_argument_name, \
191  FourthArgumentType, fourth_argument_name) \
192  /** Setup the particle so it can be used with this decorator. */ \
193  static Name setup_particle(Model *m, ParticleIndex pi, \
194  FirstArgumentType first_argument_name, \
195  SecondArgumentType second_argument_name, \
196  ThirdArgumentType third_argument_name, \
197  FourthArgumentType fourth_argument_name) { \
198  IMP_USAGE_CHECK(!get_is_setup(m, pi), \
199  "Particle " << m->get_particle_name(pi) \
200  << " already set up as " << #Name); \
201  do_setup_particle(m, pi, first_argument_name, second_argument_name, \
202  third_argument_name, fourth_argument_name); \
203  return Name(m, pi); \
204  } \
205  static Name setup_particle(IMP::ParticleAdaptor decorator, \
206  FirstArgumentType first_argument_name, \
207  SecondArgumentType second_argument_name, \
208  ThirdArgumentType third_argument_name, \
209  FourthArgumentType fourth_argument_name) { \
210  return setup_particle(decorator.get_model(), \
211  decorator.get_particle_index(), first_argument_name, \
212  second_argument_name, third_argument_name, \
213  fourth_argument_name); \
214  }
215 
216 /** Decorators need to be able to be set up from Particles, ParticleIndexes
217  and other Decorators. To help keep things uniform, we provide macros
218  to declare the setup functions. These macros expect that an appropriate
219  `do_setup_particle(Model *, ParticleIndex, args...)` function is
220  defined. But any docs needed before the macro invocation.
221 */
222 #define IMP_DECORATOR_TRAITS_SETUP_0(Name) \
223  /** Setup the particle so it can be used with this decorator. */ \
224  static Name setup_particle( \
225  Model *m, ParticleIndex pi, \
226  DecoratorTraits tr = get_default_decorator_traits()) { \
227  do_setup_particle(m, pi, tr); \
228  return Name(m, pi, tr); \
229  } \
230  static Name setup_particle( \
231  IMP::ParticleAdaptor d, \
232  DecoratorTraits tr = get_default_decorator_traits()) { \
233  do_setup_particle(d.get_model(), d.get_particle_index(), tr); \
234  return Name(d.get_model(), d.get_particle_index(), tr); \
235  }
236 /** \see IMP_DECORATOR_TRAITS_SETUP_0() */
237 #define IMP_DECORATOR_TRAITS_SETUP_1(Name, FirstArgumentType, \
238  first_argument_name) \
239  static Name setup_particle( \
240  Model *m, ParticleIndex pi, \
241  FirstArgumentType first_argument_name, \
242  DecoratorTraits tr = get_default_decorator_traits()) { \
243  do_setup_particle(m, pi, first_argument_name, tr); \
244  return Name(m, pi, tr); \
245  } \
246  static Name setup_particle( \
247  IMP::ParticleAdaptor d, FirstArgumentType first_argument_name, \
248  DecoratorTraits tr = get_default_decorator_traits()) { \
249  do_setup_particle(d.get_model(), d.get_particle_index(), \
250  first_argument_name, tr); \
251  return Name(d.get_model(), d.get_particle_index(), tr); \
252  }
253 /** \see IMP_DECORATOR_TRAITS_SETUP_0() */
254 #define IMP_DECORATOR_TRAITS_SETUP_2(Name, FirstArgumentType, \
255  first_argument_name, SecondArgumentType, \
256  second_argument_name) \
257  static Name setup_particle( \
258  Model *m, ParticleIndex pi, \
259  FirstArgumentType first_argument_name, \
260  SecondArgumentType second_argument_name, \
261  DecoratorTraits tr = get_default_decorator_traits()) { \
262  do_setup_particle(m, pi, first_argument_name, second_argument_name, tr); \
263  return Name(m, pi, tr); \
264  } \
265  static Name setup_particle( \
266  IMP::ParticleAdaptor d, FirstArgumentType first_argument_name, \
267  SecondArgumentType second_argument_name, \
268  DecoratorTraits tr = get_default_decorator_traits()) { \
269  do_setup_particle(d.get_model(), d.get_particle_index(), \
270  first_argument_name, second_argument_name, tr); \
271  return Name(d.get_model(), d.get_particle_index(), tr); \
272  }
273 
274 //! Perform actions dependent on whether a particle has an attribute.
275 /** A common pattern is to check if a particle has a particular attribute,
276  do one thing if it does and another if it does not. This macro implements
277  that pattern. It requires that the method get_particle() return the
278  particle being used.
279 
280  \param[in] AttributeKey The key for the attribute
281  \param[in] Type The type for the attribute ("Int", "Float", "String")
282  \param[in] has_action The action to take if the Particle has the attribute.
283  The attribute value is stored in the variable VALUE.
284  \param[in] not_has_action The action to take if the Particle does not have
285  the attribute.
286  \see IMP_DECORATOR_GET()
287  \see IMP_DECORATOR_GET_SET()
288 
289 */
290 #define IMP_DECORATOR_GET(AttributeKey, Type, has_action, not_has_action) \
291  do { \
292  if (get_model()->get_has_attribute(AttributeKey, get_particle_index())) { \
293  Type VALUE = \
294  get_model()->get_attribute(AttributeKey, get_particle_index()); \
295  has_action; \
296  } else { \
297  not_has_action; \
298  } \
299  } while (false)
300 
301 //! Set an attribute, creating it if it does not already exist.
302 /** Another common pattern is to have an assumed value if the attribute
303  is not there. Then, you sometimes need to set the value whether it
304  is there or not.
305  \see IMP_DECORATOR_GET()
306  \see IMP_DECORATOR_GET_SET()
307 */
308 #define IMP_DECORATOR_SET(AttributeKey, value) \
309  do { \
310  if (get_model()->get_has_attribute(AttributeKey, get_particle_index())) { \
311  get_model()->set_attribute(AttributeKey, get_particle_index(), value); \
312  } else { \
313  get_model()->add_attribute(AttributeKey, get_particle_index(), value); \
314  } \
315  } while (false)
316 
317 //! Define methods for getting and setting a particular simple field
318 /** This macro defines methods to get and set a particular attribute.
319 
320  \param[in] name The lower case name of the attribute
321  \param[in] AttributeKey The AttributeKey object controlling
322  the attribute.
323  \param[in] Type The type of the attribute (upper case).
324  \param[in] ReturnType The type to return from the get.
325  \see IMP_DECORATOR_GET()
326  \see IMP_DECORATOR_SET()
327 */
328 #define IMP_DECORATOR_GET_SET(name, AttributeKey, Type, ReturnType) \
329  ReturnType get_##name() const { \
330  return static_cast<ReturnType>( \
331  get_model()->get_attribute(AttributeKey, get_particle_index())); \
332  } \
333  void set_##name(ReturnType t) { \
334  get_model()->set_attribute(AttributeKey, get_particle_index(), t); \
335  } \
336  IMP_REQUIRE_SEMICOLON_CLASS(getset##name)
337 
338 //! Define methods for getting and setting an optional simple field.
339 /** See IMP_DECORATOR_GET_SET(). The difference is that here you can provide
340  a default value to use if the decorator does not have the attribute.
341 
342  \param[in] name The lower case name of the attribute
343  \param[in] AttributeKey The expression to get the required attribute key.
344  \param[in] Type The type of the attribute (upper case).
345  \param[in] ReturnType The type to return from the get.
346  \param[in] default_value The value returned if the attribute is missing.
347 */
348 #define IMP_DECORATOR_GET_SET_OPT(name, AttributeKey, Type, ReturnType, \
349  default_value) \
350  ReturnType get_##name() const { \
351  IMP_DECORATOR_GET(AttributeKey, Type, \
352  return static_cast<ReturnType>(VALUE), \
353  return default_value); \
354  } \
355  void set_##name(ReturnType t) { IMP_DECORATOR_SET(AttributeKey, t); } \
356  IMP_REQUIRE_SEMICOLON_CLASS(getset_##name)
357 
358 #define IMP_DECORATORS_DECL(Name, PluralName) \
359  class Name; \
360  typedef IMP::Vector<Name> PluralName
361 
362 #ifndef IMP_DOXYGEN
363 #define IMP_DECORATORS_DEF(Name, PluralName) \
364  /* needed so there is no ambiguity with operator->*/ \
365  inline std::ostream &operator<<(std::ostream &out, Name n) { \
366  n.show(out); \
367  return out; \
368  }
369 #else
370 #define IMP_DECORATORS_DEF(Name, PluralName)
371 #endif
372 
373 //! Define the types for storing sets of decorators
374 /** The macro defines the types PluralName and PluralNameTemp.
375  Parent is unused and remains for backward compatibility
376  */
377 #define IMP_DECORATORS(Name, PluralName, Parent) \
378  IMP_DECORATORS_DECL(Name, PluralName); \
379  IMP_DECORATORS_DEF(Name, PluralName)
380 
381 //! Define the types for storing sets of decorators
382 /** The macro defines the types PluralName and PluralNameTemp.
383  */
384 #define IMP_DECORATORS_WITH_TRAITS(Name, PluralName, Parent) \
385  /* needed so there is no ambiguity with operator->*/ \
386  inline std::ostream &operator<<(std::ostream &out, Name n) { \
387  n.show(out); \
388  return out; \
389  } \
390  typedef IMP::Vector<Name> PluralName
391 
392 
393 /**
394  Declares Decorator methods that allows (privately) setting a constraint
395  and publicly getting that constraint
396  */
397 #define IMP_CONSTRAINT_DECORATOR_DECL(Name) \
398  private: \
399  static ObjectKey get_constraint_key(); \
400  /** set a constraint associated with this decorator that applies 'before'
401  and 'after' before and after evaluation. The constraint is added as
402  a model ScoreState. If before and after are Null, the constraint is
403  reset and removed from the model list of score states.
404  */ \
405  static void set_constraint(SingletonModifier* before, \
406  SingletonDerivativeModifier* after, Model* m, \
407  ParticleIndex pi); \
408  \
409  public: \
410  Constraint* get_constraint() const { \
411  return dynamic_cast<Constraint*>( \
412  get_particle()->get_value(get_constraint_key())); \
413  } \
414  IMP_REQUIRE_SEMICOLON_CLASS(constraint)
415 
416 /**
417  Defines Decorator methods that allows (privately) setting a constraint
418  and publicly getting that constraint. The constraint is added as a
419  score state to the model.
420  */
421 #define IMP_CONSTRAINT_DECORATOR_DEF(Name) \
422  ObjectKey Name::get_constraint_key() { \
423  static ObjectKey ret(#Name " score state"); \
424  return ret; \
425  } \
426  void Name::set_constraint(SingletonModifier* before, \
427  SingletonDerivativeModifier* after, Model* m, \
428  ParticleIndex pi) { \
429  if (!after && !before) { \
430  if (m->get_has_attribute(get_constraint_key(), pi)) { \
431  m->remove_score_state(dynamic_cast<ScoreState*>( \
432  m->get_attribute(get_constraint_key(), pi))); \
433  m->remove_attribute(get_constraint_key(), pi); \
434  } \
435  } else { \
436  Constraint* ss = new core::SingletonConstraint( \
437  before, after, m, pi, \
438  std::string(#Name "updater for ") + m->get_particle_name(pi)); \
439  m->add_attribute(get_constraint_key(), pi, ss); \
440  m->add_score_state(ss); \
441  } \
442  } \
443  IMP_REQUIRE_SEMICOLON_NAMESPACE
444 
445 
446 /** Register a function that can be used to check that the particle
447  is valid with respect to the decorator. The function should take
448  a Particle* as an argument and return a bool. It should throw
449  an exception if something is wrong.
450 
451  This macro should only be used in a .cpp file.
452 */
453 #define IMP_CHECK_DECORATOR(Name, function) \
454  IMP::internal::ParticleCheck Name##pc(Name::get_is_setup, function);
455 
456 
457 //! Create a decorator that computes some sort of summary info on a set
458 /** Examples include a centroid or a cover for a set of particles.
459 
460  \param[in] Name The name for the decorator
461  \param[in] Parent the parent decorator type
462  \param[in] Members the way to pass a set of particles in
463  \param[in] SetupDoc extra documentation for setup
464 */
465 #define IMP_SUMMARIZE_DECORATOR_DECL(Name, Parent, Members, SetupDoc) \
466  class IMPCOREEXPORT Name : public Parent { \
467  IMP_CONSTRAINT_DECORATOR_DECL(Name); \
468  private: \
469  /** Sets up Name over particles in pis */ \
470  static void do_setup_particle(Model *m, ParticleIndex pi, \
471  const ParticleIndexes &pis); \
472  /** Sets up Name over particles passed by applying the refiner
473  over the particle pi
474  */ \
475  static void do_setup_particle(Model *m, ParticleIndex pi, \
476  Refiner *ref); \
477  \
478  public: \
479  IMP_DECORATOR_METHODS(Name, Parent); \
480  /** Sets up Name over members, and constrains Name to be
481  computed before model evaluation and to propagate derivatives
482  following model evaluation.
483  SetupDoc
484  */ \
485  IMP_DECORATOR_SETUP_1(Name, ParticleIndexesAdaptor, members); \
486  /** Sets up Name over particles passed by applying the refiner
487  over the particle pi, and constrains Name to be computed before
488  model evaluation and to propagate derivatives following model
489  evaluation.
490  SetupDoc
491  */ \
492  IMP_DECORATOR_SETUP_1(Name, Refiner *, refiner); \
493  static bool get_is_setup(Model *m, ParticleIndex pi) { \
494  return m->get_has_attribute(get_constraint_key(), pi); \
495  } \
496  IMP_NO_DOXYGEN(typedef boost::false_type DecoratorHasTraits); \
497  \
498  private: \
499  /* hide set methods*/ \
500  void set_coordinates() {}; \
501  void set_coordinates_are_optimized() const {} \
502  void set_coordinate() const {} \
503  void set_radius() const {} \
504  }; \
505  IMP_DECORATORS(Name, Name##s, Parent##s)
506 
507 
508 /** \see IMP_SUMMARIZE_DECORATOR_DECL()
509  \param[in] Name The name for the decorator
510  \param[in] Parent the parent decorator type
511  \param[in] Members the way to pass a set of particles in
512  \param[in] create_pre_modifier the statements to create the
513  SingletonModifier which computes the summary info,
514  using refiner 'ref'
515  \param[in] create_post_modifier a SingletonDerivativeModifier for
516  the derivatives of the summary back to its members,
517  using refiner 'ref'
518 */
519 #define IMP_SUMMARIZE_DECORATOR_DEF(Name, Parent, Members, \
520  create_pre_modifier, \
521  create_post_modifier) \
522  void Name::do_setup_particle(Model *m, ParticleIndex pi, \
523  const ParticleIndexes &pis) { \
524  Refiner *ref = new FixedRefiner(IMP::get_particles(m, pis)); \
525  SingletonModifier* pre_mod = create_pre_modifier; \
526  SingletonDerivativeModifier* post_mod = create_post_modifier; \
527  if (!Parent::get_is_setup(m, pi)) Parent::setup_particle(m, pi); \
528  set_constraint(pre_mod, post_mod, m, pi); \
529  } \
530  \
531  void Name::do_setup_particle(Model *m, ParticleIndex pi, \
532  Refiner *ref) { \
533  SingletonModifier* pre_mod = create_pre_modifier; \
534  SingletonDerivativeModifier* post_mod = create_post_modifier; \
535  if (!Parent::get_is_setup(m, pi)) Parent::setup_particle(m, pi); \
536  set_constraint(pre_mod, post_mod, m, pi); \
537  } \
538  \
539  void Name::show(std::ostream &out) const { \
540  out << #Name << " at " << static_cast<Parent>(*this); \
541  } \
542  IMP_CONSTRAINT_DECORATOR_DEF(Name)
543 
544 #endif /* IMPKERNEL_DECORATOR_MACROS_H */
The base class for decorators.
Various general useful functions for IMP.
Various general useful macros for IMP.
Logging and error reporting support.
Classes to handle individual model particles. (Note that implementation of inline functions is in int...
Exception definitions and assertions.
Various general useful macros for IMP.