IMP logo
IMP Reference Guide  develop.907651fe7c,2026/01/28
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-2025 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 "internal/KeyVector.h"
26 #include <IMP/Object.h>
27 #include <IMP/Pointer.h>
28 #include <IMP/internal/IDGenerator.h>
29 #include <boost/unordered_map.hpp>
30 #include <boost/unordered_set.hpp>
31 #include <IMP/tuple_macros.h>
32 #include <boost/iterator/transform_iterator.hpp>
33 #include <boost/iterator/filter_iterator.hpp>
34 #include <cereal/access.hpp>
35 #include <cereal/types/polymorphic.hpp>
36 
37 #include <limits>
38 
39 IMPKERNEL_BEGIN_NAMESPACE
40 
41 class ModelObject;
42 class Undecorator;
43 class Particle;
44 
45 #if !defined(SWIG) && !defined(IMP_DOXYGEN)
46 namespace internal {
47 enum Stage {
48  NOT_EVALUATING,
49  BEFORE_EVALUATING,
50  EVALUATING,
51  AFTER_EVALUATING,
52  COMPUTING_DEPENDENCIES
53 };
54 }
55 #endif
56 
57 class Model;
58 
59 #if !defined(SWIG) && !defined(IMP_DOXYGEN)
60 // This is needed as NodeInfo (below) needs to be showable, and Edges are not
61 inline std::ostream &operator<<(
62  std::ostream &out, const std::set<ModelObject *> &) {
63  out << "(set of ModelObject)";
64  return out;
65 }
66 #endif
67 
68 //! Class for storing model, its restraints, constraints, and particles.
69 /** The Model maintains a standard \imp container for each of Particle,
70  ScoreState and Restraint object types.
71 
72  Each Float attribute has an associated range which reflects the
73  range of values that it is expected to take on during optimization.
74  The optimizer can use these ranges to make the optimization process
75  more efficient. By default, the range estimates are simply the
76  range of values for that attribute in the various particles, but
77  it can be set to another value. For example, an attribute storing
78  an angle could have the range set to (0,PI).
79 
80  The ranges are not enforced; they are just guidelines. In order to
81  enforce ranges, see, for example,
82  IMP::example::ExampleSingletonModifier.
83 
84  \headerfile Model.h "IMP/Model.h"
85  */
86 class IMPKERNELEXPORT Model : public Object
87 #if !defined(SWIG) && !defined(IMP_DOXYGEN)
88  ,
89  public internal::Masks,
90  // The attribute tables provide fast access to
91  // e.g. particle attributes, etc.
92  public internal::FloatAttributeTable,
93  public internal::StringAttributeTable,
94  public internal::IntAttributeTable,
95  public internal::ObjectAttributeTable,
96  public internal::WeakObjectAttributeTable,
97  public internal::IntsAttributeTable,
98  public internal::FloatsAttributeTable,
99  public internal::Vector3DAttributeTable,
100  public internal::ObjectsAttributeTable,
101  public internal::ParticleAttributeTable,
102  public internal::ParticlesAttributeTable,
103  public internal::SparseStringAttributeTable,
104  public internal::SparseIntAttributeTable,
105  public internal::SparseFloatAttributeTable,
106  public internal::SparseParticleAttributeTable
107 #endif
108  {
109  typedef std::set<ModelObject *> Edges;
110  // must be up top
111  // we don't want any liveness checks
112  IMP_NAMED_TUPLE_5(NodeInfo, NodeInfos, Edges, inputs, Edges, input_outputs,
113  Edges, outputs, Edges, readers, Edges, writers, );
114  typedef boost::unordered_map<const ModelObject *, NodeInfo> DependencyGraph;
115  DependencyGraph dependency_graph_;
116  boost::unordered_set<const ModelObject *> no_dependencies_;
117  boost::unordered_map<const ModelObject *, ScoreStatesTemp>
118  required_score_states_;
119 
120  // basic representation
121  boost::unordered_map<FloatKey, FloatRange> ranges_;
122 
123  ParticleIndexes free_particles_;
126 
127  internal::KeyVector<ModelKey, PointerMember<Object> > model_data_;
128 
129 #if !defined(IMP_DOXYGEN)
130  // Map unique ID to Model*
131  class ModelMap {
132  std::map<uint32_t, Model*> map_;
133  internal::IDGenerator id_gen_;
134  public:
135  ModelMap() {}
136  uint32_t add_new_model(Model *m);
137  void add_model_with_id(Model *m, uint32_t id);
138  void remove_model(Model *m);
139  Model *get(uint32_t id) const;
140  };
141 
142  static ModelMap model_map_;
143  uint32_t unique_id_;
144 #endif
145 
146  void do_add_dependencies(const ModelObject *mo);
147  void do_clear_required_score_states(ModelObject *mo);
148  void do_check_required_score_states(const ModelObject *mo) const;
149  void do_check_update_order(const ScoreState *ss) const;
150  void do_check_inputs_and_outputs(const ModelObject *mo) const;
151  void do_check_readers_and_writers(const ModelObject *mo) const;
152  void do_check_not_in_readers_and_writers(const ModelObject *mo) const;
153  void do_clear_dependencies(const ModelObject *mo);
154 
155  // used to track time when triggers are activated
156  unsigned age_counter_;
157  // all triggers
158  Vector<unsigned> trigger_age_;
159  // time when dependencies were last changed, or 0
160  unsigned dependencies_age_;
161  // time when particles or attributes were last removed, or 0
162  unsigned removed_particles_attributes_age_;
163 
164  // allow skipping updating dependencies_age_ for temporary ModelObjects
165  bool dependencies_saved_;
166  unsigned saved_dependencies_age_;
167  // We don't use ModelObjectsTemp here because these objects might get freed
168  // under us, which would cause WeakPointer to raise an exception
169  std::vector<ModelObject *> mos_added_since_save_, mos_removed_since_save_;
170 
171  // cache of restraints that are affected by each moved particle,
172  // used for evaluate_moved() and related functions
173  internal::MovedParticlesRestraintCache moved_particles_restraint_cache_;
174  // cache of particles that are affected by each moved particle
175  internal::MovedParticlesParticleCache moved_particles_particle_cache_;
176  // time when moved_particles_*_cache_ were last updated, or 0
177  unsigned moved_particles_cache_age_;
178 
179  void register_unique_id();
180 
181  friend class cereal::access;
182 
183  template<class Archive> void serialize(Archive &ar,
184  std::uint32_t const version) {
185  ar(cereal::base_class<Object>(this));
186  // We need to get unique_id_ early on read, so that any ModelObjects
187  // that reference it get correctly associated with this model
188  ar(unique_id_);
189  if (std::is_base_of<cereal::detail::InputArchiveBase, Archive>::value) {
190  register_unique_id();
191  }
192  ar(cereal::base_class<internal::FloatAttributeTable>(this),
193  cereal::base_class<internal::StringAttributeTable>(this),
194  cereal::base_class<internal::IntAttributeTable>(this),
195  cereal::base_class<internal::IntsAttributeTable>(this),
196  cereal::base_class<internal::FloatsAttributeTable>(this),
197  cereal::base_class<internal::Vector3DAttributeTable>(this),
198  cereal::base_class<internal::ParticleAttributeTable>(this),
199  cereal::base_class<internal::ParticlesAttributeTable>(this),
200  cereal::base_class<internal::SparseStringAttributeTable>(this),
201  cereal::base_class<internal::SparseIntAttributeTable>(this),
202  cereal::base_class<internal::SparseFloatAttributeTable>(this),
203  cereal::base_class<internal::SparseParticleAttributeTable>(this));
204 
205  if (std::is_base_of<cereal::detail::InputArchiveBase, Archive>::value) {
206  size_t count;
207  free_particles_.clear();
208  ar(count);
209  particle_index_.clear();
210  while(count-- > 0) {
211  std::string name;
212  ar(name);
213  add_particle(name);
214  }
215  ParticleIndexes to_free;
216  ar(to_free);
217  for (auto pi : to_free) {
218  remove_particle(pi);
219  }
220  } else {
221  size_t count = particle_index_.size();
222  ar(count);
223  for (size_t i = 0; i < count; ++i) {
224  std::string name;
225  if (get_has_particle(ParticleIndex(i))) {
226  name = get_particle_name(ParticleIndex(i));
227  }
228  ar(name);
229  }
230  ar(free_particles_);
231  }
232 
233  // Need particle info before anything that might refer to a particle
234  // (ScoreState, or arbitrary Object)
235  ar(cereal::base_class<internal::ObjectAttributeTable>(this),
236  cereal::base_class<internal::ObjectsAttributeTable>(this),
237  cereal::base_class<internal::WeakObjectAttributeTable>(this),
238  model_data_, mutable_access_score_states());
239 
240  if (std::is_base_of<cereal::detail::InputArchiveBase, Archive>::value) {
241  // clear caches
242  age_counter_ = 1;
243  trigger_age_.clear();
244  dependencies_age_ = 0;
245  removed_particles_attributes_age_ = 0;
246  saved_dependencies_age_ = 0;
247  dependencies_saved_ = false;
248  moved_particles_cache_age_ = 0;
249  }
250  }
251 
252  // update model age (can never be zero, even if it wraps)
253  void increase_age() {
254  age_counter_++;
255  if (age_counter_ == 0) {
256  age_counter_ = 1;
257  }
258  }
259 
260  template <class MOType, class MOVector>
261  void do_get_dependent(ModelObject *mo, MOVector &ret) {
262  const auto &node = dependency_graph_.find(mo);
264  "Object " << mo->get_name()
265  << " does not have dependencies.");
266  IMP_INTERNAL_CHECK(node != dependency_graph_.end(),
267  "Node not in dependency_graph.");
268  MOType *r = dynamic_cast<MOType *>(mo);
269  if (r) {
270  ret.push_back(r);
271  }
272  for (ModelObject *cur : node->second.get_outputs()) {
273  do_get_dependent<MOType, MOVector>(cur, ret);
274  }
275  for (ModelObject *cur : node->second.get_readers()) {
276  do_get_dependent<MOType, MOVector>(cur, ret);
277  }
278  }
279 
280 #if !defined(IMP_DOXYGEN) && !defined(SWIG)
281  // things the evaluate template functions need, can't be bothered with friends
282  public:
283 #endif
284  // check more things on the first call
285  bool first_call_;
286  // the stage of evaluation
287  internal::Stage cur_stage_;
288 
289  //! Get all Restraints that depend on the given particle
290  const std::set<Restraint *> &get_dependent_restraints(ParticleIndex pi) {
291  return moved_particles_restraint_cache_.get_dependent_restraints(pi);
292  }
293 
294  //! Get all particles that depend on the given particle
295  const ParticleIndexes &get_dependent_particles(ParticleIndex pi) {
296  return moved_particles_particle_cache_.get_dependent_particles(pi);
297  }
298 
299  ModelObjectsTemp get_dependency_graph_inputs(const ModelObject *mo) const;
300  ModelObjectsTemp get_dependency_graph_outputs(const ModelObject *mo) const;
301  bool do_get_has_dependencies(const ModelObject *mo) const {
302  return no_dependencies_.find(mo) == no_dependencies_.end();
303  }
304  void do_set_has_dependencies(const ModelObject *mo, bool tf);
305  void do_set_has_all_dependencies(bool tf);
306 
307  void validate_computed_derivatives() const {}
308  void set_has_all_dependencies(bool tf);
309  bool get_has_all_dependencies() const;
310  void check_dependency_invariants() const;
311  void check_dependency_invariants(const ModelObject *mo) const;
312  ScoreStatesTemp get_ancestor_score_states(const ModelObject *mo) const;
313  ScoreStatesTemp get_descendent_score_states(const ModelObject *mo) const;
314 
315  void before_evaluate(const ScoreStatesTemp &states);
316  void after_evaluate(const ScoreStatesTemp &states, bool calc_derivs);
317 
318  internal::Stage get_stage() const { return cur_stage_; }
319  ParticleIndex add_particle_internal(Particle *p);
320  static void do_remove_score_state(ScoreState *obj);
321  void do_add_score_state(ScoreState *obj);
322  void do_remove_particle(ParticleIndex pi);
323  bool do_get_has_required_score_states(const ModelObject *mo) const;
324  void do_set_has_required_score_states(ModelObject *mo, bool tf);
325  const ScoreStatesTemp &do_get_required_score_states(const ModelObject *mo)
326  const {
327  IMP_USAGE_CHECK(do_get_has_required_score_states(mo),
328  "Doesn't have score states");
329  return required_score_states_.find(mo)->second;
330  }
331  void do_add_model_object(ModelObject *mo);
332  void do_remove_model_object(ModelObject *mo);
333 
334  public:
335  //! Construct an empty model
336  Model(std::string name = "Model %1%");
337 
338  public:
339 #if !defined(SWIG) && !defined(IMP_DOXYGEN)
340  IMP_MODEL_IMPORT(internal::FloatAttributeTable);
341  IMP_MODEL_IMPORT(internal::StringAttributeTable);
342  IMP_MODEL_IMPORT(internal::IntAttributeTable);
343  IMP_MODEL_IMPORT(internal::ObjectAttributeTable);
344  IMP_MODEL_IMPORT(internal::WeakObjectAttributeTable);
345  IMP_MODEL_IMPORT(internal::IntsAttributeTable);
346  IMP_MODEL_IMPORT(internal::FloatsAttributeTable);
347  IMP_MODEL_IMPORT(internal::Vector3DAttributeTable);
348  IMP_MODEL_IMPORT(internal::ObjectsAttributeTable);
349  IMP_MODEL_IMPORT(internal::ParticleAttributeTable);
350  IMP_MODEL_IMPORT(internal::ParticlesAttributeTable);
351  IMP_MODEL_SPARSE_IMPORT(internal::SparseStringAttributeTable);
352  IMP_MODEL_SPARSE_IMPORT(internal::SparseIntAttributeTable);
353  IMP_MODEL_SPARSE_IMPORT(internal::SparseFloatAttributeTable);
354  IMP_MODEL_SPARSE_IMPORT(internal::SparseParticleAttributeTable);
355 #endif
356  //! Clear all the cache attributes of a given particle.
357  void clear_particle_caches(ParticleIndex pi);
358 
359  //! Add particle to the model
360  ParticleIndex add_particle(std::string name);
361 
362  //! Get the name of a particle
363  std::string get_particle_name(ParticleIndex pi);
364 
365  //! Add the passed Undecorator to the particle.
366  void add_undecorator(ParticleIndex pi, Undecorator *d);
367 
368 #if !defined(IMP_DOXYGEN)
369  RestraintsTemp get_dependent_restraints_uncached(ParticleIndex pi);
370 
371  ParticlesTemp get_dependent_particles_uncached(ParticleIndex pi);
372 
373  ScoreStatesTemp get_dependent_score_states_uncached(ParticleIndex pi);
374 #endif
375 
376  /** @name States
377 
378  ScoreStates maintain invariants in the Model (see ScoreState
379  for more information.)
380 
381  ScoreStates do not need to be explicitly added to the Model, but they
382  can be if desired in order to keep them alive as long as the model is
383  alive.
384 
385  \advancedmethod
386  */
387  /**@{*/
388  IMP_LIST_ACTION(public, ScoreState, ScoreStates, score_state, score_states,
389  ScoreState *, ScoreStates, do_add_score_state(obj), {},
390  do_remove_score_state(obj));
391  /**@}*/
392 
393  public:
394 #ifndef SWIG
395  using Object::clear_caches;
396 #endif
397 
398  //! Sometimes it is useful to be able to make sure the model is up to date
399  /** This method updates all the state but does not necessarily compute the
400  score. Use this to make sure that your containers and rigid bodies are
401  up to date.
402  */
403  void update();
404 
405  //! Determine and return the correct order to evaluate ScoreStates in
406  /** ScoreStates are not evaluated in the order in which they were added
407  to the Model; instead, the Model's dependency graph is used to ensure
408  that a ScoreState that takes particle x as an input is always
409  evaluated after a state that modifies particle x on output.
410  This method determines and returns the correct order. This is also
411  cached in the ScoreStates themselves; see IMP::get_update_order.
412  */
413  ScoreStatesTemp get_ordered_score_states();
414 
415 #ifdef IMP_DOXYGEN
416  /** \name Accessing attributes
417  \anchor model_attributes
418  All the attribute data associated with each Particle are stored in the
419  Model. For each type of attribute, there are the methods detailed below
420  (where, eg, TypeKey is FloatKey or StringKey)
421  @{
422  */
423  //! add particle attribute with the specified key and initial value
424  /** \pre get_has_attribute(attribute_key, particle) is false*/
425  void add_attribute(TypeKey attribute_key, ParticleIndex particle, Type value);
426 
427  //! remove particle attribute with the specified key
428  /** \pre get_has_attribute(attribute_key, particle) is true*/
429  void remove_attribute(TypeKey attribute_key, ParticleIndex particle);
430 
431  //! return true if particle has attribute with the specified key
432  bool get_has_attribute(TypeKey attribute_key, ParticleIndex particle) const;
433 
434  //! set the value of particle attribute with the specified key
435  /** \pre get_has_attribute(attribute_key, particle) is true*/
436  void set_attribute(TypeKey attribute_key, ParticleIndex particle, Type value);
437 
438  //! get the value of the particle attribute with the specified key
439  /** \pre get_has_attribute(attribute_key, particle) is true*/
440  Type get_attribute(TypeKey attribute_key, ParticleIndex particle);
441 
442  /** Cache attributes, unlike normal attributes, can be added during
443  evaluation. They are also cleared by the clear_cache_attributes() method.
444  Cache attributes should be used when one is adding data to a particle
445  to aid scoring (eg cache the rigid body collision acceleration structure).
446 
447  When some pertinent aspect of the particle changes, the clear method
448  should
449  be called (yes, this is a bit vague). Examples where it should be cleared
450  include changing the set of members of a core::RigidBody or their
451  coordinates, changing the members of an atom::Hierarchy.
452  */
453  void add_cache_attribute(TypeKey attribute_key, ParticleIndex particle,
454  Type value);
455 
456  //! Optimized attributes are the parameters of the model that are
457  //! allowed to be modified by samplers and optimizers
458  void set_is_optimized(TypeKey attribute_key, ParticleIndex particle,
459  bool true_or_false);
460 /** @} */
461 #endif
462 
463 #ifdef SWIG
464 #define IMP_MODEL_ATTRIBUTE_METHODS(Type, Value) \
465  void add_attribute(Type##Key attribute_key, ParticleIndex particle, \
466  Value value); \
467  void remove_attribute(Type##Key attribute_key, ParticleIndex particle); \
468  bool get_has_attribute(Type##Key attribute_key, \
469  ParticleIndex particle) const; \
470  void set_attribute(Type##Key attribute_key, ParticleIndex particle, \
471  Value value); \
472  Value get_attribute(Type##Key attribute_key, ParticleIndex particle); \
473  void add_cache_attribute(Type##Key attribute_key, ParticleIndex particle, \
474  Value value)
475 
476 #define IMP_MODEL_SPARSE_ATTRIBUTE_METHODS(Type, Value) \
477  void add_attribute(Type##Key attribute_key, ParticleIndex particle, \
478  Value value); \
479  void remove_attribute(Type##Key attribute_key, ParticleIndex particle); \
480  bool get_has_attribute(Type##Key attribute_key, \
481  ParticleIndex particle) const; \
482  void set_attribute(Type##Key attribute_key, ParticleIndex particle, \
483  Value value); \
484  Value get_attribute(Type##Key attribute_key, ParticleIndex particle)
485 
486  IMP_MODEL_ATTRIBUTE_METHODS(Float, Float);
487  IMP_MODEL_ATTRIBUTE_METHODS(Int, Int);
488  IMP_MODEL_ATTRIBUTE_METHODS(Floats, Floats);
489  IMP_MODEL_ATTRIBUTE_METHODS(Vector3D, IMP::algebra::Vector3D);
490  IMP_MODEL_ATTRIBUTE_METHODS(Ints, Ints);
491  IMP_MODEL_ATTRIBUTE_METHODS(String, String);
492  IMP_MODEL_ATTRIBUTE_METHODS(ParticleIndexes, ParticleIndexes);
493  IMP_MODEL_ATTRIBUTE_METHODS(ParticleIndex, ParticleIndex);
494  IMP_MODEL_ATTRIBUTE_METHODS(Object, Object *);
495  IMP_MODEL_ATTRIBUTE_METHODS(WeakObject, Object *);
496  IMP_MODEL_SPARSE_ATTRIBUTE_METHODS(SparseString, String);
497  IMP_MODEL_SPARSE_ATTRIBUTE_METHODS(SparseInt, Int);
498  IMP_MODEL_SPARSE_ATTRIBUTE_METHODS(SparseFloat, Float);
499  IMP_MODEL_SPARSE_ATTRIBUTE_METHODS(SparseParticleIndex, ParticleIndex);
500  void set_is_optimized(FloatKey, ParticleIndex, bool);
501  void add_to_derivative(FloatKey k, ParticleIndex particle, double v,
502  const DerivativeAccumulator &da);
503 #endif
504 
505  //! Get the particle from an index.
507  IMP_USAGE_CHECK(get_has_particle(p), "Invalid particle requested");
508  return particle_index_[p];
509  }
510 
511  //! Check whether a given particle index exists.
513  if (particle_index_.size() <= get_as_unsigned_int(p)) return false;
514  return particle_index_[p];
515  }
516 
517  //! Get all particle indexes
519 
520  //! Get all the ModelObjects associated with this Model.
521  ModelObjectsTemp get_model_objects() const;
522 
523  //! Remove a particle from the Model.
524  /** The particle will then be inactive and cannot be used for anything
525  and all data stored in the particle is lost.
526  */
527  void remove_particle(ParticleIndex pi);
528 
529  /** \name Storing data in the model
530 
531  One can store data associated with the model. This is used, for example,
532  to keep a central ScoreState to normalize rigid body rotational variables.
533  @{ */
534  //! Store a piece of data in the model referenced by the key.
535  void add_data(ModelKey mk, Object *o);
536  //! Get back some data stored in the model.
537  Object *get_data(ModelKey mk) const;
538  //! Remove data stored in the model.
539  void remove_data(ModelKey mk);
540  //! Check if the model has a certain piece of data attached.
541  bool get_has_data(ModelKey mk) const;
542  /** @} */
543 
544  /** \name Model triggers
545 
546  Triggers can be used to track when to clear and rebuild caches
547  of derived model properties. For example, a Restraint may restrain
548  two particles as a function of the number of chemical bonds between
549  them. To speed up this restraint, the bond graph can be cached; however,
550  this graph needs to be rebuilt if bonds are created or removed. This
551  can be achieved by checking that the model time (see get_age()) of the
552  cache matches the time when the 'bond added/removed' Trigger was last
553  updated (see get_trigger_last_updated()), either when the Restraint is
554  evaluated or in an associated ScoreState.
555 
556  Triggers are intended for events that are rare during a typical
557  optimization. Triggers can be created by any IMP module in either C++
558  or Python by creating a new TriggerKey, much as model attributes
559  are handled. To avoid name collisions, it is recommended to prepend
560  the module and/or class name to the trigger, e.g. "atom.Bond.changed".
561 
562  For an example, see IMP::score_functor::OrientedSoap, which uses
563  a cache built from the molecular hierarchy, which is cleared when the
564  IMP::core::Hierarchy::get_changed_key() trigger is updated.
565 
566  @{ */
567 
568  //! Get the current 'model time'.
569  /** This is a number 1 or more that tracks the 'age' of the model;
570  it is incremented every time before_evaluate() is called.
571  It may wrap (and so should not be assumed to always increase)
572  but will never be 0. */
573  unsigned get_age() { return age_counter_; }
574 
575  //! Get the time when the given trigger was last updated, or 0.
576  /** Return the 'model time' (as given by get_age()) when the given
577  trigger was last updated on this model, or 0 if never. */
579  if (trigger_age_.size() > tk.get_index()) {
580  return trigger_age_[tk.get_index()];
581  } else {
582  return 0;
583  }
584  }
585 
586  //! Update the given trigger
588  if (tk.get_index() >= trigger_age_.size()) {
589  trigger_age_.resize(tk.get_index() + 1, 0);
590  }
591  trigger_age_[tk.get_index()] = age_counter_;
592  }
593  /** @} */
594 
595  //! Get the model age when ModelObject dependencies were last changed, or 0.
596  /** This gives the Model age (see get_age()) when Particles, Restraints,
597  or ScoreStates were last added or removed. It is typically used to
598  help maintain caches that depend on the model's dependency graph. */
599  unsigned get_dependencies_updated() { return dependencies_age_; }
600 
601  //! Get the model age when particles or attributes were last removed, or 0.
602  /** This gives the Model age (see get_age()) when any particle or attribute
603  was last removed. It is typically used by callers that rely on certain
604  particles or decorators being present. */
606  return removed_particles_attributes_age_;
607  }
608 
609  //! Mark a 'restore point' for ModelObject dependencies.
610  /** \see restore_dependencies() */
612  dependencies_saved_ = true;
613  saved_dependencies_age_ = dependencies_age_;
615  mos_added_since_save_.clear();
616  mos_removed_since_save_.clear();
617  }
618  }
619 
620  //! Restore ModelObject dependencies to previous restore point.
621  /** This method, when paired with save_dependencies(), can be used to
622  avoid triggering a model dependency update due to a temporary change
623  in the model dependency graph, for example due to adding a temporary
624  restraint, evaluating it, then removing that same restraint. It should
625  only be called in cases where it is known that the dependency graph
626  is the same as when save_dependencies() was called (this is only checked
627  in debug mode). Save/restore call pairs cannot be nested, although it
628  is OK to skip the call to restore_dependencies(), e.g. if an exception
629  occurs.
630 
631  \see get_dependencies_updated()
632  \see save_dependencies()
633  */
635  if (dependencies_saved_) {
636  dependencies_saved_ = false;
637  dependencies_age_ = saved_dependencies_age_;
639  // Need to sort pointers since we may not add/remove in the same order
640  std::sort(mos_added_since_save_.begin(), mos_added_since_save_.end());
641  std::sort(mos_removed_since_save_.begin(),
642  mos_removed_since_save_.end());
643  IMP_INTERNAL_CHECK(mos_added_since_save_ == mos_removed_since_save_,
644  "ModelObjects added do not match those removed");
645  }
646  }
647  }
648 
649  //! Get an upper bound on the number of particles in the Model.
650  /** This value is guaranteed to be at least the number of particles in
651  the model (there may be fewer particles if any have been removed)
652  and every ParticleIndex will be smaller than this value. */
653  unsigned get_particles_size() const { return particle_index_.size(); }
654 
655  //! Get the unique ID of this Model.
656  /** When multiple Models exist simultaneously, each has a different unique ID.
657  */
658  uint32_t get_unique_id() const {
659  return unique_id_;
660  }
661 
662  //! Return the Model with the given unique ID.
663  /** If no Model with this ID exists, nullptr is returned. */
664  static Model* get_by_unique_id(uint32_t id) {
665  return model_map_.get(id);
666  }
667 
669 
670  public:
671 #if !defined(IMP_DOXYGEN)
672  virtual void do_destroy() override;
673 #endif
674 };
675 
676 IMPKERNEL_END_NAMESPACE
677 
678 CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES(
679  IMP::Model, cereal::specialization::member_serialize);
680 
681 CEREAL_CLASS_VERSION(IMP::Model, 1);
682 
683 // This is needed for per cpp compilations, a not even sure why
684 // (perhaps cause Model returns ParticleIterator here and there?)
685 // - Feel free to remove if you *really* know what you're doing
686 #include "IMP/Particle.h"
687 
688 #endif /* IMPKERNEL_MODEL_H */
Particle * get_particle(ParticleIndex p) const
Get the particle from an index.
Definition: Model.h:506
Basic types used by IMP.
#define IMP_IF_CHECK(level)
Execute the code block if a certain level checks are on.
Definition: check_macros.h:104
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 restore_dependencies()
Restore ModelObject dependencies to previous restore point.
Definition: Model.h:634
Index< ParticleIndexTag > ParticleIndex
Definition: base_types.h:182
void add_particle(RMF::FileHandle fh, Particle *hs)
Macros to help in defining tuple classes.
virtual void clear_caches()
Definition: Object.h:270
unsigned get_dependencies_updated()
Get the model age when ModelObject dependencies were last changed, or 0.
Definition: Model.h:599
A more IMP-like version of the std::vector.
Definition: Vector.h:50
unsigned get_particles_size() const
Get an upper bound on the number of particles in the Model.
Definition: Model.h:653
unsigned get_age()
Get the current 'model time'.
Definition: Model.h:573
bool get_has_particle(ParticleIndex p) const
Check whether a given particle index exists.
Definition: Model.h:512
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:578
#define IMP_INTERNAL_CHECK(expr, message)
An assertion to check for internal errors in IMP. An IMP::ErrorException will be thrown.
Definition: check_macros.h:139
Class for storing model, its restraints, constraints, and particles.
Definition: Model.h:86
Base class for objects in a Model that depend on other objects.
Definition: ModelObject.h:28
virtual void do_destroy()
Definition: Object.h:274
Common base class for heavy weight IMP objects.
Definition: Object.h:111
ParticleIndexes get_particle_indexes(ParticlesTemp const &particles)
ScoreStates maintain invariants in the Model.
Definition: ScoreState.h:56
static Model * get_by_unique_id(uint32_t id)
Return the Model with the given unique ID.
Definition: Model.h:664
uint32_t get_unique_id() const
Get the unique ID of this Model.
Definition: Model.h:658
Implements a vector tied to a particular index of type Index<Tag>.
Definition: Index.h:90
unsigned get_removed_particles_attributes_age()
Get the model age when particles or attributes were last removed, or 0.
Definition: Model.h:605
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.
void save_dependencies()
Mark a 'restore point' for ModelObject dependencies.
Definition: Model.h:611
A shared base class to help in debugging and things.
Represents a scoring function on the model.
VectorD< 3 > Vector3D
Definition: VectorD.h:408
double Float
Basic floating-point value (could be float, double...)
Definition: types.h:19
Class to handle individual particles of a Model object.
Definition: Particle.h:45
bool get_has_dependencies() const
Return whether this object has dependencies computed.
#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:34
void set_trigger_updated(TriggerKey tk)
Update the given trigger.
Definition: Model.h:587
std::string String
Basic string value.
Definition: types.h:43
Class for adding derivatives from restraints to the model.