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