IMP logo
IMP Reference Guide  develop.c4c24800fe,2026/07/12
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-2022 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_tables 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  double const**quaternions_tables,
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  double const **quaternions_tables,
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  double const** quaternions_tables,
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  double const* quaternions_tables[4];
325  for(unsigned int i = 0; i < 4; i++){
326  quaternions_tables[i]=
327  core::RigidBody::access_quaternion_i_data(m, i);
328  }
329  algebra::Sphere3D* sphere_derivatives_table=
330  m->access_sphere_derivatives_data();
331  algebra::Vector3D* torques_table=
332  core::RigidBody::access_torque_data(m);
333  // evaluate:
334  return evaluate_index_with_internal_tables(m,
335  spheres_table,
336  quaternions_tables,
337  sphere_derivatives_table,
338  torques_table,
339  p,
340  da);
341 }
342 
343 
344 
345 
346 /**
347  the sites of each particle are transformed to a common frame of reference
348  (using the reference frame of each particle), and the site-specific
349  attraction, and the inter-particle non specific attraction and repulsion
350  are evaluated and summed.
351 */
352 inline double
353 SitesPairScore::evaluate_index_with_internal_tables
354 ( Model* m,
355  algebra::Sphere3D const* spheres_table,
356  double const** quaternions_tables,
357  algebra::Sphere3D *sphere_derivatives_table,
358  algebra::Vector3D *torques_table,
359  const ParticleIndexPair &pip,
360  DerivativeAccumulator *da) const {
362 
363  // I. evaluate non-specific attraction and repulsion between
364  // parent particles before computing for specific sites :
365  double non_specific_score = P::evaluate_index(m, pip, da);
367  lips_cache= P::get_evaluation_cache();
368 
369  // II. Return if parent particles are out of site-specific interaction range
370  // using cache to avoid some redundant calcs
371  double const& distance2= lips_cache.particles_delta_squared;
372  IMP_LOG(PROGRESS, "distance2 " << distance2
373  << " ; distance upper-bound " << ubound_distance2_ << std::endl);
374  if (distance2 > ubound_distance2_) {
375  IMP_LOG(PROGRESS, "Sites contribution is 0.0 and non-specific score is "
376  << non_specific_score << std::endl);
377  return non_specific_score;
378  }
379 
380  double site_score=evaluate_site_contributions_with_internal_tables
381  (spheres_table,
382  quaternions_tables,
383  sphere_derivatives_table,
384  torques_table,
385  pip, da);
386  // III. evaluate site-specific contributions :
387  return site_score + non_specific_score;
388 }
389 
390 #ifndef SWIG
391 
392 //!
393 inline double
394 SitesPairScore::evaluate_site_contributions_with_internal_tables
395 ( algebra::Sphere3D const* spheres_table,
396  double const**quaternions_tables,
397  algebra::Sphere3D *sphere_derivatives_table,
398  algebra::Vector3D *torques_table,
399  const ParticleIndexPair &pip,
401  boost::tuple<unsigned int,
402  std::vector<unsigned int>,
403  std::vector<unsigned int>,
404  bool>
405  * contacts_accumulator
406  ) const
407 {
409  // interaction statistics variables
410  static unsigned int n_contacts;
411  static std::vector<unsigned int> occupied_sites0; // how many contacts at each site of particle 0
412  static std::vector<unsigned int> occupied_sites1; // how many contacts at each site of particle 1
413  if(contacts_accumulator){
414  n_contacts= 0;
415  occupied_sites0.resize(sites0_.size());
416  occupied_sites1.resize(sites1_.size());
417  std::fill(occupied_sites0.begin(), occupied_sites0.end(),0);
418  std::fill(occupied_sites1.begin(), occupied_sites1.end(),0);
419  }
420 
421  // bring sites_ to the frame of reference of nn_sites_ and nn_
422  ParticleIndex pi0 = pip[0];
423  ParticleIndex pi1 = pip[1];
424  // get rbi0/1 info, update if needed
425  internal::RigidBodyInfo rbi0 = get_rigid_body_info(spheres_table,
426  quaternions_tables,
427  pi0);
428  internal::RigidBodyInfo rbi1 = get_rigid_body_info(spheres_table,
429  quaternions_tables,
430  pi1);
431  IMP_LOG_PROGRESS( "RBI0.pi " << rbi0.pi
432  << " RB0.cache_id " << rbi0.cache_id
433  << "RBI0.tr " << rbi0.tr << std::endl);
434  IMP_LOG_PROGRESS( "RBI1.cache_id " << rbi1.cache_id
435  << "RBI1.pi " << rbi1.pi
436  << "RBI1.tr " << rbi1.tr << std::endl);
437  // sum over specific interactions between all pairs of sites:
438  double sum = 0;
439  if(is_orientational_score_){
440  // Pre-compute a few variables that do not depend on either both sites or on site1
441  algebra::Vector3D const& gRB0= rbi0.tr.get_translation();
442  algebra::Vector3D const& gRB1= rbi1.tr.get_translation();
443  algebra::Vector3D gUnitRB0RB1= gRB1-gRB0;
444  double distRB0RB1= get_magnitude_and_normalize_in_place(gUnitRB0RB1); // distance between centers
445  for (unsigned int i0 = 0; i0 < sites0_.size(); ++i0) {
446  algebra::Vector3D gSite0 = rbi0.tr.get_transformed(sites0_[i0].get_center());
447  algebra::Vector3D gUnitRB0Site0= (gSite0-gRB0)*rbi0.iradius;
448  double cosSigma0 = gUnitRB0Site0*gUnitRB0RB1;
449  if(cosSigma0 < params_.cosSigma1_max) { // not in range... - note the indexing is not an error - sigma0 is equivalent to params_.sigma1
450  continue;
451  }
452  double kFactor0=internal::get_k_factor(cosSigma0, params_.cosSigma1_max); // note the indexing is not an error - sigma0 is equivalent to params_.sigma1
453  algebra::Vector3D gRotSigma0;
454  double dKFactor0;
455  if(da){
456  gRotSigma0 = get_vector_product(gUnitRB0Site0,gUnitRB0RB1);
457  double absSinSigma0 = get_magnitude_and_normalize_in_place(gRotSigma0);
458  dKFactor0=internal::get_derivative_k_factor(absSinSigma0, params_.cosSigma1_max);
459  }
460  for(unsigned int i1 = 0 ; i1 < sites1_.size(); ++i1) {
461  algebra::Vector3D gSite1 = rbi1.tr.get_transformed(sites1_[i1].get_center());
462  IMP_LOG_PROGRESS( "Evaluating sites at global coordinates: " << gSite0
463  << " ; " << gSite1 << std::endl );
464  double cur_score;
465  cur_score =
466  internal::evaluate_pair_of_sites(params_,
467  rbi0, rbi1,
468  gSite1,
469  gUnitRB0RB1, distRB0RB1,
470  gRotSigma0,
471  kFactor0, dKFactor0,
472  da,
473  sphere_derivatives_table,
474  torques_table);
475  sum += cur_score;
476  if(contacts_accumulator && cur_score!=0.0){
477  n_contacts++;
478  occupied_sites0[i0]++;
479  occupied_sites1[i1]++;
480  }
481  } // j
482  } // i
483  } // is_orientational_score_
484  else
485  {
486  for (unsigned int i = 0; i < sites0_.size(); ++i) {
487  algebra::Vector3D g0 = rbi0.tr.get_transformed(sites0_[i].get_center());
488  for(unsigned int j = 0 ; j < sites1_.size(); ++j) {
489  algebra::Vector3D g1 = rbi1.tr.get_transformed(sites1_[j].get_center());
490  IMP_LOG_PROGRESS( "Evaluating sites at global coordinates: " << g0 << " ; " << g1 << std::endl );
491  double cur_score;
492  // old score
493  cur_score =
494  internal::evaluate_one_site_3(params_.k,
495  params_.r,
496  rbi0, rbi1,
497  sites0_[i], sites1_[j],
498  g0, g1,
499  da,
500  sphere_derivatives_table,
501  torques_table);
502 
503  sum += cur_score;
504  if(contacts_accumulator && cur_score!=0.0){
505  n_contacts++;
506  occupied_sites0[i]++;
507  occupied_sites1[i]++;
508  }
509  }// j
510  }// i
511  } // else
512  if(contacts_accumulator){
513  double non_specific_range= P::get_range_attraction();
514  double d_spheres= IMP::algebra::get_distance(spheres_table[pip[0].get_index()],
515  spheres_table[pip[1].get_index()]);
516  bool is_nonspecific_interaction= d_spheres < non_specific_range;
517  (*contacts_accumulator)=
518  boost::make_tuple(n_contacts,
519  occupied_sites0,
520  occupied_sites1,
521  is_nonspecific_interaction);
522  }
523 
524  IMP_LOG_PROGRESS( "Sum " << sum << std::endl);
525  return sum;
526 }
527 
528 
529 //!
530 inline double
531 SitesPairScore::evaluate_site_contributions
532 (Model* m,
533  const ParticleIndexPair &pip,
535  boost::tuple< unsigned int, std::vector<unsigned int>, std::vector<unsigned int>, bool >
536  (*contacts_accumulator)
537  ) const
538 {
539  // Get internal tables
540  algebra::Sphere3D const* spheres_table=
541  m->access_spheres_data();
542  double const* quaternions_tables[4];
543  for(unsigned int i = 0; i < 4; i++){
544  quaternions_tables[i]=
545  core::RigidBody::access_quaternion_i_data(m, i);
546  }
547  algebra::Sphere3D* sphere_derivatives_table=
548  m->access_sphere_derivatives_data();
549  algebra::Vector3D* torques_table=
550  core::RigidBody::access_torque_data(m);
551  // evaluate:
552  return evaluate_site_contributions_with_internal_tables
553  (spheres_table,
554  quaternions_tables,
555  sphere_derivatives_table,
556  torques_table,
557  pip,
558  da,
559  contacts_accumulator);
560 }
561 
562 #endif // ifndef SWIG
563 
564 //!
565 inline internal::RigidBodyInfo
566 SitesPairScore::get_rigid_body_info
567 (algebra::Sphere3D const* spheres_table,
568  double const **quaternions_tables,
569  ParticleIndex pi) const
570 {
571  // TODO: add usage check that it has valid quaternions
572  // IMP_USAGE_CHECK(core::RigidBody::get_is_setup(m, pi),
573  // "PI " << pi.get_index() << " not a rigid body");
574  /* if(is_cache_active_){ */
575  /* std::pair<t_particles_rb_cache::iterator, bool> */
576  /* p = particles_rb_cache_.insert */
577  /* (std::make_pair(pi, internal::RigidBodyInfo())); */
578  /* internal::RigidBodyInfo& rbi_cached = p.first->second; */
579  /* bool const rbi_in_cache = !p.second; */
580  /* if(!rbi_in_cache || */
581  /* rbi_cached.cache_id != cur_cache_id_) // = cached version is outdated */
582  /* { */
583  /* rbi_cached.set_particle(spheres_table, */
584  /* quaternions_tables, */
585  /* pi, */
586  /* cur_cache_id_); */
587  /* } */
588  /* return rbi_cached; */
589  /* } */
590  /* else // if is_cache_active_ */
591  /* { */
592  return internal::RigidBodyInfo(spheres_table,
593  quaternions_tables,
594  pi,
595  INVALID_CACHE_ID);
596  /* } */
597 }
598 
599 
600 
601 IMPNPCTRANSPORT_END_NAMESPACE
602 
603 #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.
#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.