IMP logo
IMP Reference Guide  2.14.0
The Integrative Modeling Platform
rigid_bodies.h
Go to the documentation of this file.
1 /**
2  * \file IMP/core/rigid_bodies.h
3  * \brief functionality for defining rigid bodies
4  *
5  * Copyright 2007-2020 IMP Inventors. All rights reserved.
6  */
7 
8 #ifndef IMPCORE_RIGID_BODIES_H
9 #define IMPCORE_RIGID_BODIES_H
10 
11 #include <IMP/core/core_config.h>
12 #include "internal/rigid_bodies.h"
13 
14 #include "XYZ.h"
15 #include "XYZR.h"
16 #include <IMP/SingletonContainer.h>
17 #include <IMP/SingletonModifier.h>
18 #include <IMP/Refiner.h>
19 #include <IMP/algebra/Vector3D.h>
20 #include <IMP/algebra/Rotation3D.h>
23 #include <Eigen/Dense>
24 
25 IMPCORE_BEGIN_NAMESPACE
26 
27 IMP_DECORATORS_DECL(RigidMember, RigidMembers);
28 IMP_DECORATORS_DECL(RigidBodyMember, RigidBodyMembers);
29 
30 //! A decorator for a rigid body
31 /** A rigid body particle describes a set of particles, known
32  as the members, which move rigidly together. The rigid body
33  is represented as an algebra::ReferenceFrame3D coupled
34  with local coordinates (RigidMember::get_internal_coordinates())
35  for the members expressed in that reference frame. The
36  global coordinates of the members are accessed, as with
37  other global coordinates, via the XYZ::get_coordinates().
38 
39  Since the
40  members are simply a set of particles which move together
41  they don't (necessarily) define a shape. For example,
42  the members of the rigid body made from a molecular hierarchy
43  would include particles corresponding to intermediate levels
44  of the hierarchy. As a result, methods
45  that use rigid bodies usually should simply take the list of
46  particles they are interested in and then check for rigid
47  bodies internally.
48 
49  The initial reference of the rigid body is computed from
50  the coordinates, masses and radii of the particles
51  passed to the constructor, based on diagonalizing the
52  inertial tensor (which is not stored, currently).
53 
54  The rigid body radius is the farthest point of any of its
55  members from the origin of its reference frame. For rigid
56  body members, this takes into account the radius of the
57  member.
58 
59  RigidBodies can be nested (that is, a RigidBody can have
60  another RigidBody as a member). This can be useful for
61  organizational reasons as well as for accelerating
62  computations since operations are affected by
63  the total number of children contained in the rigid body
64  being operated on. Examples of this include collision detection
65  where if you have multiple representations of geometry at
66  different resolutions it is faster to put each of them
67  in a separate rigid body and then create one rigid body
68  containing all of them.
69 
70  It is often desirable to randomize the orientation of a rigid
71  body:
72  \include randomize_rigid_body.py
73 
74  \usesconstraint
75 
76  \see RigidMember
77  \see NonRigidMember
78  \see RigidBodyMover
79  \see RigidClosePairsFinder
80  \see RigidBodyDistancePairScore
81  */
82 class IMPCOREEXPORT RigidBody : public XYZ {
83  private:
84  /* Computes the coordinates of p given its internal (local)
85  coordinates and the current position and orientation of the
86  rigid body.
87  */
89 
90  void add_member_internal(Particle *p,
91  const algebra::ReferenceFrame3D &rf);
92 
93  //! do updates to rigid body upon changes in its members
94  //! such as updating the rigid body radius based on the
95  //! point/sphere distance of all of its point/sphere members
96  //! from its origin
97  void on_change();
98 
99  static void teardown_constraints(Particle *p);
100 
101  static ObjectKey get_constraint_key_0();
102 
103  static ObjectKey get_constraint_key_1();
104 
105  // setup rigid body attributes with particles in ps, using their
106  // center of mass, inertia tensor to initialize the reference frame
107  static void do_setup_particle(Model *m, ParticleIndex pi,
109 
110  // setup a rigid body with specified reference frame
111  static void do_setup_particle(Model *m, ParticleIndex pi,
112  const algebra::ReferenceFrame3D &rf);
113 
114  void setup_score_states();
115 
116  // add a member associated with xyz coords (if it has a ref frame,
117  // it is still being ignored)
118  void add_point_member(ParticleIndex pi);
119 
120  // add a member associated with a reference frame
121  void add_rigid_body_member(ParticleIndex pi);
122 
123  public:
124  RigidMembers get_rigid_members() const;
125 
126  //! Get keys for rotation quaternion.
128  return internal::rigid_body_data().quaternion_;
129  }
130 
131  //! Returns a list of all members that are not themselves decorated as
132  //! rigid bodies, in the form of particle indexes.
134  static ParticleIndexes empty;
135  if (get_model()->get_has_attribute(internal::rigid_body_data().members_,
136  get_particle_index())) {
137  return get_model()->get_attribute(internal::rigid_body_data().members_,
139  } else {
140  return empty;
141  }
142  }
143 
144  //! Get all members that are themselves decorated as rigid bodies,
145  //! as model particle indexes
147  static ParticleIndexes empty;
148  if (get_model()->get_has_attribute(
149  internal::rigid_body_data().body_members_, get_particle_index())) {
150  return get_model()->get_attribute(
151  internal::rigid_body_data().body_members_, get_particle_index());
152  } else {
153  return empty;
154  }
155  }
156 
157  //! Get the particle indexes of any member of this rigid body, regardless
158  //! of whether it is itself a rigid body or not
160  return get_member_particle_indexes() + get_body_member_particle_indexes();
161  }
162 
164 
165  /**
166  Create a rigid body for pi with the particle indexes ps as its members.
167  The coordinates of pi are set to the center of mass of ps and the rotation
168  of its reference frame is based on the diagonalized inertia tensor of ps.
169 
170  @note If size(ps)=1, then its reference frame is copied if it is a
171  rigid body, or its rotation is set to identity if it is not
172  a rigid body.
173  */
175 
176  /**
177  Create a rigid body with the passed reference frame as its initial
178  position.
179  */
181 
182  //! Make the rigid body no longer rigid.
183  static void teardown_particle(RigidBody rb);
184 
185  IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(RigidBody);
186  ~RigidBody();
187 
188  //! Return true if the particle is a rigid body
189  static bool get_is_setup(Model *m, ParticleIndex pi) {
190  return internal::get_has_required_attributes_for_body(m, pi);
191  }
192 
193  // swig doesn't support using, so the method is wrapped
194  //! Get the coordinates of the particle
195  //! (= translation from local to global rigid body coordinates)
197 
198  //! returns the rotation of the particle
199  //! (= rotation from local to global rigid body orientation)
201  return get_reference_frame().get_transformation_to().get_rotation();
202  }
203 
204  //! Get the reference frame of this rigid body, which enables
205  //! trnasformation between the local rigid body coordinates
206  //! global coordinates
209  get_model()->get_attribute(internal::rigid_body_data().quaternion_[0],
211  get_model()->get_attribute(internal::rigid_body_data().quaternion_[1],
213  get_model()->get_attribute(internal::rigid_body_data().quaternion_[2],
215  get_model()->get_attribute(internal::rigid_body_data().quaternion_[3],
216  get_particle_index()));
217  IMP_USAGE_CHECK_FLOAT_EQUAL(v.get_squared_magnitude(), 1,
218  "Rotation is not a unit vector: " << v);
219  /*if (v.get_squared_magnitude() > 0){
220  v = v.get_unit_vector();
221  } else {
222  v = algebra::VectorD<4>(1,0,0,0);
223  }*/
224  bool assume_normalized = true;
225  IMP::algebra::Rotation3D rot(v, assume_normalized);
228  }
229 
230  //! Set the current reference frame
231  /** All members of the rigid body will have their coordinates updated
232  immediately.
233  \see IMP::core::transform(RigidBody,const algebra::Transformation3D&)
234  \see set_reference_frame_lazy()
235  */
236  void set_reference_frame(const IMP::algebra::ReferenceFrame3D &tr);
237 
238  //! Change the reference, delay updating the members until evaluate
239  /** \see set_reference_frame()
240  */
241  inline void set_reference_frame_lazy
243  {
246  get_particle()->set_value(internal::rigid_body_data().quaternion_[0], v[0]);
247  get_particle()->set_value(internal::rigid_body_data().quaternion_[1], v[1]);
248  get_particle()->set_value(internal::rigid_body_data().quaternion_[2], v[2]);
249  get_particle()->set_value(internal::rigid_body_data().quaternion_[3], v[3]);
251  }
252 
253 #ifndef SWIG
254 #ifndef IMP_DOXYGEN
255  //! 'expert' method for setting the reference more quickly
256  //! use at own risk
257  inline void set_rotation_lazy_using_internal_tables
258  (const IMP::algebra::Rotation3D &rot,
259  double* quaternion_tables[])
260  {
262  rot.get_quaternion();
263  int pi=get_particle_index().get_index();
264  quaternion_tables[0][pi]=v[0];
265  quaternion_tables[1][pi]=v[1];
266  quaternion_tables[2][pi]=v[2];
267  quaternion_tables[3][pi]=v[3];
268  }
269 
270  //! 'expert' method for setting the reference more quickly
271  //! use at own risk
272  inline void apply_rotation_lazy_using_internal_tables
273  (const IMP::algebra::Rotation3D &rot,
274  double* quaternion_tables[])
275  {
276  int pi=get_particle_index().get_index();
278  ( quaternion_tables[0][pi],
279  quaternion_tables[1][pi],
280  quaternion_tables[2][pi],
281  quaternion_tables[3][pi] );
283  (cur_rot*rot).get_quaternion();;
284  quaternion_tables[0][pi]=v[0];
285  quaternion_tables[1][pi]=v[1];
286  quaternion_tables[2][pi]=v[2];
287  quaternion_tables[3][pi]=v[3];
288  }
289 
290 #endif // IMP_DOXYGEN
291 #endif // SWIG
292 
293 
294 
295 
296  /** Update the reference frame of the rigid body based on aligning
297  the current global coordinates of the passed rigid body members
298  onto their old local coordinates. Non-passed members are ignored.
299 
300  This method is useful for updating the rigid body after new
301  global coordinates were loaded for the members. The members are
302  passed explicitly since, typically, some are desired to just
303  move along with the newly loaded rigid body.
304 
305  \note This requires at least three members that are not colinear
306  to work.
307  */
308  void set_reference_frame_from_members(const ParticleIndexes &members);
309 
310  //! Pull back global adjoints from members.
311  /** Adjoints (reverse-mode sensitivities) are partial derivatives of the
312  score with respect to intermediate values in the scoring function
313  computation, such as the global coordinates of a bead within a rigid
314  body or the global reference frame of a nested rigid body.
315 
316  This function pulls back (back-propagates) global adjoints and local
317  torque on all members to the global rotation, global coordinates, and
318  local torque on this rigid body and the internal coordinates and
319  rotation of any non-rigid members.
320 
321  This is called by an internal score state after scoring function
322  evaluation and is not meant to be called by the user.
323  */
324  void pull_back_members_adjoints(DerivativeAccumulator &da);
325 
326  //! Pull back global adjoints from member that is a point.
327  /**
328  @param pi index of member particle
329  @param da accumulator for the adjoints
330  */
331  void pull_back_member_adjoints(ParticleIndex pi,
332  DerivativeAccumulator &da);
333 
334 #ifndef SWIG
335  /** Same as above, but uses fewer allocations.
336 
337  @param pi index of member particle
338  @param T transformation from this body's local coordinates to global
339  @param x local coordinates of the member
340  @param Dy adjoint on the member's global coordinates
341  @param Dx adjoint on the member's local coordinates
342  @param DT adjoint on the transformation
343  @param xtorque torque contribution from Dy in local coordinates
344  @param da accumulator for the adjoints
345  */
346  void pull_back_member_adjoints(ParticleIndex pi,
347  const algebra::Transformation3D &T,
349  algebra::Vector3D &Dy,
350  algebra::Vector3D &Dx,
351  algebra::Transformation3DAdjoint &DT,
352  algebra::Vector3D &xtorque,
353  DerivativeAccumulator &da);
354 #endif
355 
356  //! Pull back global adjoints from member that is also a rigid body.
357  /**
358  @param pi index of member particle
359  @param da accumulator for the adjoints
360  */
361  void pull_back_body_member_adjoints(ParticleIndex pi,
362  DerivativeAccumulator &da);
363 
364 #ifndef SWIG
365  /** Same as above, but uses fewer allocations.
366 
367  @param pi index of member particle
368  @param TA transformation from this body's local coordinates to global
369  @param TB transformation from member's local coordinates to this
370  body's local coordinates
371  @param DTC adjoint on composition of TA and TB, which is the
372  transformation from the member's local coordinates to
373  global
374  @param DTA adjoint on TA
375  @param DTB adjoint on TB
376  @param betatorque torque contribution from DTC in local coordinates at
377  beta, the position of the member in local coordinates.
378  @param da accumulator for the adjoints
379  */
380  void pull_back_body_member_adjoints(ParticleIndex pi,
381  const algebra::Transformation3D &TA,
382  algebra::Transformation3D &TB,
383  algebra::Transformation3DAdjoint &DTC,
384  algebra::Transformation3DAdjoint &DTA,
385  algebra::Transformation3DAdjoint &DTB,
386  algebra::Vector3D &betatorque,
387  DerivativeAccumulator &da);
388 #endif
389 
390  /** Update the translational and rotational derivatives
391  on the rigid body center of mass, using the Cartesian derivative
392  vector at a speicified location (the point where the force is
393  being applied).
394 
395  Updates both the quaternion derivatives and the torque.
396 
397  @param local_derivative The derivative vector in local rigid body coordinates
398  @param local_location The location where the derivative is taken in local
399  rigid body coordinates
400  @param da Accumulates the output derivative over the rigid body
401  center of mass (translation and rotation torque, quaternion)
402  */
403  IMPCORE_DEPRECATED_METHOD_DECL(2.12)
404  void add_to_derivatives(const algebra::Vector3D &local_derivative,
405  const algebra::Vector3D &local_location,
406  DerivativeAccumulator &da);
407 
408  /** Faster version of the above, if all is cached.
409 
410  @param local_derivative The derivative vector in local rigid body coordinates
411  @param global_derivative The derivative vector in global coordinates
412  @param local_location The location where the derivative is taken in local
413  rigid body coordinates
414  @param rot_local_to_global Rotation matrix from local rigid body to
415  global coordinates
416  @param da Accumulates the output derivative over the rigid body
417  center of mass (translation and rotation torque, quaternion)
418  */
419  IMPCORE_DEPRECATED_METHOD_DECL(2.12)
420  void add_to_derivatives(const algebra::Vector3D &local_derivative,
421  const algebra::Vector3D &global_derivative,
422  const algebra::Vector3D &local_location,
423  const algebra::Rotation3D &rot_local_to_global,
424  DerivativeAccumulator &da);
425 
426  /** Update the rotational derivatives from another body specified by the
427  rotation from the other body's local coordinates to this body's local
428  coordinates. The provided quaternion derivative on the other body are in
429  the reference frame of the other body.
430 
431  Updates only quaternion derivatives.
432 
433  @param other_qderiv The derivative on the quaternion taking the other body's
434  local coordinates to global.
435  @param rot_other_to_local Rotation taking the local coordinates of the other body
436  to this body's local coordinates.
437  @param rot_local_to_global Rotation taking this rigid body's local coordinates to
438  global coordinates.
439  @param da Accumulates the output derivatives.
440  */
441  IMPCORE_DEPRECATED_METHOD_DECL(2.12)
442  void add_to_rotational_derivatives(const algebra::Vector4D &other_qderiv,
443  const algebra::Rotation3D &rot_other_to_local,
444  const algebra::Rotation3D &rot_local_to_global,
445  DerivativeAccumulator &da);
446 
447  /** Add to quaternion derivative of this rigid body
448  Note that this method does not update the torque.
449 
450  @param qderiv Derivative wrt to quaternion taking local coordinates to
451  global.
452  @param da Object for accumulating derivatives
453  */
454  inline void add_to_rotational_derivatives(const algebra::Vector4D &qderiv,
455  DerivativeAccumulator &da);
456 
457  /** Add torque to derivative table of this rigid body
458  Note that this method does not update the quaternion derivatives, so should
459  be used by optimizers that rely on torque only (e.g. BrownianDynamics)
460 
461  @param torque_local Torque vector in local reference frame,
462  in units of kCal/Mol/Radian
463  @param da Object for accumulating derivatives
464  */
465  inline void add_to_torque(const algebra::Vector3D &torque_local,
466  DerivativeAccumulator &da);
467 
468 
469  /** The units are kCal/Mol/Radian */
470  algebra::Vector3D get_torque() const {
471  algebra::Vector3D ret;
472  for (unsigned int i = 0; i < 3; ++i) {
473  ret[i] = get_model()->get_derivative(
474  internal::rigid_body_data().torque_[i], get_particle_index());
475  }
476  return ret;
477  }
478 
479 #if !defined(SWIG) && !defined(IMP_DOXYGEN)
480  //! expert method for fast const-access to internal torque
481  //! of coordinate #i table
482  static double const* access_torque_i_data
483  (IMP::Model const* m, unsigned int i)
484  {
485  IMP_USAGE_CHECK(i<3,"torque is 3 dimensional");
486  FloatKey k=
487  internal::rigid_body_data().torque_[i];
488  double const* ret=m->access_derivative_data(k);
489  return ret;
490  }
491 
492  //! expert method for fast access to internal torque
493  //! of coordinate #i table
494  static double* access_torque_i_data
495  (IMP::Model* m, unsigned int i)
496  {
497  IMP_USAGE_CHECK(i<3,"torque is 3 dimensional");
498  FloatKey k=
499  internal::rigid_body_data().torque_[i];
500  double* ret=m->access_derivative_data(k);
501  return ret;
502  }
503 
504  //! expert method for fast const-access to internal quaternion coordinate #i table
505  static double const* access_quaternion_i_data
506  (IMP::Model const* m, unsigned int i)
507  {
508  IMP_USAGE_CHECK(i<4,"quaternion is 4 dimensional");
509  FloatKey k=
510  internal::rigid_body_data().quaternion_[i];
511  double const* ret=m->FloatAttributeTable::access_attribute_data(k);
512  return ret;
513  }
514 
515  //! expert method for fast access to internal quaternion coordinate #i table
516  static double* access_quaternion_i_data
517  (IMP::Model* m, unsigned int i)
518  {
519  IMP_USAGE_CHECK(i<4,"quaternion is 4 dimensional");
520  FloatKey k=
521  internal::rigid_body_data().quaternion_[i];
522  double* ret=m->FloatAttributeTable::access_attribute_data(k);
523  return ret;
524  }
525 
526 
527 #endif
528 
529  //! Returns true if the rigid body coordinates are flagged as
530  //! optimized for Optimizer objects
531  bool get_coordinates_are_optimized() const;
532 
533  //! Set whether the rigid body coordinates are flagged as optimized
534  //! for Optimizer objects
535  void set_coordinates_are_optimized(bool tf);
536 
537  //! Normalize the quaternion
538  void normalize_rotation();
539 
540  //! Update the global coordinates of the members based on
541  //! their local coordinates and this rigid body's reference frame
542  void update_members();
543 
544  //! Get the derivatives of the quaternion
545  algebra::VectorD<4> get_rotational_derivatives() const;
546 
547 #ifndef IMP_DOXYGEN
548  unsigned int get_number_of_members() const {
549  return get_body_member_particle_indexes().size() +
550  get_member_particle_indexes().size();
551  }
552 
553  RigidBodyMember get_member(unsigned int i) const;
554 #endif
555  //! Add a proper member that moves rigidly with this rigid body,
556  //! properly handling rigid bodies and XYZ particles.
557  /**
558  Add p to the list of members. If p is a valid RigidBody, it is added
559  as a rigid body member, otherwise it is added as a point member
560  (for which the rotation is not tracked). By default, p is considered
561  a strictly rigid member, in that its local coordinates are not expected
562  to change independently.
563 
564  The radius of the rigid body is updated to reflect the new member.
565 
566  \see add_non_rigid_member
567  */
568  void add_member(ParticleIndexAdaptor p);
569 
570  /** Add a non-rigid member, for which internal coordinates may change
571  independently.
572 
573  @note Currently RigidBody non-rigid members are not handled properly.
574  */
575  void add_non_rigid_member(ParticleIndexAdaptor p);
576 
577  /** Set whether a particular member is flagged as a rigid member
578  or as a non-rigid member. This affects the way the rigid body
579  updates the coordinates and / or reference frame of its members.
580 
581  The radius of the rigid body is updated to reflect this change.
582  */
583  void set_is_rigid_member(ParticleIndex pi, bool tf);
584 };
585 
586 #ifndef IMP_DOXYGEN
587 // inline implementation
588 void RigidBody::add_to_rotational_derivatives(const algebra::Vector4D &qderiv,
589  DerivativeAccumulator &da) {
590  for (unsigned int i = 0; i < 4; ++i) {
591  get_model()->add_to_derivative(internal::rigid_body_data().quaternion_[i],
592  get_particle_index(), qderiv[i], da);
593  }
594 }
595 
596 
597 // inline implementation
598 void RigidBody::add_to_torque(const algebra::Vector3D &torque_local,
599  DerivativeAccumulator &da) {
600  for (unsigned int i = 0; i < 3; ++i) {
601  get_model()->add_to_derivative(internal::rigid_body_data().torque_[i],
602  get_particle_index(), torque_local[i], da);
603  }
604 }
605 
606 #endif
607 
608 
609 /** It is often useful to store precalculated properties of the rigid body
610  for later use. These need to be cleared out when the rigid body changes.
611  To make sure this happens, register the key here.
612 */
613 void IMPCOREEXPORT add_rigid_body_cache_key(ObjectKey k);
614 
615 //! A member of a rigid body, it has internal (local) coordinates
616 class IMPCOREEXPORT RigidBodyMember : public XYZ {
618 
619  RigidBody get_rigid_body() const;
620 
621  //! Return the internal (local) coordinates of this member
622  /** These coordinates are relative to the reference frame of the
623  rigid body that owns it
624  */
626  return get_model()->get_internal_coordinates(get_particle_index());
627  }
628 
629  //! set the internal (local) coordinates for this member
631  get_model()->get_internal_coordinates(get_particle_index()) = v;
632  get_rigid_body().get_model()->clear_particle_caches(get_particle_index());
633  }
634 
635  //! Set the internal (local) coordinates of this member,
636  //! assuming it is a rigid body itself
637  /** Set the internal (local) coordinates of this rigid body
638  relative to the reference frame of the rigid body that owns it
639  */
642  get_model()->get_has_attribute(
643  internal::rigid_body_data().lquaternion_[0], get_particle_index()),
644  "Can only set the internal transformation if member is"
645  << " a rigid body itself.");
646  set_internal_coordinates(v.get_translation());
647 
648  get_model()->set_attribute(internal::rigid_body_data().lquaternion_[0],
650  v.get_rotation().get_quaternion()[0]);
651  get_model()->set_attribute(internal::rigid_body_data().lquaternion_[1],
653  v.get_rotation().get_quaternion()[1]);
654  get_model()->set_attribute(internal::rigid_body_data().lquaternion_[2],
656  v.get_rotation().get_quaternion()[2]);
657  get_model()->set_attribute(internal::rigid_body_data().lquaternion_[3],
659  v.get_rotation().get_quaternion()[3]);
660  get_rigid_body().get_model()->clear_particle_caches(get_particle_index());
661  }
662 
663  //! Return the internal (local) coordinates of this member,
664  //! assuming it is a rigid body itself
665  /** Return the internal (local) coordinates of this rigid body
666  relative to the reference frame of the rigid body that owns it
667  */
670  get_model()->get_has_attribute(
671  internal::rigid_body_data().lquaternion_[0], get_particle_index()),
672  "Can only set the internal transformation if member is a "
673  << "rigid body itself.");
674  algebra::Vector3D tr =
675  get_model()->get_internal_coordinates(get_particle_index());
677  get_model()->get_attribute(internal::rigid_body_data().lquaternion_[0],
679  get_model()->get_attribute(internal::rigid_body_data().lquaternion_[1],
681  get_model()->get_attribute(internal::rigid_body_data().lquaternion_[2],
683  get_model()->get_attribute(internal::rigid_body_data().lquaternion_[3],
684  get_particle_index()));
685  return algebra::Transformation3D(rot, tr);
686  }
687 
688  ~RigidBodyMember();
689  //! sets the global coordinates of this member using XYZ::set_coordinates()
690  // this is here since swig does like using statements
691  void set_coordinates(const algebra::Vector3D &center) {
692  XYZ::set_coordinates(center);
693  }
694 
695 #ifndef IMP_DOXYGEN
696  //! Set the global coordinates from the internal coordinates,
697  //! using tr as a reference frame
699  set_coordinates(tr.get_transformed(get_internal_coordinates()));
700  }
701 #endif
702  IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(RigidBodyMember);
703 
704  //! return true if it is a rigid member
706  return internal::get_has_required_attributes_for_member(m, p);
707  }
708 
709  static FloatKeys get_internal_coordinate_keys() {
710  return internal::rigid_body_data().child_keys_;
711  }
712 
713  static FloatKeys get_internal_rotation_keys() {
714  return internal::rigid_body_data().lquaternion_;
715  }
716 };
717 
718 //! A decorator for a particle that is part of a rigid body, and is
719 //! actually rigid
720 /**
721  RigidMember particles, as opposed to NonRigidMember particles, are
722  not expected to change their internal (local) coordinates or
723  reference frames, and their global coordinates are expected to
724  change only through setting the coordinates (or reference frame) of
725  the rigid body that owns them.
726 
727  \see RigidBody
728  */
729 class IMPCOREEXPORT RigidMember : public RigidBodyMember {
730  public:
732 
733  IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(RigidMember);
734  ~RigidMember();
735 
736  //! return true if it is a rigid member
738  return internal::get_has_required_attributes_for_rigid_member(m, p);
739  }
740 };
741 
742 //! A decorator for a particle that is part of a rigid body but not rigid
743 /** NonRigidMembers, like RigidMembers, have internal coordinates and move
744  along with the rigid body. However, it is expected that their internal
745  coordinates will change, and so they are not part of structures that
746  assume rigidity.
747 
748  \see RigidBody
749  */
750 class IMPCOREEXPORT NonRigidMember : public RigidBodyMember {
751  public:
753  IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(NonRigidMember);
754  ~NonRigidMember();
755 
756  //! return true if it is a rigid member
757  static bool get_is_setup(Model *m, ParticleIndex p) {
758  return internal::get_has_required_attributes_for_non_member(m, p);
759  }
760 
761  //! Add to derivatives of local coordinates.
762  /** @param deriv_parent The derivative vector in local coordinates of the
763  parent rigid body.
764  @param da Accumulates the derivative over the local translation.
765  */
767  DerivativeAccumulator &da) {
768  for (unsigned int i = 0; i < 3; ++i) {
769  get_model()->add_to_derivative(get_internal_coordinate_keys()[i],
770  get_particle_index(), deriv_parent[i], da);
771  }
772  }
773 
774  /** Update the rotational derivatives of the internal transformation.
775 
776  Updates only local quaternion derivatives.
777 
778  @param local_qderiv The derivative on the quaternion taking this non-rigid
779  body's local coordinates to global.
780  @param rot_local_to_parent Rotation taking the local coordinates of the non-rigid
781  body to its parent's.
782  @param rot_parent_to_global Rotation taking the parent rigid body's local coordinates
783  to global coordinates.
784  @param da Accumulates the output derivatives.
785  */
786  IMPCORE_DEPRECATED_METHOD_DECL(2.12)
787  void add_to_internal_rotational_derivatives(
788  const algebra::Vector4D &local_qderiv,
789  const algebra::Rotation3D &rot_local_to_parent,
790  const algebra::Rotation3D &rot_parent_to_global,
792 
793  /** Add to internal quaternion derivatives of this non-rigid body
794 
795  @param qderiv Derivative wrt to quaternion taking local coordinates to
796  parent.
797  @param da Object for accumulating derivatives
798  */
799  void add_to_internal_rotational_derivatives(const algebra::Vector4D &qderiv,
800  DerivativeAccumulator &da) {
802  get_model()->get_has_attribute(
803  get_internal_rotation_keys()[0], get_particle_index()),
804  "Can only set derivatives of internal rotation if member is a "
805  << "rigid body itself.");
806  for (unsigned int i = 0; i < 4; ++i) {
807  get_model()->add_to_derivative(get_internal_rotation_keys()[i],
808  get_particle_index(), qderiv[i], da);
809  }
810  }
811 
812 
813  //! Get derivatives wrt translation component of internal transformation.
815  algebra::Vector3D ret;
816  for (unsigned int i = 0; i < 3; ++i) {
817  ret[i] = get_model()->get_derivative(
818  get_internal_coordinate_keys()[i], get_particle_index());
819  }
820  return ret;
821  }
822 
823  //! Get derivatives wrt quaternion component of internal transformation.
825  algebra::Vector4D ret;
826  for (unsigned int i = 0; i < 4; ++i) {
827  ret[i] = get_model()->get_derivative(
828  get_internal_rotation_keys()[i], get_particle_index());
829  }
830  return ret;
831  }
832 };
833 
834 #ifndef IMP_DOXYGEN
835 
836 class IMPCOREEXPORT RigidMembersRefiner : public Refiner {
837  public:
838  RigidMembersRefiner(std::string name = "RigidMembersRefiner%d")
839  : Refiner(name) {}
840  virtual bool get_can_refine(Particle *) const IMP_OVERRIDE;
841 #ifndef SWIG
842  using Refiner::get_refined;
843 #endif
844  virtual const ParticlesTemp get_refined(Particle *) const
845  IMP_OVERRIDE;
846  virtual ModelObjectsTemp do_get_inputs(
847  Model *m, const ParticleIndexes &pis) const IMP_OVERRIDE;
848  IMP_OBJECT_METHODS(RigidMembersRefiner);
849 };
850 
851 namespace internal {
852 IMPCOREEXPORT RigidMembersRefiner *get_rigid_members_refiner();
853 }
854 #endif
855 
856 //! Transform a rigid body
857 /** The transformation is applied current conformation of the rigid
858  body, as opposed to replacing the current conformation, as in
859  RigidBody::set_reference_frame().
860 
861  \see RigidBody
862  \see algebra::Transformation3D
863 */
864 inline void transform(RigidBody a, const algebra::Transformation3D &tr) {
865  a.set_reference_frame(get_transformed(a.get_reference_frame(), tr));
866 }
867 
868 /** Compute the rigid body reference frame given a set of input particles.
869  */
870 IMPCOREEXPORT algebra::ReferenceFrame3D get_initial_reference_frame(
871  Model *m, const ParticleIndexes &pis);
872 
873 inline algebra::ReferenceFrame3D get_initial_reference_frame(
874  const ParticlesTemp &ps) {
875  if (ps.empty()) {
876  return algebra::ReferenceFrame3D();
877  }
878  return get_initial_reference_frame(ps[0]->get_model(),
879  get_indexes(ps));
880 }
881 
882 /** Create a set of rigid bodies that are bound together for efficiency.
883  These rigid bodies cannot nest or have other dependencies among them.
884 
885  All rigid bodies have the default reference frame.
886 
887  \note Do not use this with DOMINO as all the rigid bodies use the same
888  ScoreState and so will be considered inter-dependent.
889 */
890 IMPCOREEXPORT ParticlesTemp create_rigid_bodies(Model *m,
891  unsigned int n,
892  bool no_members =
893  false);
894 
895 IMP_DECORATORS_DEF(RigidMember, RigidMembers);
896 IMP_DECORATORS(RigidBody, RigidBodies, XYZs);
897 
898 /** Show the rigid body hierarchy rooted at passed body. */
899 IMPCOREEXPORT void show_rigid_body_hierarchy(RigidBody rb,
900  TextOutput out =
901  TextOutput(std::cout));
902 
903 //! Return the index of the outer-most rigid body containing the member.
904 /** Use this to, for example, group particles into rigid bodies. */
905 IMPCOREEXPORT ParticleIndex get_root_rigid_body(RigidMember m);
906 
907 IMPCORE_END_NAMESPACE
908 
909 #endif /* IMPCORE_RIGID_BODIES_H */
void set_internal_coordinates(const algebra::Vector3D &v) const
set the internal (local) coordinates for this member
Definition: rigid_bodies.h:630
A Modifier on ParticlesTemp.
Simple 3D transformation class.
ParticleIndex get_particle_index() const
Returns the particle index decorated by this decorator.
Definition: Decorator.h:188
algebra::Vector3D get_internal_derivatives() const
Get derivatives wrt translation component of internal transformation.
Definition: rigid_bodies.h:814
algebra::Vector4D get_internal_rotational_derivatives() const
Get derivatives wrt quaternion component of internal transformation.
Definition: rigid_bodies.h:824
Key< 0 > FloatKey
The type used to identify float attributes in the Particles.
Definition: base_types.h:32
A member of a rigid body, it has internal (local) coordinates.
Definition: rigid_bodies.h:616
A container for Singletons.
ParticleIndex get_root_rigid_body(RigidMember m)
Return the index of the outer-most rigid body containing the member.
#define IMP_USAGE_CHECK_FLOAT_EQUAL(expra, exprb, message)
Definition: check_macros.h:178
algebra::Vector3D get_coordinates() const
Definition: rigid_bodies.h:196
IMP::algebra::Rotation3D get_rotation() const
Definition: rigid_bodies.h:200
#define IMP_DECORATOR_SETUP_1(Name, FirstArgumentType, first_argument_name)
#define IMP_OBJECT_METHODS(Name)
Define the basic things needed by any Object.
Definition: object_macros.h:25
Model * get_model() const
Returns the Model containing the particle.
Definition: Decorator.h:191
ParticlesTemp create_rigid_bodies(Model *m, unsigned int n, bool no_members=false)
Index< ParticleIndexTag > ParticleIndex
Definition: base_types.h:158
bool get_coordinates_are_optimized() const
Get whether the coordinates are optimized.
Definition: XYZ.h:89
static FloatKeys get_rotation_keys()
Get keys for rotation quaternion.
Definition: rigid_bodies.h:127
void add_rigid_body_cache_key(ObjectKey k)
A more IMP-like version of the std::vector.
Definition: Vector.h:39
const Vector4D & get_quaternion() const
Return the quaternion so that it can be stored.
Definition: Rotation3D.h:230
Simple XYZ decorator.
VectorD< 4 > Vector4D
Definition: VectorD.h:425
A reference frame in 3D.
void show_rigid_body_hierarchy(RigidBody rb, TextOutput out=TextOutput(std::cout))
void clear_particle_caches(ParticleIndex pi)
Clear all the cache attributes of a given particle.
IMP::Vector< IMP::WeakPointer< ModelObject > > ModelObjectsTemp
Definition: base_types.h:86
Class for storing model, its restraints, constraints, and particles.
Definition: Model.h:72
const Rotation3D & get_rotation() const
Return the rotation associated with this transformation.
static bool get_is_setup(Model *m, ParticleIndexAdaptor p)
return true if it is a rigid member
Definition: rigid_bodies.h:737
virtual bool get_can_refine(Particle *) const
Return true if this refiner can refine that particle.
Definition: Refiner.h:51
void set_reference_frame(const IMP::algebra::ReferenceFrame3D &tr)
Set the current reference frame.
A Cartesian vector in D-dimensions.
Definition: VectorD.h:52
Refine a particle into a list of particles.
void set_coordinates(const algebra::Vector3D &v)
set all coordinates from a vector
Definition: XYZ.h:62
const Transformation3D & get_transformation_to() const
Return transformation from local to global coordinates.
static bool get_is_setup(Model *m, ParticleIndex pi)
Return true if the particle is a rigid body.
Definition: rigid_bodies.h:189
const ParticleIndexes & get_member_particle_indexes() const
Definition: rigid_bodies.h:133
static bool get_is_setup(Model *m, ParticleIndexAdaptor p)
return true if it is a rigid member
Definition: rigid_bodies.h:705
Represent an XYZR particle with a sphere.
void set_attribute(TypeKey attribute_key, ParticleIndex particle, Type value)
set the value of particle attribute with the specified key
void add_to_internal_derivatives(const algebra::Vector3D &deriv_parent, DerivativeAccumulator &da)
Add to derivatives of local coordinates.
Definition: rigid_bodies.h:766
A decorator for a particle with x,y,z coordinates.
Definition: XYZ.h:30
const algebra::Vector3D & get_coordinates() const
Convert it to a vector.
Definition: XYZ.h:109
virtual const ParticlesTemp get_refined(Particle *a) const =0
Refine the passed particle into a set of particles.
Vector3D get_transformed(const Vector3D &o) const
Transform.
A decorator for a particle that is part of a rigid body but not rigid.
Definition: rigid_bodies.h:750
Simple 3D rotation class.
void set_internal_transformation(const algebra::Transformation3D &v)
Definition: rigid_bodies.h:640
Particle * get_particle() const
Returns the particle decorated by this decorator.
Definition: Decorator.h:171
Key< 4 > ObjectKey
The type used to identify an Object attribute.
Definition: base_types.h:48
3D rotation class.
Definition: Rotation3D.h:51
void set_coordinates_are_optimized(bool tf) const
Set whether the coordinates are optimized.
Definition: XYZ.h:95
void set_coordinates(const algebra::Vector3D &center)
sets the global coordinates of this member using XYZ::set_coordinates()
Definition: rigid_bodies.h:691
#define IMP_DECORATOR_METHODS(Name, Parent)
VectorD< 3 > Vector3D
Definition: VectorD.h:421
Abstract class to implement hierarchical methods.
Definition: Refiner.h:34
Simple 3D vector class.
Class to handle individual particles of a Model object.
Definition: Particle.h:41
#define IMP_USAGE_CHECK(expr, message)
A runtime test for incorrect usage of a class or method.
Definition: check_macros.h:168
#define IMP_DECORATORS(Name, PluralName, Parent)
Define the types for storing sets of decorators.
void transform(RigidBody a, const algebra::Transformation3D &tr)
Transform a rigid body.
Definition: rigid_bodies.h:864
A reference frame in 3D.
ParticleIndexes get_member_indexes() const
Definition: rigid_bodies.h:159
const ParticleIndexes & get_body_member_particle_indexes() const
Definition: rigid_bodies.h:146
A decorator for a rigid body.
Definition: rigid_bodies.h:82
const Vector3D & get_translation() const
Return the translation vector associated with this transformation.
algebra::Transformation3D get_internal_transformation() const
Definition: rigid_bodies.h:668
Type get_attribute(TypeKey attribute_key, ParticleIndex particle)
get the value of the particle attribute with the specified key
Decorator for a sphere-like particle.
ParticleIndexes get_indexes(const ParticlesTemp &ps)
static bool get_is_setup(Model *m, ParticleIndex p)
return true if it is a rigid member
Definition: rigid_bodies.h:757
#define IMP_OVERRIDE
Cause a compile error if this method does not override a parent method.
Class for adding derivatives from restraints to the model.
const algebra::Vector3D & get_internal_coordinates() const
Return the internal (local) coordinates of this member.
Definition: rigid_bodies.h:625
IMP::algebra::ReferenceFrame3D get_reference_frame() const
Definition: rigid_bodies.h:207