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