IMP logo
IMP Reference Guide  develop.6100cc8943,2021/10/26
The Integrative Modeling Platform
Model.h
Go to the documentation of this file.
1 /**
2  * \file IMP/Model.h
3  * \brief Storage of a model, its restraints, constraints and particles.
4  *
5  * Copyright 2007-2021 IMP Inventors. All rights reserved.
6  *
7  */
8 
9 #ifndef IMPKERNEL_MODEL_H
10 #define IMPKERNEL_MODEL_H
11 
12 #include <IMP/kernel_config.h>
13 #include "ModelObject.h"
14 #include "ScoringFunction.h"
15 #include "Restraint.h"
16 #include "RestraintSet.h"
17 #include "ScoreState.h"
18 #include "container_macros.h"
19 #include "base_types.h"
20 //#include "Particle.h"
21 #include "Undecorator.h"
22 #include "internal/AttributeTable.h"
23 #include "internal/attribute_tables.h"
24 #include "internal/moved_particles_cache.h"
25 #include <IMP/Object.h>
26 #include <IMP/Pointer.h>
27 #include <boost/unordered_map.hpp>
28 #include <boost/unordered_set.hpp>
29 #include <IMP/tuple_macros.h>
30 #include <boost/iterator/transform_iterator.hpp>
31 #include <boost/iterator/filter_iterator.hpp>
32 
33 #include <limits>
34 
35 IMPKERNEL_BEGIN_NAMESPACE
36 
37 class ModelObject;
38 class Undecorator;
39 class Particle;
40 
41 #if !defined(SWIG) && !defined(IMP_DOXYGEN)
42 namespace internal {
43 enum Stage {
44  NOT_EVALUATING,
45  BEFORE_EVALUATING,
46  EVALUATING,
47  AFTER_EVALUATING,
48  COMPUTING_DEPENDENCIES
49 };
50 }
51 #endif
52 
53 class Model;
54 
55 //! Class for storing model, its restraints, constraints, and particles.
56 /** The Model maintains a standard \imp container for each of Particle,
57  ScoreState and Restraint object types.
58 
59  Each Float attribute has an associated range which reflects the
60  range of values that it is expected to take on during optimization.
61  The optimizer can use these ranges to make the optimization process
62  more efficient. By default, the range estimates are simply the
63  range of values for that attribute in the various particles, but
64  it can be set to another value. For example, an attribute storing
65  an angle could have the range set to (0,PI).
66 
67  The ranges are not enforced; they are just guidelines. In order to
68  enforce ranges, see, for example,
69  IMP::example::ExampleSingletonModifier.
70 
71  \headerfile Model.h "IMP/Model.h"
72  */
73 class IMPKERNELEXPORT Model : public Object
74 #if !defined(SWIG) && !defined(IMP_DOXYGEN)
75  ,
76  public internal::Masks,
77  // The attribute tables provide fast access to
78  // e.g. particle attributes, etc.
79  public internal::FloatAttributeTable,
80  public internal::StringAttributeTable,
81  public internal::IntAttributeTable,
82  public internal::ObjectAttributeTable,
83  public internal::WeakObjectAttributeTable,
84  public internal::IntsAttributeTable,
85  public internal::FloatsAttributeTable,
86  public internal::ObjectsAttributeTable,
87  public internal::ParticleAttributeTable,
88  public internal::ParticlesAttributeTable
89 #endif
90  {
92  // must be up top
93  // we don't want any liveness checks
94  IMP_NAMED_TUPLE_5(NodeInfo, NodeInfos, Edges, inputs, Edges, input_outputs,
95  Edges, outputs, Edges, readers, Edges, writers, );
96  typedef boost::unordered_map<const ModelObject *, NodeInfo> DependencyGraph;
97  DependencyGraph dependency_graph_;
98  boost::unordered_set<const ModelObject *> no_dependencies_;
99  boost::unordered_map<const ModelObject *, ScoreStatesTemp>
100  required_score_states_;
101 
102  // basic representation
103  boost::unordered_map<FloatKey, FloatRange> ranges_;
104 
105  ParticleIndexes free_particles_;
108 
109  Vector<PointerMember<Object> > model_data_;
110 
111  void do_add_dependencies(const ModelObject *mo);
112  void do_clear_required_score_states(ModelObject *mo);
113  void do_check_required_score_states(const ModelObject *mo) const;
114  void do_check_update_order(const ScoreState *ss) const;
115  void do_check_inputs_and_outputs(const ModelObject *mo) const;
116  void do_check_readers_and_writers(const ModelObject *mo) const;
117  void do_check_not_in_readers_and_writers(const ModelObject *mo) const;
118  void do_clear_dependencies(const ModelObject *mo);
119 
120  // used to track time when triggers are activated
121  unsigned age_counter_;
122  // all triggers
123  Vector<unsigned> trigger_age_;
124  // time when dependencies were last changed, or 0
125  unsigned dependencies_age_;
126  // cache of restraints that are affected by each moved particle,
127  // used for evaluate_moved() and related functions
128  internal::MovedParticlesRestraintCache moved_particles_restraint_cache_;
129  // cache of particles that are affected by each moved particle
130  internal::MovedParticlesParticleCache moved_particles_particle_cache_;
131  // time when moved_particles_*_cache_ were last updated, or 0
132  unsigned moved_particles_cache_age_;
133 
134  // update model age (can never be zero, even if it wraps)
135  void increase_age() {
136  age_counter_++;
137  if (age_counter_ == 0) {
138  age_counter_ = 1;
139  }
140  }
141 
142 #if !defined(IMP_DOXYGEN) && !defined(SWIG)
143  // things the evaluate template functions need, can't be bothered with friends
144  public:
145 #endif
146  // check more things on the first call
147  bool first_call_;
148  // the stage of evaluation
149  internal::Stage cur_stage_;
150 
151  //! Get all Restraints that depend on the given particle
152  const std::set<Restraint *> &get_dependent_restraints(ParticleIndex pi) {
153  return moved_particles_restraint_cache_.get_dependent_restraints(pi);
154  }
155 
156  //! Get all particles that depend on the given particle
157  const std::set<ParticleIndex> &get_dependent_particles(ParticleIndex pi) {
158  return moved_particles_particle_cache_.get_dependent_particles(pi);
159  }
160 
161  ModelObjectsTemp get_dependency_graph_inputs(const ModelObject *mo) const;
162  ModelObjectsTemp get_dependency_graph_outputs(const ModelObject *mo) const;
163  bool do_get_has_dependencies(const ModelObject *mo) const {
164  return no_dependencies_.find(mo) == no_dependencies_.end();
165  }
166  void do_set_has_dependencies(const ModelObject *mo, bool tf);
167  void do_set_has_all_dependencies(bool tf);
168 
169  void validate_computed_derivatives() const {}
170  void set_has_all_dependencies(bool tf);
171  bool get_has_all_dependencies() const;
172  void check_dependency_invariants() const;
173  void check_dependency_invariants(const ModelObject *mo) const;
174  ScoreStatesTemp get_ancestor_score_states(const ModelObject *mo) const;
175  ScoreStatesTemp get_descendent_score_states(const ModelObject *mo) const;
176 
177  void before_evaluate(const ScoreStatesTemp &states);
178  void after_evaluate(const ScoreStatesTemp &states, bool calc_derivs);
179 
180  internal::Stage get_stage() const { return cur_stage_; }
181  ParticleIndex add_particle_internal(Particle *p);
182  static void do_remove_score_state(ScoreState *obj);
183  void do_add_score_state(ScoreState *obj);
184  void do_remove_particle(ParticleIndex pi);
185  bool do_get_has_required_score_states(const ModelObject *mo) const;
186  void do_set_has_required_score_states(ModelObject *mo, bool tf);
187  const ScoreStatesTemp &do_get_required_score_states(const ModelObject *mo)
188  const {
189  IMP_USAGE_CHECK(do_get_has_required_score_states(mo),
190  "Doesn't have score states");
191  return required_score_states_.find(mo)->second;
192  }
193  void do_add_model_object(ModelObject *mo);
194  void do_remove_model_object(ModelObject *mo);
195 
196  public:
197  //! Construct an empty model
198  Model(std::string name = "Model %1%");
199 
200  public:
201 #if !defined(SWIG) && !defined(IMP_DOXYGEN)
202  IMP_MODEL_IMPORT(internal::FloatAttributeTable);
203  IMP_MODEL_IMPORT(internal::StringAttributeTable);
204  IMP_MODEL_IMPORT(internal::IntAttributeTable);
205  IMP_MODEL_IMPORT(internal::ObjectAttributeTable);
206  IMP_MODEL_IMPORT(internal::WeakObjectAttributeTable);
207  IMP_MODEL_IMPORT(internal::IntsAttributeTable);
208  IMP_MODEL_IMPORT(internal::FloatsAttributeTable);
209  IMP_MODEL_IMPORT(internal::ObjectsAttributeTable);
210  IMP_MODEL_IMPORT(internal::ParticleAttributeTable);
211  IMP_MODEL_IMPORT(internal::ParticlesAttributeTable);
212 #endif
213  //! Clear all the cache attributes of a given particle.
214  void clear_particle_caches(ParticleIndex pi);
215 
216  //! Add particle to the model
217  ParticleIndex add_particle(std::string name);
218 
219  //! Get the name of a particle
220  std::string get_particle_name(ParticleIndex pi);
221 
222  //! Add the passed Undecorator to the particle.
223  void add_undecorator(ParticleIndex pi, Undecorator *d);
224 
225  /** @name States
226 
227  ScoreStates maintain invariants in the Model (see ScoreState
228  for more information.)
229 
230  ScoreStates do not need to be explictly added to the Model, but they
231  can be if desired in order to keep them alive as long as the model is
232  alive.
233 
234  \advancedmethod
235  */
236  /**@{*/
237  IMP_LIST_ACTION(public, ScoreState, ScoreStates, score_state, score_states,
238  ScoreState *, ScoreStates, do_add_score_state(obj), {},
239  do_remove_score_state(obj));
240  /**@}*/
241 
242  public:
243 #ifndef SWIG
244  using Object::clear_caches;
245 #endif
246 
247  //! Sometimes it is useful to be able to make sure the model is up to date
248  /** This method updates all the state but does not necessarily compute the
249  score. Use this to make sure that your containers and rigid bodies are
250  up to date.
251  */
252  void update();
253 
254 #ifdef IMP_DOXYGEN
255  /** \name Accessing attributes
256  \anchor model_attributes
257  All the attribute data associated with each Particle are stored in the
258  Model. For each type of attribute, there are the methods detailed below
259  (where, eg, TypeKey is FloatKey or StringKey)
260  @{
261  */
262  //! add particle atribute with the specied key and initial value
263  /** \pre get_has_attribute(attribute_key, particle) is false*/
264  void add_attribute(TypeKey attribute_key, ParticleIndex particle, Type value);
265 
266  //! remove particle attribute with the specied key
267  /** \pre get_has_attribute(attribute_key, particle) is true*/
268  void remove_attribute(TypeKey attribute_key, ParticleIndex particle);
269 
270  //! return true if particle has attribute with the specified key
271  bool get_has_attribute(TypeKey attribute_key, ParticleIndex particle) const;
272 
273  //! set the value of particle attribute with the specified key
274  /** \pre get_has_attribute(attribute_key, particle) is true*/
275  void set_attribute(TypeKey attribute_key, ParticleIndex particle, Type value);
276 
277  //! get the value of the particle attribute with the specified key
278  /** \pre get_has_attribute(attribute_key, particle) is true*/
279  Type get_attribute(TypeKey attribute_key, ParticleIndex particle);
280 
281  /** Cache attributes, unlike normal attributes, can be added during
282  evaluation. They are also cleared by the clear_cache_attributes() method.
283  Cache attributes should be used when one is adding data to a particle
284  to aid scoring (eg cache the rigid body collision acceleration structure).
285 
286  When some pertinent aspect of the particle changes, the clear method
287  should
288  be called (yes, this is a bit vague). Examples where it should be cleared
289  include changing the set of members of a core::RigidBody or their
290  coordinates, changing the members of an atom::Hierarchy.
291  */
292  void add_cache_attribute(TypeKey attribute_key, ParticleIndex particle,
293  Type value);
294 
295  //! Optimized attributes are the parameters of the model that are
296  //! allowed to be modified by samplers and optimizers
297  void set_is_optimized(TypeKey attribute_key, ParticleIndex particle,
298  bool true_or_false);
299 /** @} */
300 #endif
301 
302 #ifdef SWIG
303 #define IMP_MODEL_ATTRIBUTE_METHODS(Type, Value) \
304  void add_attribute(Type##Key attribute_key, ParticleIndex particle, \
305  Value value); \
306  void remove_attribute(Type##Key attribute_key, ParticleIndex particle); \
307  bool get_has_attribute(Type##Key attribute_key, \
308  ParticleIndex particle) const; \
309  void set_attribute(Type##Key attribute_key, ParticleIndex particle, \
310  Value value); \
311  Value get_attribute(Type##Key attribute_key, ParticleIndex particle); \
312  void add_cache_attribute(Type##Key attribute_key, ParticleIndex particle, \
313  Value value)
314 
315  IMP_MODEL_ATTRIBUTE_METHODS(Float, Float);
316  IMP_MODEL_ATTRIBUTE_METHODS(Int, Int);
317  IMP_MODEL_ATTRIBUTE_METHODS(Floats, Floats);
318  IMP_MODEL_ATTRIBUTE_METHODS(Ints, Ints);
319  IMP_MODEL_ATTRIBUTE_METHODS(String, String);
320  IMP_MODEL_ATTRIBUTE_METHODS(ParticleIndexes, ParticleIndexes);
321  IMP_MODEL_ATTRIBUTE_METHODS(ParticleIndex, ParticleIndex);
322  IMP_MODEL_ATTRIBUTE_METHODS(Object, Object *);
323  IMP_MODEL_ATTRIBUTE_METHODS(WeakObject, Object *);
324  void set_is_optimized(FloatKey, ParticleIndex, bool);
325  void add_to_derivative(FloatKey k, ParticleIndex particle, double v,
326  const DerivativeAccumulator &da);
327 #endif
328 
329  //! Get the particle from an index.
331  IMP_USAGE_CHECK(get_has_particle(p), "Invalid particle requested");
332  return particle_index_[p];
333  }
334 
335  //! Check whether a given particle index exists.
337  if (particle_index_.size() <= get_as_unsigned_int(p)) return false;
338  return particle_index_[p];
339  }
340 
341  //! Get all particle indexes
343 
344  //! Get all the ModelObjects associated with this Model.
345  ModelObjectsTemp get_model_objects() const;
346 
347  //! Remove a particle from the Model.
348  /** The particle will then be inactive and cannot be used for anything
349  and all data stored in the particle is lost.
350  */
351  void remove_particle(ParticleIndex pi);
352 
353  /** \name Storing data in the model
354 
355  One can store data associated with the model. This is used, for example,
356  to keep a central ScoreState to normalize rigid body rotational variables.
357  @{ */
358  //! Store a piece of data in the model referenced by the key.
359  void add_data(ModelKey mk, Object *o);
360  //! Get back some data stored in the model.
361  Object *get_data(ModelKey mk) const;
362  //! Remove data stored in the model.
363  void remove_data(ModelKey mk);
364  //! Check if the model has a certain piece of data attached.
365  bool get_has_data(ModelKey mk) const;
366  /** @} */
367 
368  /** \name Model triggers
369 
370  Triggers can be used to track when to clear and rebuild caches
371  of derived model properties. For example, a Restraint may restrain
372  two particles as a function of the number of chemical bonds between
373  them. To speed up this restraint, the bond graph can be cached; however,
374  this graph needs to be rebuilt if bonds are created or removed. This
375  can be achieved by checking that the model time (see get_age()) of the
376  cache matches the time when the 'bond added/removed' Trigger was last
377  updated (see get_trigger_last_updated()), either when the Restraint is
378  evaluated or in an associated ScoreState.
379 
380  Triggers are intended for events that are rare during a typical
381  optimization. Triggers can be created by any IMP module in either C++
382  or Python by creating a new TriggerKey, much as model attributes
383  are handled. To avoid name collisions, it is recommended to prepend
384  the module and/or class name to the trigger, e.g. "atom.Bond.changed".
385 
386  For an example, see IMP::score_functor::OrientedSoap, which uses
387  a cache built from the molecular hierarchy, which is cleared when the
388  IMP::core::Hierarchy::get_changed_key() trigger is updated.
389 
390  @{ */
391 
392  //! Get the current 'model time'.
393  /** This is a number 1 or more that tracks the 'age' of the model;
394  it is incremented every time before_evaluate() is called.
395  It may wrap (and so should not be assumed to always increase)
396  but will never be 0. */
397  unsigned get_age() { return age_counter_; }
398 
399  //! Get the time when the given trigger was last updated, or 0.
400  /** Return the 'model time' (as given by get_age()) when the given
401  trigger was last updated on this model, or 0 if never. */
403  if (trigger_age_.size() > tk.get_index()) {
404  return trigger_age_[tk.get_index()];
405  } else {
406  return 0;
407  }
408  }
409 
410  //! Update the given trigger
412  if (tk.get_index() >= trigger_age_.size()) {
413  trigger_age_.resize(tk.get_index() + 1, 0);
414  }
415  trigger_age_[tk.get_index()] = age_counter_;
416  }
417  /** @} */
418 
419  //! Get the model age when ModelObject dependencies were last changed, or 0.
420  /** This gives the Model age (see get_age()) when Particles, Restraints,
421  or ScoreStates were last added or removed. It is typically used to
422  help maintain caches that depend on the model's dependency graph. */
423  unsigned get_dependencies_updated() { return dependencies_age_; }
424 
426 
427  public:
428 #if !defined(IMP_DOXYGEN)
429  virtual void do_destroy() IMP_OVERRIDE;
430 #endif
431 };
432 
433 IMPKERNEL_END_NAMESPACE
434 
435 // This is needed for per cpp compilations, a not even sure why
436 // (perhaps cause Model returns ParticleIterator here and there?)
437 // - Feel free to remove if you *really* know what you're doing
438 #include "IMP/Particle.h"
439 
440 #endif /* IMPKERNEL_MODEL_H */
Particle * get_particle(ParticleIndex p) const
Get the particle from an index.
Definition: Model.h:330
Basic types used by IMP.
Used to hold a set of related restraints.
boost::graph DependencyGraph
Directed graph on the interactions between the various objects in the model.
The base class for undecorators.
#define IMP_OBJECT_METHODS(Name)
Define the basic things needed by any Object.
Definition: object_macros.h:25
void add_particle(RMF::FileHandle fh, Particle *hs)
Macros to help in defining tuple classes.
virtual void clear_caches()
Definition: Object.h:227
unsigned get_dependencies_updated()
Get the model age when ModelObject dependencies were last changed, or 0.
Definition: Model.h:423
unsigned get_age()
Get the current 'model time'.
Definition: Model.h:397
bool get_has_particle(ParticleIndex p) const
Check whether a given particle index exists.
Definition: Model.h:336
Macros to define containers of objects.
unsigned get_trigger_last_updated(TriggerKey tk)
Get the time when the given trigger was last updated, or 0.
Definition: Model.h:402
Class for storing model, its restraints, constraints, and particles.
Definition: Model.h:73
Base class for objects in a Model that depend on other objects.
Definition: ModelObject.h:26
virtual void do_destroy()
Definition: Object.h:231
Common base class for heavy weight IMP objects.
Definition: Object.h:106
ParticleIndexes get_particle_indexes(ParticlesTemp const &particles)
ScoreStates maintain invariants in the Model.
Definition: ScoreState.h:54
Implements a vector tied to a particular index of type Index<Tag>.
Definition: Index.h:57
Shared score state.
Base class for objects in a Model that depend on other objects.
Classes to handle individual model particles. (Note that implementation of inline functions is in int...
A nullptr-initialized pointer to an IMP Object.
A shared base class to help in debugging and things.
Represents a scoring function on the model.
double Float
Basic floating-point value (could be float, double...)
Definition: types.h:20
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
Abstract base class for all restraints.
int Int
Basic integer value.
Definition: types.h:35
void set_trigger_updated(TriggerKey tk)
Update the given trigger.
Definition: Model.h:411
std::string String
Basic string value.
Definition: types.h:44
#define IMP_OVERRIDE
Cause a compile error if this method does not override a parent method.
Class for adding derivatives from restraints to the model.