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