IMP logo
IMP Reference Guide  develop.ef7183ce54,2026/10/07
The Integrative Modeling Platform
Restraint.h
Go to the documentation of this file.
1 /**
2  * \file IMP/Restraint.h
3  * \brief Abstract base class for all restraints.
4  *
5  * Copyright 2007-2026 IMP Inventors. All rights reserved.
6  *
7  */
8 
9 #ifndef IMPKERNEL_RESTRAINT_H
10 #define IMPKERNEL_RESTRAINT_H
11 
12 #include <IMP/kernel_config.h>
13 #include "ModelObject.h"
14 #include "ScoreAccumulator.h"
15 #include "DerivativeAccumulator.h"
16 #include "constants.h"
17 #include "base_types.h"
18 #include <IMP/InputAdaptor.h>
19 #include <IMP/deprecation_macros.h>
20 #include <IMP/RestraintInfo.h>
21 #include <type_traits>
22 #include <cereal/access.hpp>
23 #include <cereal/types/base_class.hpp>
24 
25 IMPKERNEL_BEGIN_NAMESPACE
26 class DerivativeAccumulator;
27 
28 //! A restraint is a term in an \imp ScoringFunction.
29 /**
30  To implement a new restraint, just implement the two methods:
31  - IMP::Restraint::unprotected_evaluate()
32  - IMP::ModelObject::do_get_inputs();
33  and use the macro to handle IMP::Object
34  - IMP_OBJECT_METHODS()
35 
36  \note When logging is VERBOSE, restraints should print enough information
37  in evaluate to reproduce the entire flow of data in evaluate. When
38  logging is TERSE the restraint should print out only a constant number of
39  lines per evaluate call.
40 
41  \note Physical restraints should use the units of kcal/mol for restraint
42  values and kcal/mol/A for derivatives.
43 
44  When implementing an expensive restraint it makes sense to support early
45  abort of evaluation if the user is only interested in good scores or scores
46  below a threshold. To do this, look at the fields of the ScoreAccumulator
47  object such as
48  - ScoreAccumulator::get_is_evaluate_if_below(),
49  - ScoreAccumulator::get_is_evaluate_if_good()
50  - ScoreAccumulator::get_maximum()
51 
52  \headerfile Restraint.h "IMP/Restraint.h"
53 
54  See IMP::example::ExampleRestraint for an example.
55  */
56 class IMPKERNELEXPORT Restraint : public ModelObject {
57  public:
58  //! Create a restraint and register it with the model.
59  Restraint(Model *m, std::string name);
60 
61  //! Default constructor.
62  /** Default-constructed restraints cannot be evaluated. */
63  Restraint();
64 
65  /** Compute and return the current score for the restraint.
66  */
67  double get_score() const;
68 
69  /** \name Evaluation convenience methods
70  These are convenience methods to get the score of just this restraint;
71  each just calls the equivalent method in the ScoringFunction class.
72  @{
73  */
74 
75  //! \see ScoringFunction::evaluate
76  double evaluate(bool calc_derivs) const;
77 
78  //! \see ScoringFunction::evaluate_moved
79  double evaluate_moved(bool calc_derivs,
80  const ParticleIndexes &moved_pis,
81  const ParticleIndexes &reset_pis) const;
82 
83  //! \see ScoringFunction::evaluate_moved_if_below
84  double evaluate_moved_if_below(bool calc_derivatives,
85  const ParticleIndexes &moved_pis,
86  const ParticleIndexes &reset_pis, double max) const;
87 
88  //! \see ScoringFunction::evaluate_moved_if_good
89  double evaluate_moved_if_good(bool calc_derivatives,
90  const ParticleIndexes &moved_pis,
91  const ParticleIndexes &reset_pis) const;
92 
93  //! \see ScoringFunction::evaluate_if_good
94  double evaluate_if_good(bool calc_derivatives) const;
95 
96  //! \see ScoringFunction::evaluate_if_below
97  double evaluate_if_below(bool calc_derivatives, double max) const;
98 /** @} */
99 
100  /** \name Evaluation implementation
101  These methods are called in order to perform the actual restraint
102  scoring. The restraints should assume that all appropriate ScoreState
103  objects have been updated and so that the input particles and containers
104  are up to date. The returned score should be the unweighted score.
105 
106  \note These functions probably should be called \c do_evaluate, but
107  were grandfathered in.
108  \note Although the returned score is unweighted, the DerivativeAccumulator
109  passed in should be properly weighted.
110  @{
111  */
112  //! Return the unweighted score for the restraint.
113  virtual double unprotected_evaluate(DerivativeAccumulator *da) const;
114 
115  //! Return the unweighted score, taking moving particles into account.
116  /** By default this just calls regular unprotected_evaluate(), but
117  may be overridden by restraints to be more efficient, e.g. by
118  skipping terms that involve unchanged particles.
119 
120  This function is intended to be called in a loop within an
121  optimizer that moves only a subset of particles each time,
122  e.g. Monte Carlo. Before the first call (where the state of the model
123  is unknown) you should call clear_moved_cache() otherwise out of date
124  information may be used.
125 
126  \param da Object to accumulate derivatives, or nullptr.
127  \param moved_pis Particles that have moved since the last
128  scoring function evaluation.
129  \param reset_pis Particles that have moved, but back to the
130  positions they had at the last-but-one evaluation
131  (e.g. due to a rejected Monte Carlo move).
132 
133  \return Current score.
134  */
136  DerivativeAccumulator *da, const ParticleIndexes &moved_pis,
137  const ParticleIndexes &reset_pis) const {
138  IMP_UNUSED(moved_pis);
139  IMP_UNUSED(reset_pis);
140  return unprotected_evaluate(da);
141  }
142 
143  //! Clear any caches used by unprotected_evaluate_moved().
144  virtual void clear_moved_cache() {
145  last_score_ = last_last_score_ = BAD_SCORE;
146  }
147 
148  /** The function calling this will treat any score >= get_maximum_score
149  as bad and so can return early as soon as such a situation is found.*/
151  double max) const {
152  IMP_UNUSED(max);
153  return unprotected_evaluate(da);
154  }
155 
156  //! The function calling this will treat any score >= max as bad.
158  double max) const {
159  IMP_UNUSED(max);
160  return unprotected_evaluate(da);
161  }
162 
163  virtual double unprotected_evaluate_moved_if_below(
164  DerivativeAccumulator *da, const ParticleIndexes &moved_pis,
165  const ParticleIndexes &reset_pis, double max) const {
166  IMP_UNUSED(max);
167  return unprotected_evaluate_moved(da, moved_pis, reset_pis);
168  }
169 
170  virtual double unprotected_evaluate_moved_if_good(
171  DerivativeAccumulator *da, const ParticleIndexes &moved_pis,
172  const ParticleIndexes &reset_pis, double max) const {
173  IMP_UNUSED(max);
174  return unprotected_evaluate_moved(da, moved_pis, reset_pis);
175  }
176 
177 /** @} */
178 
179  //! \return static key:value information about this restraint, or null.
180  /** \return a set of key:value pairs that contain static information
181  about this restraint (i.e. information that doesn't change during
182  a sampling run, such as the type of restraint or filename from
183  which information is read). Usually this includes a "type" key with
184  the fully qualified classname (e.g. IMP.mymodule.MyRestraint).
185  If no such information is available, a null pointer is returned.
186  This information is used when writing restraints to files, e.g. by
187  the IMP.rmf module.
188  */
189  virtual RestraintInfo *get_static_info() const {
190  return nullptr;
191  }
192 
193  //! \return dynamic key:value information about this restraint, or null.
194  /** \return a set of key:value pairs that contain dynamic information
195  about this restraint (i.e. information that changes during a sampling
196  run, such as scores or cross correlations).
197  If no such information is available, a null pointer is returned.
198  This information is used when writing restraints to files, e.g. by
199  the IMP.rmf module.
200  */
201  virtual RestraintInfo *get_dynamic_info() const {
202  return nullptr;
203  }
204 
205 #ifndef IMP_DOXYGEN
206  //! Perform the actual restraint scoring.
207  /** The restraints should assume that all appropriate ScoreState
208  objects have been updated and so that the input particles and containers
209  are up to date. The returned score should be the unweighted score.
210  */
211  void add_score_and_derivatives(ScoreAccumulator sa) const;
212 
213  void add_score_and_derivatives_moved(
214  ScoreAccumulator sa, const ParticleIndexes &moved_pis,
215  const ParticleIndexes &reset_pis) const;
216 #endif
217 
218  //! Decompose this restraint into constituent terms
219  /** Given the set of input particles, decompose the restraint into parts
220  that are as simple as possible. For many restraints, the simplest
221  part is simply the restraint itself.
222 
223  If a restraint can be decomposed, it should return a
224  RestraintSet so that the maximum score and weight can be
225  passed properly.
226 
227  The restraints returned have had set_model() called and so can
228  be evaluated.
229  */
231 
232  //! Decompose this restraint into constituent terms for the current conf
233  /** \return a decomposition that is value for the current conformation,
234  but will not necessarily be valid if any of the particles are
235  changed. This is the same as create_decomposition() for
236  non-conditional restraints.
237 
238  The restraints returned have had set_model() called and so can be
239  evaluated.
240  */
241  Restraint *create_current_decomposition() const;
242 
243  /** \name Weights
244  Each restraint's contribution to the model score is weighted. The
245  total weight for the restraint is the some over all the paths containing
246  it. That is, if a restraint is in a RestraintSet with weight .5 and
247  another with weight 2, and the restraint itself has weight 3, then the
248  total weight of the restraint is \f$.5 \cdot 3 + 2 \cdot 3 = 7.5 \f$.
249  @{
250  */
251  void set_weight(Float weight);
252  Float get_weight() const { return weight_; }
253  /** @} */
254  /** \name Filtering
255  We are typically only interested in "good" conformations of
256  the model. These are described by specifying maximum scores
257  per restraint (or RestraintSet). Samplers, optimizers
258  etc are free to ignore configurations they encounter which
259  go outside these bounds.
260 
261  \note The maximum score is for the unweighted restraint.
262  That is, the restraint evaluation is bad if the value
263  is greater than the maximum score divided by the weight.
264  @{
265  */
266  double get_maximum_score() const { return max_; }
267  void set_maximum_score(double s);
268 /** @} */
269 
270 //! Create a scoring function with only this restraint.
271 /** \note This method cannot be implemented in Python due to memory
272  management issues (and the question of why you would ever
273  want to).
274  */
275 #ifndef SWIG
276  virtual
277 #endif
278  ScoringFunction *
279  create_scoring_function(double weight = 1.0,
280  double max = NO_MAX) const;
281 #if !defined(IMP_DOXYGEN)
282  void set_last_score(double s) const {
283  last_last_score_ = last_score_;
284  last_score_ = s;
285  }
286  void set_last_last_score(double s) const { last_last_score_ = s; }
287 #endif
288 
289  /** Return the (unweighted) score for this restraint last time it was
290  evaluated.
291  \note If some sort of special evaluation (eg Model::evaluate_if_good())
292  was the last call, the score, if larger than the max, is not accurate.
293  */
294  virtual double get_last_score() const { return last_score_; }
295 
296  //! Get the unweighted score from the last-but-one time it was evaluated
297  /** \see get_last_score
298  */
299  double get_last_last_score() const { return last_last_score_; }
300 
301  //! Return whether this restraint wraps a number of other restraints
302  bool get_is_aggregate() const { return is_aggregate_; }
303 
304  //! Return whether this restraint provides custom logic for reset moves
305  bool get_is_custom_reset() const { return is_custom_reset_; }
306 
307  /** Return whether this restraint violated its maximum last time it was
308  evaluated.
309  */
310  bool get_was_good() const { return get_last_score() < max_; }
311 
313 
314  protected:
315  /** A Restraint should override this if it wants to decompose itself
316  for domino and other purposes. The returned restraints will be made
317  into a RestraintSet if needed, with suitable weight and maximum score.
318  */
320  return Restraints(1, const_cast<Restraint *>(this));
321  }
322  /** A Restraint should override this if it wants to decompose itself
323  for display and other purposes. The returned restraints will be made
324  into a RestraintSet if needed, with suitable weight and maximum score.
325 
326  The returned restraints should be only the non-zero terms and should
327  have their last scores set appropriately.
328  */
330  return do_create_decomposition();
331  }
332 
333  virtual void do_add_score_and_derivatives(ScoreAccumulator sa) const;
334 
335  virtual void do_add_score_and_derivatives_moved(
336  ScoreAccumulator sa, const ParticleIndexes &moved_pis,
337  const ParticleIndexes &reset_pis) const;
338 
339  /** No outputs. */
340  ModelObjectsTemp do_get_outputs() const override {
341  return ModelObjectsTemp();
342  }
343 
344  protected:
345  bool is_aggregate_, is_custom_reset_;
346 
347  private:
348  ScoringFunction *create_internal_scoring_function() const;
349 
350  double weight_;
351  double max_;
352  mutable double last_score_;
353  mutable double last_last_score_;
354  // cannot be released outside the class
355  mutable Pointer<ScoringFunction> cached_internal_scoring_function_;
356 
357  friend class cereal::access;
358 
359  template<class Archive> void serialize(Archive &ar) {
360  ar(cereal::base_class<ModelObject>(this));
361  ar(weight_, max_);
362  // Clear caches
363  if (std::is_base_of<cereal::detail::InputArchiveBase, Archive>::value) {
364  last_score_ = last_last_score_ = BAD_SCORE;
365  cached_internal_scoring_function_ = nullptr;
366  }
367  // Note that flags (is_aggregate_, is_custom_reset_) are not read or
368  // written here, as they are only ever set in the constructor
369  }
370 
371 };
372 
373 //! Provide a consistent interface for things that take Restraints as arguments.
374 /**
375  \note Passing an empty list of restraints should be supported, but problems
376  could arise, so be alert (the problems would not be subtle).
377 */
378 class IMPKERNELEXPORT RestraintsAdaptor :
379 #if !defined(SWIG) && !defined(IMP_DOXYGEN)
380  public Restraints
381 #else
382  public InputAdaptor
383 #endif
384  {
385  static Restraint *get(Restraint *r) { return r; }
386 
387  public:
388  RestraintsAdaptor() {}
389  RestraintsAdaptor(const Restraints &sf) : Restraints(sf) {}
391  : Restraints(sf.begin(), sf.end()) {}
392  RestraintsAdaptor(Restraint *sf) : Restraints(1, sf) {}
393 #ifndef IMP_DOXYGEN
394  template <class T>
395  RestraintsAdaptor(internal::PointerBase<T> t)
396  : Restraints(1, get(t)) {}
397 #endif
398 };
399 
400 //! Return the decomposition of a list of restraints.
401 IMPKERNELEXPORT Restraints create_decomposition(const RestraintsTemp &rs);
402 
403 IMPKERNEL_END_NAMESPACE
404 
405 #endif /* IMPKERNEL_RESTRAINT_H */
bool get_is_custom_reset() const
Return whether this restraint provides custom logic for reset moves.
Definition: Restraint.h:305
Control display of deprecation information.
const double NO_MAX
Use this value when you want to turn off maximum for restraint evaluation.
Basic types used by IMP.
IMP::Vector< IMP::Pointer< Restraint > > Restraints
Definition: base_types.h:119
Class for adding scores from restraints to the model.
virtual RestraintInfo * get_static_info() const
Definition: Restraint.h:189
Various useful constants.
virtual RestraintInfo * get_dynamic_info() const
Definition: Restraint.h:201
Class for adding derivatives from restraints to the model.
const double BAD_SCORE
virtual Restraints do_create_decomposition() const
Definition: Restraint.h:319
#define IMP_REF_COUNTED_DESTRUCTOR(Name)
Set up destructor for a ref counted object.
A smart pointer to a reference counted object.
Definition: Pointer.h:87
ScoringFunction * create_scoring_function(RestraintType *rs, double weight=1.0, double max=NO_MAX, std::string name=std::string())
Create a ScoringFunction on a single restraint.
Definition: generic.h:23
double get_last_last_score() const
Get the unweighted score from the last-but-one time it was evaluated.
Definition: Restraint.h:299
IMP::Vector< IMP::WeakPointer< ModelObject > > ModelObjectsTemp
Definition: base_types.h:122
Class for storing model, its restraints, constraints, and particles.
Definition: Model.h:86
virtual double unprotected_evaluate_if_below(DerivativeAccumulator *da, double max) const
The function calling this will treat any score >= max as bad.
Definition: Restraint.h:157
Base class for objects in a Model that depend on other objects.
Definition: ModelObject.h:28
Convenience class to accept multiple input types.
virtual Restraints do_create_current_decomposition() const
Definition: Restraint.h:329
virtual double unprotected_evaluate_if_good(DerivativeAccumulator *da, double max) const
Definition: Restraint.h:150
#define IMP_UNUSED(variable)
Provide a consistent interface for things that take Restraints as arguments.
Definition: Restraint.h:378
Class for adding up scores during ScoringFunction evaluation.
Restraints create_decomposition(const RestraintsTemp &rs)
Return the decomposition of a list of restraints.
Report key:value information on restraints.
Definition: RestraintInfo.h:47
Base class for objects in a Model that depend on other objects.
virtual double get_last_score() const
Definition: Restraint.h:294
bool get_is_aggregate() const
Return whether this restraint wraps a number of other restraints.
Definition: Restraint.h:302
ModelObjectsTemp do_get_outputs() const override
Definition: Restraint.h:340
bool get_was_good() const
Definition: Restraint.h:310
Represents a scoring function on the model.
Report key:value information on restraints.
double Float
Basic floating-point value (could be float, double...)
Definition: types.h:19
Convenience class to accept multiple input types.
Definition: InputAdaptor.h:25
virtual double unprotected_evaluate_moved(DerivativeAccumulator *da, const ParticleIndexes &moved_pis, const ParticleIndexes &reset_pis) const
Return the unweighted score, taking moving particles into account.
Definition: Restraint.h:135
virtual void clear_moved_cache()
Clear any caches used by unprotected_evaluate_moved().
Definition: Restraint.h:144
Class for adding derivatives from restraints to the model.
A restraint is a term in an IMP ScoringFunction.
Definition: Restraint.h:56