IMP logo
IMP Reference Guide  develop.4eee3cf66f,2026/08/02
The Integrative Modeling Platform
SitesPairScore.h
Go to the documentation of this file.
1 /**
2  * \file SitesPairScore.h
3  * \brief A Score on the distance between a pair of particles.
4  *
5  * Copyright 2007-2026 IMP Inventors. All rights reserved.
6  */
7 
8 // TODO: verify if energy units are kcal/mol or KT
9 
10 #ifndef IMPNPCTRANSPORT_SITES_PAIR_SCORE_H
11 #define IMPNPCTRANSPORT_SITES_PAIR_SCORE_H
12 
13 #include "npctransport_config.h"
16 #include "internal/RigidBodyInfo.h"
17 #include "internal/sites.h"
18 #include <IMP/PairScore.h>
19 #include <IMP/UnaryFunction.h>
20 #include <IMP/Pointer.h>
21 #include <IMP/core/XYZR.h>
22 #include <IMP/core/Typed.h>
25 #include <IMP/generic.h>
28 #include <IMP/set_map_macros.h>
30 #include <IMP/atom/estimates.h>
31 #include <boost/unordered_set.hpp>
32 
33 #include <boost/array.hpp>
34 
35 IMPNPCTRANSPORT_BEGIN_NAMESPACE
36 
37 
38 /** \brief Apply a function to the distance between two particles with
39  a set of specific binding sites
40 
41  The sites are expressed in the local reference frame of
42  the two rigid bodies. Care must be taken to pass the bodies
43  in the appropriate order. See construction documentation for more details.
44 */
45 class IMPNPCTRANSPORTEXPORT SitesPairScore
47 {
48  private:
50 
51 
52  /************************* class variables ****************/
53  bool is_orientational_score_; // if true, use orientation-dependent score
56  sites0_, sites1_;
57 
58 
59  //! Maximal square of distance between particles with interacting sites
60  //! based on the interaction range and list of sites
61  double ubound_distance2_;
62 
63  // //! Cache:
64  // typedef IMP_KERNEL_LARGE_UNORDERED_MAP<ParticleIndex,internal::RigidBodyInfo>
65  // t_particles_rb_cache;
66  // mutable t_particles_rb_cache particles_rb_cache_;
67  // mutable bool is_cache_active_;
68  // mutable unsigned int cur_cache_id_; // to keep track of caching rounds
69 
70  public:
71 
72  /**
73  For positive sigmas, this is an orientation dependent score between two
74  spherical particles that
75  contain a fixed set of interaction sites, sites0 and sites1 (for
76  first and second particle, resp.).
77 
78  The interaction is composed of a non-specific interaction term
79  between the bead spheres, and the sum of interactions between
80  specific interactions sites of each bead.
81 
82  If \sigma{0} and \sigma{1} are positive, the attractive force
83  between pairs of sites at an optimal orientation (sites facing
84  each other) depends on their distance x. The attraction force
85  magnitude is k*x when x<=0.5*range and k*(range-x) when x is
86  between 0.5*range and range. When site0 is rotated by \sigma <
87  \sigma{0}, this force decays further by a factor
88  (cos{\sigma}-cos{\sigma}0)/(1.0-cos{\sigma0}). The force decays
89  similarly when site1 is rotated by \sigma < \sigma{1}. The
90  maximal potential energy difference due to such pair of
91  interacting sites is:
92  max\DELTA{U}_{site_site} = 0.25 * k * range^2 [kcal/mol]
93 
94  If sigma0_deg or sigma1_deg are non-positive, the attractive
95  force between pairs of sites within the attraction range is a
96  constant k, and the maximal interaction energy is instead:
97  max\DELTA{U}_{site-site} = k * range [kCal/mol]
98 
99  In addition to site-site interaction, there is a constant
100  attractive force k_nonspec_attraction between the sphere surfaces
101  up to a range range_nonspec_attraction, with maximal energy
102  contribution:
103  max\DELTA{U}_{non-specific} = 0.5 * k_nonspec_attraction * range_nonspec_attraction [kcal/mol]
104 
105  Note that for a specific pair of particles, each particle might have
106  a different reference frame (rigid body translation and rotation),
107  which is applied to the sites list upon score evaluation.
108 
109  @param range Maximal range of site specific attraction in any direction
110  of specific sites placed on particles
111  @param k Maximal site specific attraction coefficient (in
112  kcal/mol/A^2 when sigma0_deg and sigma1_deg are positive,
113  or kcal/mol/A otherwise, i.e., for orientation-independent interactions)
114  @param sigma0_deg, sigma1_deg Maximal rotational range of sites 0 and 1, respectively,
115  on the particle surface, specified in degrees. If either is 0,
116  the pair score between site centers is used with a constant k.
117  @param range_nonspec_attraction Range for non-specific attraction term
118  between particles that contain the sites
119  @param k_nonspec_attraction Non-specific attraction coefficient between particles
120  (constant force in kCal/mol/A within specified range)
121  @param k_nonspec_repulsion Repulsion coefficient between particles (constant force
122  applied when particle spheres overlap in kCal/mol/A)
123  @param sites0 List of sites on the first particle, in its local reference frame
124  @param sites1 List of sites on the second particle, in its local reference frame
125  */
126  SitesPairScore(double range, double k,
127  double sigma0_deg, double sigma1_deg,
128  double range_nonspec_attraction, double k_nonspec_attraction,
129  double k_nonspec_repulsion,
130  const algebra::Sphere3Ds &sites0,
131  const algebra::Sphere3Ds &sites1);
132 
133 
134  public:
135 
136  virtual double evaluate_indexes(
138  unsigned int lower_bound,
139  unsigned int upper_bound,
140  bool all_indexes_checked=false) const override final;
141 
142  //! evaluated indexes for the range from lower_bound to upper_bound
143  //! in p, if score>max then return max value of double
145  ( Model *m, const ParticleIndexPairs &p,
147  double max, unsigned int lower_bound,
148  unsigned int upper_bound,
149  bool all_indexes_checked=false) const override
150  {
151  IMP_UNUSED(all_indexes_checked);
152  // activate_cache();
153  double ret = 0.0;
154  for (unsigned int i = lower_bound; i < upper_bound; ++i) {
155  ret += evaluate_if_good_index(m, p[i], da, max - ret);
156  if (ret > max) return std::numeric_limits<double>::max();
157  }
158  // deactivate_cache();
159  return ret;
160  }
161 
162 
163  /** evaluate the score for the pair of model particle indexes in p,
164  updating score derivatives to da
165  */
166  virtual double evaluate_index(Model *m, const ParticleIndexPair &p,
167  DerivativeAccumulator *da) const override;
168 
169 #ifndef SWIG
170  /**
171  EvaluatE all site-site interactions
172  for evaluate_index() for the pair pip in model m. If da is not nullptr,
173  it accumulated appropriate derivatives. If contacts_accumulator is not null,
174  then the number of individual contacts and occupied sites is asscumulated there.
175 
176  @param sphere_table An array storing of sphere coordinates by particle index
177  @param quaternions_table An array of quaternions by particle index
178  @param sphere_table An array storing of sphere coordinate derivatives by particle index
179  @param torques_table An array of torques by particle index
180  @param pip the pair of particle indexes in m
181  @param da optional accumulator for force and torque derivatives
182  @param contacts_accumulator A pointer to a tuple of output values
183  [num-contacts, sites0-bound, sites1-bound, is_nonspec].
184  num-contacts is the total number of site-site contacts between pip.
185  sites0-bound and sites1-bound are vectors of contact counts
186  for each site of pip[0] and pip[1], resp, with one entry per site.
187  is_nonspec is true if the molecules have non-zero
188  nonspecific interactions Ignored if Null
189 
190  @return the site-site contributions for the score for the pair
191  pip in model m.
192  */
193  double
194  evaluate_site_contributions_with_internal_tables
195  (algebra::Sphere3D const* spheres_table,
196  algebra::Vector4D const* quaternions_table,
197  algebra::Sphere3D *sphere_derivatives_table,
198  algebra::Vector3D *torques_table,
199  const ParticleIndexPair &pip,
201  boost::tuple< unsigned int, std::vector<unsigned int>, std::vector<unsigned int>, bool >
202  (*contacts_accumulator) = nullptr
203  ) const;
204 
205  /**
206  EvaluatE all site-site interactions
207  for evaluate_index() for the pair pip in model m. If da is not nullptr,
208  it accumulated appropriate derivatives. If contacts_accumulator is not null,
209  then the number of individual contacts and occupied sites is asscumulated there.
210 
211  @param m the model
212  @param pip the pair of particle indexes in m
213  @param da optional accumulator for force and torque derivatives
214  @param contacts_accumulator A pointer to a tuple of output values
215  [num-contacts, sites0-bound, sites1-bound, is_nonspec].
216  num-contacts is the total number of site-site contacts between pip.
217  sites0-bound and sites1-bound are vectors of contact counts
218  for each site of pip[0] and pip[1], resp. is_nonspec is true if the
219  spheres have non-zero non-specific interactions
220  Ignored if Null
221 
222  @return the site-site contributions for the score for the pair
223  pip in model m.
224  */
225  double
226  evaluate_site_contributions
227  (Model* m,
228  const ParticleIndexPair &pip,
230  boost::tuple< unsigned int, std::vector<unsigned int>, std::vector<unsigned int>, bool >
231  (*contacts_accumulator)
232  ) const;
233 
234 #endif
235 
237  const ParticleIndexes &pis) const override;
238 
239  // Restraints do_create_current_decomposition(Model *m,
240  // const ParticleIndexPair &vt)
241  // const override;
242 
243  //! return the range for site-site attraction
244  double get_sites_range() const { return params_.r; }
245 
246  //! return the k for site-site attraction
247  double get_sites_k() const { return params_.k; }
248 
249  SitesPairScoreParameters get_parameters() const {return params_;}
250 
251  public:
253 
254  private:
255 
256  /** evaluate the score for the pair of model particle indexes in p,
257  updating score derivatives to da, and using internal attribute
258  tables in Model
259  */
260  inline double evaluate_index_with_internal_tables
261  ( Model* m,
262  algebra::Sphere3D const* spheres_table,
263  algebra::Vector4D const* quaternions_table,
264  algebra::Sphere3D *sphere_derivatives_table,
265  algebra::Vector3D *torques_table,
266  const ParticleIndexPair &p,
267  DerivativeAccumulator *da) const;
268 
269  // gets the rigid body information (e.g., translation, inverse rotation)
270  // associated with particle m.pi, possibly from cache (depending on internal
271  // cache definitions)
272  inline internal::RigidBodyInfo
273  get_rigid_body_info
274  (algebra::Sphere3D const* spheres_table,
275  algebra::Vector4D const* quaternions_table,
276  ParticleIndex pi) const;
277 
278  public:
279  // sets the sites associated with each partner to sites0
280  // and sites1, respectively (in local reference frame)
281  void set_sites(const algebra::Sphere3Ds &sites0,
282  const algebra::Sphere3Ds &sites1){
283  sites0_= sites0;
284  sites1_= sites1;
285  }
286 
287  // sets the sites associated with the first partner
288  // (in local reference frame)
289  void set_sites0(const algebra::Sphere3Ds &sites0){
290  sites0_= sites0;
291  }
292 
293  // sets the sites associated with the first partner
294  // (in local reference frame)
295  void set_sites1(const algebra::Sphere3Ds &sites1){
296  sites1_= sites1;
297  }
298 
299  private:
300  /* // maintain a cache for evaluate_index() till call to deactivate_cache() */
301  /* inline void activate_cache() const */
302  /* { */
303  /* // (note: cache is mutable) */
304  /* is_cache_active_ = true; cur_cache_id_++; */
305  /* } */
306 
307  /* inline void deactivate_cache() const */
308  /* { */
309  /* // (note: cache is mutable) */
310  /* is_cache_active_ = false; */
311  /* } */
312 
313 
314 };
315 
316 //!
317 inline double
318 SitesPairScore::evaluate_index
319 (Model *m, const ParticleIndexPair &p,
320  DerivativeAccumulator *da) const{
321  // get internal tables:
322  algebra::Sphere3D const* spheres_table=
323  m->access_spheres_data();
324  algebra::Vector4D const* quaternions_table =
325  core::RigidBody::access_quaternion_data(m);
326  algebra::Sphere3D* sphere_derivatives_table=
327  m->access_sphere_derivatives_data();
328  algebra::Vector3D* torques_table=
329  core::RigidBody::access_torque_data(m);
330  // evaluate:
331  return evaluate_index_with_internal_tables(m,
332  spheres_table,
333  quaternions_table,
334  sphere_derivatives_table,
335  torques_table,
336  p,
337  da);
338 }
339 
340 
341 
342 
343 /**
344  the sites of each particle are transformed to a common frame of reference
345  (using the reference frame of each particle), and the site-specific
346  attraction, and the inter-particle non specific attraction and repulsion
347  are evaluated and summed.
348 */
349 inline double
350 SitesPairScore::evaluate_index_with_internal_tables
351 (Model* m,
352  algebra::Sphere3D const* spheres_table,
353  algebra::Vector4D const* quaternions_table,
354  algebra::Sphere3D *sphere_derivatives_table,
355  algebra::Vector3D *torques_table,
356  const ParticleIndexPair &pip,
357  DerivativeAccumulator *da) const {
359 
360  // I. evaluate non-specific attraction and repulsion between
361  // parent particles before computing for specific sites :
362  double non_specific_score = P::evaluate_index(m, pip, da);
364  lips_cache= P::get_evaluation_cache();
365 
366  // II. Return if parent particles are out of site-specific interaction range
367  // using cache to avoid some redundant calcs
368  double const& distance2= lips_cache.particles_delta_squared;
369  IMP_LOG(PROGRESS, "distance2 " << distance2
370  << " ; distance upper-bound " << ubound_distance2_ << std::endl);
371  if (distance2 > ubound_distance2_) {
372  IMP_LOG(PROGRESS, "Sites contribution is 0.0 and non-specific score is "
373  << non_specific_score << std::endl);
374  return non_specific_score;
375  }
376 
377  double site_score=evaluate_site_contributions_with_internal_tables
378  (spheres_table,
379  quaternions_table,
380  sphere_derivatives_table,
381  torques_table,
382  pip, da);
383  // III. evaluate site-specific contributions :
384  return site_score + non_specific_score;
385 }
386 
387 #ifndef SWIG
388 
389 //!
390 inline double
391 SitesPairScore::evaluate_site_contributions_with_internal_tables
392 ( algebra::Sphere3D const* spheres_table,
393  algebra::Vector4D const* quaternions_table,
394  algebra::Sphere3D *sphere_derivatives_table,
395  algebra::Vector3D *torques_table,
396  const ParticleIndexPair &pip,
398  boost::tuple<unsigned int,
399  std::vector<unsigned int>,
400  std::vector<unsigned int>,
401  bool>
402  * contacts_accumulator
403  ) const
404 {
406  // interaction statistics variables
407  static unsigned int n_contacts;
408  static std::vector<unsigned int> occupied_sites0; // how many contacts at each site of particle 0
409  static std::vector<unsigned int> occupied_sites1; // how many contacts at each site of particle 1
410  if(contacts_accumulator){
411  n_contacts= 0;
412  occupied_sites0.resize(sites0_.size());
413  occupied_sites1.resize(sites1_.size());
414  std::fill(occupied_sites0.begin(), occupied_sites0.end(),0);
415  std::fill(occupied_sites1.begin(), occupied_sites1.end(),0);
416  }
417 
418  // bring sites_ to the frame of reference of nn_sites_ and nn_
419  ParticleIndex pi0 = pip[0];
420  ParticleIndex pi1 = pip[1];
421  // get rbi0/1 info, update if needed
422  internal::RigidBodyInfo rbi0 = get_rigid_body_info(spheres_table,
423  quaternions_table,
424  pi0);
425  internal::RigidBodyInfo rbi1 = get_rigid_body_info(spheres_table,
426  quaternions_table,
427  pi1);
428  IMP_LOG_PROGRESS( "RBI0.pi " << rbi0.pi
429  << " RB0.cache_id " << rbi0.cache_id
430  << "RBI0.tr " << rbi0.tr << std::endl);
431  IMP_LOG_PROGRESS( "RBI1.cache_id " << rbi1.cache_id
432  << "RBI1.pi " << rbi1.pi
433  << "RBI1.tr " << rbi1.tr << std::endl);
434  // sum over specific interactions between all pairs of sites:
435  double sum = 0;
436  if(is_orientational_score_){
437  // Pre-compute a few variables that do not depend on either both sites or on site1
438  algebra::Vector3D const& gRB0= rbi0.tr.get_translation();
439  algebra::Vector3D const& gRB1= rbi1.tr.get_translation();
440  algebra::Vector3D gUnitRB0RB1= gRB1-gRB0;
441  double distRB0RB1= get_magnitude_and_normalize_in_place(gUnitRB0RB1); // distance between centers
442  for (unsigned int i0 = 0; i0 < sites0_.size(); ++i0) {
443  algebra::Vector3D gSite0 = rbi0.tr.get_transformed(sites0_[i0].get_center());
444  algebra::Vector3D gUnitRB0Site0= (gSite0-gRB0)*rbi0.iradius;
445  double cosSigma0 = gUnitRB0Site0*gUnitRB0RB1;
446  if(cosSigma0 < params_.cosSigma1_max) { // not in range... - note the indexing is not an error - sigma0 is equivalent to params_.sigma1
447  continue;
448  }
449  double kFactor0=internal::get_k_factor(cosSigma0, params_.cosSigma1_max); // note the indexing is not an error - sigma0 is equivalent to params_.sigma1
450  algebra::Vector3D gRotSigma0;
451  double dKFactor0;
452  if(da){
453  gRotSigma0 = get_vector_product(gUnitRB0Site0,gUnitRB0RB1);
454  double absSinSigma0 = get_magnitude_and_normalize_in_place(gRotSigma0);
455  dKFactor0=internal::get_derivative_k_factor(absSinSigma0, params_.cosSigma1_max);
456  }
457  for(unsigned int i1 = 0 ; i1 < sites1_.size(); ++i1) {
458  algebra::Vector3D gSite1 = rbi1.tr.get_transformed(sites1_[i1].get_center());
459  IMP_LOG_PROGRESS( "Evaluating sites at global coordinates: " << gSite0
460  << " ; " << gSite1 << std::endl );
461  double cur_score;
462  cur_score =
463  internal::evaluate_pair_of_sites(params_,
464  rbi0, rbi1,
465  gSite1,
466  gUnitRB0RB1, distRB0RB1,
467  gRotSigma0,
468  kFactor0, dKFactor0,
469  da,
470  sphere_derivatives_table,
471  torques_table);
472  sum += cur_score;
473  if(contacts_accumulator && cur_score!=0.0){
474  n_contacts++;
475  occupied_sites0[i0]++;
476  occupied_sites1[i1]++;
477  }
478  } // j
479  } // i
480  } // is_orientational_score_
481  else
482  {
483  for (unsigned int i = 0; i < sites0_.size(); ++i) {
484  algebra::Vector3D g0 = rbi0.tr.get_transformed(sites0_[i].get_center());
485  for(unsigned int j = 0 ; j < sites1_.size(); ++j) {
486  algebra::Vector3D g1 = rbi1.tr.get_transformed(sites1_[j].get_center());
487  IMP_LOG_PROGRESS( "Evaluating sites at global coordinates: " << g0 << " ; " << g1 << std::endl );
488  double cur_score;
489  // old score
490  cur_score =
491  internal::evaluate_one_site_3(params_.k,
492  params_.r,
493  rbi0, rbi1,
494  sites0_[i], sites1_[j],
495  g0, g1,
496  da,
497  sphere_derivatives_table,
498  torques_table);
499 
500  sum += cur_score;
501  if(contacts_accumulator && cur_score!=0.0){
502  n_contacts++;
503  occupied_sites0[i]++;
504  occupied_sites1[i]++;
505  }
506  }// j
507  }// i
508  } // else
509  if(contacts_accumulator){
510  double non_specific_range= P::get_range_attraction();
511  double d_spheres= IMP::algebra::get_distance(spheres_table[pip[0].get_index()],
512  spheres_table[pip[1].get_index()]);
513  bool is_nonspecific_interaction= d_spheres < non_specific_range;
514  (*contacts_accumulator)=
515  boost::make_tuple(n_contacts,
516  occupied_sites0,
517  occupied_sites1,
518  is_nonspecific_interaction);
519  }
520 
521  IMP_LOG_PROGRESS( "Sum " << sum << std::endl);
522  return sum;
523 }
524 
525 
526 //!
527 inline double
528 SitesPairScore::evaluate_site_contributions
529 (Model* m,
530  const ParticleIndexPair &pip,
532  boost::tuple< unsigned int, std::vector<unsigned int>, std::vector<unsigned int>, bool >
533  (*contacts_accumulator)
534  ) const
535 {
536  // Get internal tables
537  algebra::Sphere3D const* spheres_table=
538  m->access_spheres_data();
539  algebra::Vector4D const* quaternions_table =
540  core::RigidBody::access_quaternion_data(m);
541  algebra::Sphere3D* sphere_derivatives_table=
542  m->access_sphere_derivatives_data();
543  algebra::Vector3D* torques_table=
544  core::RigidBody::access_torque_data(m);
545  // evaluate:
546  return evaluate_site_contributions_with_internal_tables
547  (spheres_table,
548  quaternions_table,
549  sphere_derivatives_table,
550  torques_table,
551  pip,
552  da,
553  contacts_accumulator);
554 }
555 
556 #endif // ifndef SWIG
557 
558 //!
559 inline internal::RigidBodyInfo
560 SitesPairScore::get_rigid_body_info
561 (algebra::Sphere3D const* spheres_table,
562  algebra::Vector4D const* quaternions_table,
563  ParticleIndex pi) const
564 {
565  // TODO: add usage check that it has valid quaternions
566  // IMP_USAGE_CHECK(core::RigidBody::get_is_setup(m, pi),
567  // "PI " << pi.get_index() << " not a rigid body");
568  /* if(is_cache_active_){ */
569  /* std::pair<t_particles_rb_cache::iterator, bool> */
570  /* p = particles_rb_cache_.insert */
571  /* (std::make_pair(pi, internal::RigidBodyInfo())); */
572  /* internal::RigidBodyInfo& rbi_cached = p.first->second; */
573  /* bool const rbi_in_cache = !p.second; */
574  /* if(!rbi_in_cache || */
575  /* rbi_cached.cache_id != cur_cache_id_) // = cached version is outdated */
576  /* { */
577  /* rbi_cached.set_particle(spheres_table, */
578  /* quaternions_tables, */
579  /* pi, */
580  /* cur_cache_id_); */
581  /* } */
582  /* return rbi_cached; */
583  /* } */
584  /* else // if is_cache_active_ */
585  /* { */
586  return internal::RigidBodyInfo(spheres_table,
587  quaternions_table,
588  pi,
589  INVALID_CACHE_ID);
590  /* } */
591 }
592 
593 
594 
595 IMPNPCTRANSPORT_END_NAMESPACE
596 
597 #endif /* IMPNPCTRANSPORT_SITES_PAIR_SCORE_H */
Apply a PairScore to each Pair in a list.
virtual double evaluate_indexes(Model *m, const ParticleIndexPairs &pips, DerivativeAccumulator *da, unsigned int lower_bound, unsigned int upper_bound, bool all_indexes_checked=false) const override
#define IMP_OBJECT_METHODS(Name)
Define the basic things needed by any Object.
Definition: object_macros.h:25
#define IMP_OBJECT_LOG
Set the log level to the object's log level.
Definition: log_macros.h:284
Single variable function.
VectorD< 4 > Vector4D
Definition: VectorD.h:411
#define IMP_LOG_PROGRESS(expr)
Definition: log_macros.h:94
A particle with a user-defined type.
Macros to choose the best set or map for different purposes.
Class for storing model, its restraints, constraints, and particles.
Definition: Model.h:86
Apply a function to the distance between two particles with a set of specific binding sites...
virtual double evaluate_if_good_indexes(Model *m, const ParticleIndexPairs &o, DerivativeAccumulator *da, double max, unsigned int lower_bound, unsigned int upper_bound, bool all_indexes_checked=false) const
Ints get_index(const ParticlesTemp &particles, const Subset &subset, const Subsets &excluded)
VectorD< 3 > Vector3D
Definition: VectorD.h:407
#define IMP_UNUSED(variable)
Define PairScore.
Represent an XYZR particle with a sphere.
Simple 3D transformation class.
A score on the distance between the surfaces of two spheres.
A nullptr-initialized pointer to an IMP Object.
double get_sites_range() const
return the range for site-site attraction
ModelObjectsTemp do_get_inputs(Model *m, const ParticleIndexes &pis) const override
Overload this method to specify the inputs.
double get_sites_k() const
return the k for site-site attraction
double evaluate_index(algebra::Sphere3D const &s0, algebra::Sphere3D const &s1, algebra::Sphere3D &ds0, algebra::Sphere3D &ds1, DerivativeAccumulator *da) const
Functions to search over vectors.
A Score on the distance between a pair of particles.
A summary of useful information about rigid bodies and their transformation for eg, caching purposes for SitesPairScore.
Vector3D get_vector_product(const Vector3D &p1, const Vector3D &p2)
Return the vector product (cross product) of two vectors.
Definition: Vector3D.h:31
Decorator for a sphere-like particle.
double get_distance(const Line3D &s, const Vector3D &p)
Get closest distance between a line and a point.
Class for adding derivatives from restraints to the model.
Estimates of various physical quantities.
Compile-time generic restraint and constraint support.