IMP logo
IMP Reference Guide  develop.c881750dcd,2026/05/12
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  It is also permissible to modify the internal coordinates of
588  non-rigid members during sampling, e.g. using IMP::core::BallMover.
589  Rigid members, on the other hand, are assumed to have fixed
590  internal coordinates.
591 
592  The radius of the rigid body is updated to reflect this change.
593  */
594  void set_is_rigid_member(ParticleIndex pi, bool tf);
595 
596  //! Remove the member from this rigid body.
597  /** The member can be either a rigid body member or a point
598  member, either rigid or non-rigid.
599 
600  The radius of the rigid body is updated to reflect the removed member.
601 
602  \throw UsageException if the given particle is not a member of this body.
603  */
604  void remove_member(ParticleIndexAdaptor p);
605 };
606 
607 #ifndef IMP_DOXYGEN
608 // inline implementation
609 void RigidBody::add_to_rotational_derivatives(const algebra::Vector4D &qderiv,
610  DerivativeAccumulator &da) {
611  for (unsigned int i = 0; i < 4; ++i) {
612  get_model()->add_to_derivative(internal::rigid_body_data().quaternion_[i],
613  get_particle_index(), qderiv[i], da);
614  }
615 }
616 
617 
618 // inline implementation
619 void RigidBody::add_to_torque(const algebra::Vector3D &torque_local,
620  DerivativeAccumulator &da) {
621  for (unsigned int i = 0; i < 3; ++i) {
622  get_model()->add_to_derivative(internal::rigid_body_data().torque_[i],
623  get_particle_index(), torque_local[i], da);
624  }
625 }
626 
627 #endif
628 
629 
630 /** It is often useful to store precalculated properties of the rigid body
631  for later use. These need to be cleared out when the rigid body changes.
632  To make sure this happens, register the key here.
633 */
634 void IMPCOREEXPORT add_rigid_body_cache_key(ObjectKey k);
635 
636 //! A member of a rigid body, it has internal (local) coordinates
637 class IMPCOREEXPORT RigidBodyMember : public XYZ {
639 
640  RigidBody get_rigid_body() const;
641 
642  //! Return the internal (local) coordinates of this member
643  /** These coordinates are relative to the reference frame of the
644  rigid body that owns it
645  */
647  return get_model()->get_internal_coordinates(get_particle_index());
648  }
649 
650  //! set the internal (local) coordinates for this member
652  get_model()->get_internal_coordinates(get_particle_index()) = v;
653  get_rigid_body().get_model()->clear_particle_caches(get_particle_index());
654  }
655 
656  //! Set the internal (local) coordinates of this member,
657  //! assuming it is a rigid body itself
658  /** Set the internal (local) coordinates of this rigid body
659  relative to the reference frame of the rigid body that owns it
660  */
663  get_model()->get_has_attribute(
664  internal::rigid_body_data().lquaternion_[0], get_particle_index()),
665  "Can only set the internal transformation if member is"
666  << " a rigid body itself.");
667  set_internal_coordinates(v.get_translation());
668 
669  get_model()->set_attribute(internal::rigid_body_data().lquaternion_[0],
671  v.get_rotation().get_quaternion()[0]);
672  get_model()->set_attribute(internal::rigid_body_data().lquaternion_[1],
674  v.get_rotation().get_quaternion()[1]);
675  get_model()->set_attribute(internal::rigid_body_data().lquaternion_[2],
677  v.get_rotation().get_quaternion()[2]);
678  get_model()->set_attribute(internal::rigid_body_data().lquaternion_[3],
680  v.get_rotation().get_quaternion()[3]);
681  get_rigid_body().get_model()->clear_particle_caches(get_particle_index());
682  }
683 
684  //! Return the internal (local) coordinates of this member,
685  //! assuming it is a rigid body itself
686  /** Return the internal (local) coordinates of this rigid body
687  relative to the reference frame of the rigid body that owns it
688  */
691  get_model()->get_has_attribute(
692  internal::rigid_body_data().lquaternion_[0], get_particle_index()),
693  "Can only set the internal transformation if member is a "
694  << "rigid body itself.");
695  algebra::Vector3D tr =
696  get_model()->get_internal_coordinates(get_particle_index());
698  get_model()->get_attribute(internal::rigid_body_data().lquaternion_[0],
700  get_model()->get_attribute(internal::rigid_body_data().lquaternion_[1],
702  get_model()->get_attribute(internal::rigid_body_data().lquaternion_[2],
704  get_model()->get_attribute(internal::rigid_body_data().lquaternion_[3],
705  get_particle_index()));
706  return algebra::Transformation3D(rot, tr);
707  }
708 
709  ~RigidBodyMember();
710  //! sets the global coordinates of this member using XYZ::set_coordinates()
711  // this is here since SWIG doesn't like "using" statements
712  void set_coordinates(const algebra::Vector3D &center) {
713  XYZ::set_coordinates(center);
714  }
715 
716 #ifndef IMP_DOXYGEN
717  //! Set the global coordinates from the internal coordinates,
718  //! using tr as a reference frame
720  set_coordinates(tr.get_transformed(get_internal_coordinates()));
721  }
722 #endif
723  IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(RigidBodyMember);
724 
725  //! return true if it is a rigid member
727  return internal::get_has_required_attributes_for_member(m, p);
728  }
729 
730  static FloatKeys get_internal_coordinate_keys() {
731  return internal::rigid_body_data().child_keys_;
732  }
733 
734  static FloatKeys get_internal_rotation_keys() {
735  return internal::rigid_body_data().lquaternion_;
736  }
737 };
738 
739 //! A decorator for a particle that is part of a rigid body, and is
740 //! actually rigid
741 /**
742  RigidMember particles, as opposed to NonRigidMember particles, are
743  not expected to change their internal (local) coordinates or
744  reference frames, and their global coordinates are expected to
745  change only through setting the coordinates (or reference frame) of
746  the rigid body that owns them.
747 
748  \see RigidBody
749  */
750 class IMPCOREEXPORT RigidMember : public RigidBodyMember {
751  public:
753 
754  IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(RigidMember);
755  ~RigidMember();
756 
757  //! return true if it is a rigid member
759  return internal::get_has_required_attributes_for_rigid_member(m, p);
760  }
761 };
762 
763 //! A decorator for a particle that is part of a rigid body but not rigid
764 /** NonRigidMembers, like RigidMembers, have internal coordinates and move
765  along with the rigid body. However, it is expected that their internal
766  coordinates will change, and so they are not part of structures that
767  assume rigidity.
768 
769  \see RigidBody
770  */
771 class IMPCOREEXPORT NonRigidMember : public RigidBodyMember {
772  public:
774  IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(NonRigidMember);
775  ~NonRigidMember();
776 
777  //! return true if it is a rigid member
778  static bool get_is_setup(Model *m, ParticleIndex p) {
779  return internal::get_has_required_attributes_for_non_member(m, p);
780  }
781 
782  //! Add to derivatives of local coordinates.
783  /** @param deriv_parent The derivative vector in local coordinates of the
784  parent rigid body.
785  @param da Accumulates the derivative over the local translation.
786  */
788  DerivativeAccumulator &da) {
789  for (unsigned int i = 0; i < 3; ++i) {
790  get_model()->add_to_derivative(get_internal_coordinate_keys()[i],
791  get_particle_index(), deriv_parent[i], da);
792  }
793  }
794 
795  /** Update the rotational derivatives of the internal transformation.
796 
797  Updates only local quaternion derivatives.
798 
799  @param local_qderiv The derivative on the quaternion taking this non-rigid
800  body's local coordinates to global.
801  @param rot_local_to_parent Rotation taking the local coordinates of the non-rigid
802  body to its parent's.
803  @param rot_parent_to_global Rotation taking the parent rigid body's local coordinates
804  to global coordinates.
805  @param da Accumulates the output derivatives.
806  */
807  IMPCORE_DEPRECATED_METHOD_DECL(2.12)
808  void add_to_internal_rotational_derivatives(
809  const algebra::Vector4D &local_qderiv,
810  const algebra::Rotation3D &rot_local_to_parent,
811  const algebra::Rotation3D &rot_parent_to_global,
813 
814  /** Add to internal quaternion derivatives of this non-rigid body
815 
816  @param qderiv Derivative wrt to quaternion taking local coordinates to
817  parent.
818  @param da Object for accumulating derivatives
819  */
820  void add_to_internal_rotational_derivatives(const algebra::Vector4D &qderiv,
821  DerivativeAccumulator &da) {
823  get_model()->get_has_attribute(
824  get_internal_rotation_keys()[0], get_particle_index()),
825  "Can only set derivatives of internal rotation if member is a "
826  << "rigid body itself.");
827  for (unsigned int i = 0; i < 4; ++i) {
828  get_model()->add_to_derivative(get_internal_rotation_keys()[i],
829  get_particle_index(), qderiv[i], da);
830  }
831  }
832 
833 
834  //! Get derivatives wrt translation component of internal transformation.
836  algebra::Vector3D ret;
837  for (unsigned int i = 0; i < 3; ++i) {
838  ret[i] = get_model()->get_derivative(
839  get_internal_coordinate_keys()[i], get_particle_index());
840  }
841  return ret;
842  }
843 
844  //! Get derivatives wrt quaternion component of internal transformation.
846  algebra::Vector4D ret;
847  for (unsigned int i = 0; i < 4; ++i) {
848  ret[i] = get_model()->get_derivative(
849  get_internal_rotation_keys()[i], get_particle_index());
850  }
851  return ret;
852  }
853 };
854 
855 #ifndef IMP_DOXYGEN
856 
857 class IMPCOREEXPORT RigidMembersRefiner : public Refiner {
858  public:
859  RigidMembersRefiner(std::string name = "RigidMembersRefiner%d")
860  : Refiner(name) {}
861  virtual bool get_can_refine(Particle *) const override;
862 #ifndef SWIG
863  using Refiner::get_refined;
864 #endif
865  virtual const ParticlesTemp get_refined(Particle *) const
866  override;
868  Model *m, const ParticleIndexes &pis) const override;
869  IMP_OBJECT_METHODS(RigidMembersRefiner);
870 };
871 
872 namespace internal {
873 IMPCOREEXPORT RigidMembersRefiner *get_rigid_members_refiner();
874 }
875 #endif
876 
877 //! Transform a rigid body
878 /** The transformation is applied current conformation of the rigid
879  body, as opposed to replacing the current conformation, as in
880  RigidBody::set_reference_frame().
881 
882  \see RigidBody
883  \see algebra::Transformation3D
884 */
885 inline void transform(RigidBody a, const algebra::Transformation3D &tr) {
887 }
888 
889 /** Compute the rigid body reference frame given a set of input particles.
890  */
891 IMPCOREEXPORT algebra::ReferenceFrame3D get_initial_reference_frame(
892  Model *m, const ParticleIndexes &pis);
893 
894 inline algebra::ReferenceFrame3D get_initial_reference_frame(
895  const ParticlesTemp &ps) {
896  if (ps.empty()) {
897  return algebra::ReferenceFrame3D();
898  }
899  return get_initial_reference_frame(ps[0]->get_model(),
900  get_indexes(ps));
901 }
902 
903 /** Create a set of rigid bodies that are bound together for efficiency.
904  These rigid bodies cannot nest or have other dependencies among them.
905 
906  All rigid bodies have the default reference frame.
907 
908  \note Do not use this with DOMINO as all the rigid bodies use the same
909  ScoreState and so will be considered inter-dependent.
910 */
911 IMPCOREEXPORT ParticlesTemp create_rigid_bodies(Model *m,
912  unsigned int n,
913  bool no_members =
914  false);
915 
916 IMP_DECORATORS_DEF(RigidMember, RigidMembers);
917 IMP_DECORATORS(RigidBody, RigidBodies, XYZs);
918 
919 /** Show the rigid body hierarchy rooted at passed body. */
920 IMPCOREEXPORT void show_rigid_body_hierarchy(RigidBody rb,
921  TextOutput out =
922  TextOutput(std::cout));
923 
924 //! Return the index of the outer-most rigid body containing the member.
925 /** Use this to, for example, group particles into rigid bodies. */
926 IMPCOREEXPORT ParticleIndex get_root_rigid_body(RigidMember m);
927 
928 IMPCORE_END_NAMESPACE
929 
930 #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:651
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:835
algebra::Vector4D get_internal_rotational_derivatives() const
Get derivatives wrt quaternion component of internal transformation.
Definition: rigid_bodies.h:845
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:637
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:758
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:726
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:787
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:771
Simple 3D rotation class.
void set_internal_transformation(const algebra::Transformation3D &v)
Definition: rigid_bodies.h:661
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:712
#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:885
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:689
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:778
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:646
IMP::algebra::ReferenceFrame3D get_reference_frame() const
Definition: rigid_bodies.h:213