IMP logo
IMP Reference Guide  develop.5651aa123e,2024/07/23
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-2022 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  \param da Object to accumulate derivatives, or nullptr.
121  \param moved_pis Particles that have moved since the last
122  scoring function evaluation.
123  \param reset_pis Particles that have moved, but back to the
124  positions they had at the last-but-one evaluation
125  (e.g. due to a rejected Monte Carlo move).
126 
127  \return Current score.
128  */
130  DerivativeAccumulator *da, const ParticleIndexes &moved_pis,
131  const ParticleIndexes &reset_pis) const {
132  IMP_UNUSED(moved_pis);
133  IMP_UNUSED(reset_pis);
134  return unprotected_evaluate(da);
135  }
136 
137  /** The function calling this will treat any score >= get_maximum_score
138  as bad and so can return early as soon as such a situation is found.*/
140  double max) const {
141  IMP_UNUSED(max);
142  return unprotected_evaluate(da);
143  }
144 
145  //! The function calling this will treat any score >= max as bad.
147  double max) const {
148  IMP_UNUSED(max);
149  return unprotected_evaluate(da);
150  }
151 
152  virtual double unprotected_evaluate_moved_if_below(
153  DerivativeAccumulator *da, const ParticleIndexes &moved_pis,
154  const ParticleIndexes &reset_pis, double max) const {
155  IMP_UNUSED(max);
156  return unprotected_evaluate_moved(da, moved_pis, reset_pis);
157  }
158 
159  virtual double unprotected_evaluate_moved_if_good(
160  DerivativeAccumulator *da, const ParticleIndexes &moved_pis,
161  const ParticleIndexes &reset_pis, double max) const {
162  IMP_UNUSED(max);
163  return unprotected_evaluate_moved(da, moved_pis, reset_pis);
164  }
165 
166 /** @} */
167 
168  //! \return static key:value information about this restraint, or null.
169  /** \return a set of key:value pairs that contain static information
170  about this restraint (i.e. information that doesn't change during
171  a sampling run, such as the type of restraint or filename from
172  which information is read). Usually this includes a "type" key with
173  the fully qualified classname (e.g. IMP.mymodule.MyRestraint).
174  If no such information is available, a null pointer is returned.
175  This information is used when writing restraints to files, e.g. by
176  the IMP.rmf module.
177  */
178  virtual RestraintInfo *get_static_info() const {
179  return nullptr;
180  }
181 
182  //! \return dynamic key:value information about this restraint, or null.
183  /** \return a set of key:value pairs that contain dynamic information
184  about this restraint (i.e. information that changes during a sampling
185  run, such as scores or cross correlations).
186  If no such information is available, a null pointer is returned.
187  This information is used when writing restraints to files, e.g. by
188  the IMP.rmf module.
189  */
190  virtual RestraintInfo *get_dynamic_info() const {
191  return nullptr;
192  }
193 
194 #ifndef IMP_DOXYGEN
195  //! Perform the actual restraint scoring.
196  /** The restraints should assume that all appropriate ScoreState
197  objects have been updated and so that the input particles and containers
198  are up to date. The returned score should be the unweighted score.
199  */
200  void add_score_and_derivatives(ScoreAccumulator sa) const;
201 
202  void add_score_and_derivatives_moved(
203  ScoreAccumulator sa, const ParticleIndexes &moved_pis,
204  const ParticleIndexes &reset_pis) const;
205 #endif
206 
207  //! Decompose this restraint into constituent terms
208  /** Given the set of input particles, decompose the restraint into parts
209  that are as simple as possible. For many restraints, the simplest
210  part is simply the restraint itself.
211 
212  If a restraint can be decomposed, it should return a
213  RestraintSet so that the maximum score and weight can be
214  passed properly.
215 
216  The restraints returned have had set_model() called and so can
217  be evaluated.
218  */
220 
221  //! Decompose this restraint into constituent terms for the current conf
222  /** \return a decomposition that is value for the current conformation,
223  but will not necessarily be valid if any of the particles are
224  changed. This is the same as create_decomposition() for
225  non-conditional restraints.
226 
227  The restraints returned have had set_model() called and so can be
228  evaluated.
229  */
230  Restraint *create_current_decomposition() const;
231 
232  /** \name Weights
233  Each restraint's contribution to the model score is weighted. The
234  total weight for the restraint is the some over all the paths containing
235  it. That is, if a restraint is in a RestraintSet with weight .5 and
236  another with weight 2, and the restraint itself has weight 3, then the
237  total weight of the restraint is \f$.5 \cdot 3 + 2 \cdot 3 = 7.5 \f$.
238  @{
239  */
240  void set_weight(Float weight);
241  Float get_weight() const { return weight_; }
242  /** @} */
243  /** \name Filtering
244  We are typically only interested in "good" conformations of
245  the model. These are described by specifying maximum scores
246  per restraint (or RestraintSet). Samplers, optimizers
247  etc are free to ignore configurations they encounter which
248  go outside these bounds.
249 
250  \note The maximum score is for the unweighted restraint.
251  That is, the restraint evaluation is bad if the value
252  is greater than the maximum score divided by the weight.
253  @{
254  */
255  double get_maximum_score() const { return max_; }
256  void set_maximum_score(double s);
257 /** @} */
258 
259 //! Create a scoring function with only this restraint.
260 /** \note This method cannot be implemented in Python due to memory
261  management issues (and the question of why you would ever
262  want to).
263  */
264 #ifndef SWIG
265  virtual
266 #endif
267  ScoringFunction *
268  create_scoring_function(double weight = 1.0,
269  double max = NO_MAX) const;
270 #if !defined(IMP_DOXYGEN)
271  void set_last_score(double s) const {
272  last_last_score_ = last_score_;
273  last_score_ = s;
274  }
275  void set_last_last_score(double s) const { last_last_score_ = s; }
276 #endif
277 
278  /** Return the (unweighted) score for this restraint last time it was
279  evaluated.
280  \note If some sort of special evaluation (eg Model::evaluate_if_good())
281  was the last call, the score, if larger than the max, is not accurate.
282  */
283  virtual double get_last_score() const { return last_score_; }
284 
285  //! Get the unweighted score from the last-but-one time it was evaluated
286  /** \see get_last_score
287  */
288  double get_last_last_score() const { return last_last_score_; }
289 
290  //! Return whether this restraint wraps a number of other restraints
291  bool get_is_aggregate() const { return is_aggregate_; }
292 
293  /** Return whether this restraint violated its maximum last time it was
294  evaluated.
295  */
296  bool get_was_good() const { return get_last_score() < max_; }
297 
299 
300  protected:
301  /** A Restraint should override this if it wants to decompose itself
302  for domino and other purposes. The returned restraints will be made
303  into a RestraintSet if needed, with suitable weight and maximum score.
304  */
306  return Restraints(1, const_cast<Restraint *>(this));
307  }
308  /** A Restraint should override this if it wants to decompose itself
309  for display and other purposes. The returned restraints will be made
310  into a RestraintSet if needed, with suitable weight and maximum score.
311 
312  The returned restraints should be only the non-zero terms and should
313  have their last scores set appropriately.
314  */
316  return do_create_decomposition();
317  }
318 
319  virtual void do_add_score_and_derivatives(ScoreAccumulator sa) const;
320 
321  virtual void do_add_score_and_derivatives_moved(
322  ScoreAccumulator sa, const ParticleIndexes &moved_pis,
323  const ParticleIndexes &reset_pis) const;
324 
325  /** No outputs. */
326  ModelObjectsTemp do_get_outputs() const override {
327  return ModelObjectsTemp();
328  }
329 
330  protected:
331  bool is_aggregate_;
332 
333  private:
334  ScoringFunction *create_internal_scoring_function() const;
335 
336  double weight_;
337  double max_;
338  mutable double last_score_;
339  mutable double last_last_score_;
340  // cannot be released outside the class
341  mutable Pointer<ScoringFunction> cached_internal_scoring_function_;
342 
343  friend class cereal::access;
344 
345  template<class Archive> void serialize(Archive &ar) {
346  ar(cereal::base_class<ModelObject>(this));
347  ar(weight_, max_);
348  // Clear caches
349  if (std::is_base_of<cereal::detail::InputArchiveBase, Archive>::value) {
350  last_score_ = last_last_score_ = BAD_SCORE;
351  cached_internal_scoring_function_ = nullptr;
352  }
353  }
354 
355 };
356 
357 //! Provide a consistent interface for things that take Restraints as arguments.
358 /**
359  \note Passing an empty list of restraints should be supported, but problems
360  could arise, so be alert (the problems would not be subtle).
361 */
362 class IMPKERNELEXPORT RestraintsAdaptor :
363 #if !defined(SWIG) && !defined(IMP_DOXYGEN)
364  public Restraints
365 #else
366  public InputAdaptor
367 #endif
368  {
369  static Restraint *get(Restraint *r) { return r; }
370 
371  public:
372  RestraintsAdaptor() {}
373  RestraintsAdaptor(const Restraints &sf) : Restraints(sf) {}
375  : Restraints(sf.begin(), sf.end()) {}
376  RestraintsAdaptor(Restraint *sf) : Restraints(1, sf) {}
377 #ifndef IMP_DOXYGEN
378  template <class T>
379  RestraintsAdaptor(internal::PointerBase<T> t)
380  : Restraints(1, get(t)) {}
381 #endif
382 };
383 
384 //! Return the decomposition of a list of restraints.
385 IMPKERNELEXPORT Restraints create_decomposition(const RestraintsTemp &rs);
386 
387 IMPKERNEL_END_NAMESPACE
388 
389 #endif /* IMPKERNEL_RESTRAINT_H */
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:103
Class for adding scores from restraints to the model.
virtual RestraintInfo * get_static_info() const
Definition: Restraint.h:178
Various useful constants.
virtual RestraintInfo * get_dynamic_info() const
Definition: Restraint.h:190
Class for adding derivatives from restraints to the model.
const double BAD_SCORE
virtual Restraints do_create_decomposition() const
Definition: Restraint.h:305
#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:288
IMP::Vector< IMP::WeakPointer< ModelObject > > ModelObjectsTemp
Definition: base_types.h:106
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:146
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:315
virtual double unprotected_evaluate_if_good(DerivativeAccumulator *da, double max) const
Definition: Restraint.h:139
#define IMP_UNUSED(variable)
Provide a consistent interface for things that take Restraints as arguments.
Definition: Restraint.h:362
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:283
bool get_is_aggregate() const
Return whether this restraint wraps a number of other restraints.
Definition: Restraint.h:291
ModelObjectsTemp do_get_outputs() const override
Definition: Restraint.h:326
bool get_was_good() const
Definition: Restraint.h:296
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:129
Class for adding derivatives from restraints to the model.
A restraint is a term in an IMP ScoringFunction.
Definition: Restraint.h:56