IMP logo
IMP Reference Guide  develop.c4c24800fe,2026/07/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  /** Add to quaternion derivative of this rigid body
397  Note that this method does not update the torque.
398 
399  @param qderiv Derivative wrt to quaternion taking local coordinates to
400  global.
401  @param da Object for accumulating derivatives
402  */
403  inline void add_to_rotational_derivatives(const algebra::Vector4D &qderiv,
404  DerivativeAccumulator &da);
405 
406  /** Add torque to derivative table of this rigid body
407  Note that this method does not update the quaternion derivatives, so should
408  be used by optimizers that rely on torque only (e.g. BrownianDynamics)
409 
410  @param torque_local Torque vector in local reference frame,
411  in units of kCal/Mol/Radian
412  @param da Object for accumulating derivatives
413  */
414  inline void add_to_torque(const algebra::Vector3D &torque_local,
415  DerivativeAccumulator &da);
416 
417 
418  /** The units are kCal/Mol/Radian */
420  return get_model()->get_derivative(
421  internal::rigid_body_data().torque_, get_particle_index());
422  }
423 
424 #if !defined(SWIG) && !defined(IMP_DOXYGEN)
425  //! expert method for fast const-access to internal torque table
426  static algebra::Vector3D const* access_torque_data(IMP::Model const* m)
427  {
428  Vector3DDerivKey k = internal::rigid_body_data().torque_;
429  return m->access_derivative_data(k);
430  }
431 
432  //! expert method for fast access to internal torque table
433  static algebra::Vector3D *access_torque_data(IMP::Model *m)
434  {
435  Vector3DDerivKey k = internal::rigid_body_data().torque_;
436  return m->access_derivative_data(k);
437  }
438 
439  //! expert method for fast const-access to internal quaternion coordinate #i table
440  static double const* access_quaternion_i_data
441  (IMP::Model const* m, unsigned int i)
442  {
443  IMP_USAGE_CHECK(i<4,"quaternion is 4 dimensional");
444  FloatKey k=
445  internal::rigid_body_data().quaternion_[i];
446  double const* ret=m->FloatAttributeTable::access_attribute_data(k);
447  return ret;
448  }
449 
450  //! expert method for fast access to internal quaternion coordinate #i table
451  static double* access_quaternion_i_data
452  (IMP::Model* m, unsigned int i)
453  {
454  IMP_USAGE_CHECK(i<4,"quaternion is 4 dimensional");
455  FloatKey k=
456  internal::rigid_body_data().quaternion_[i];
457  double* ret=m->FloatAttributeTable::access_attribute_data(k);
458  return ret;
459  }
460 
461 
462 #endif
463 
464  //! Returns true if the rigid body coordinates are flagged as
465  //! optimized for Optimizer objects
466  bool get_coordinates_are_optimized() const;
467 
468  //! Set whether the rigid body coordinates are flagged as optimized
469  //! for Optimizer objects
470  void set_coordinates_are_optimized(bool tf);
471 
472  //! Normalize the quaternion
473  void normalize_rotation();
474 
475  //! Update the global coordinates of the members based on
476  //! their local coordinates and this rigid body's reference frame
477  void update_members();
478 
479  //! Get the derivatives of the quaternion
480  algebra::VectorD<4> get_rotational_derivatives() const;
481 
482 #ifndef IMP_DOXYGEN
483  unsigned int get_number_of_members() const {
484  return get_body_member_particle_indexes().size() +
485  get_member_particle_indexes().size();
486  }
487 
488  RigidBodyMember get_member(unsigned int i) const;
489 #endif
490  //! Add a proper member that moves rigidly with this rigid body,
491  //! properly handling rigid bodies and XYZ particles.
492  /**
493  Add p to the list of members. If p is a valid RigidBody, it is added
494  as a rigid body member, otherwise it is added as a point member
495  (for which the rotation is not tracked). By default, p is considered
496  a strictly rigid member, in that its local coordinates are not expected
497  to change independently.
498 
499  The radius of the rigid body is updated to reflect the new member.
500 
501  \see add_non_rigid_member
502  */
503  void add_member(ParticleIndexAdaptor p);
504 
505  /** Add a non-rigid member, for which internal coordinates may change
506  independently.
507 
508  @note Currently RigidBody non-rigid members are not handled properly.
509  */
510  void add_non_rigid_member(ParticleIndexAdaptor p);
511 
512  /** Set whether a particular member is flagged as a rigid member
513  or as a non-rigid member. This affects the way the rigid body
514  updates the coordinates and / or reference frame of its members.
515 
516  It is also permissible to modify the internal coordinates of
517  non-rigid members during sampling, e.g. using IMP::core::BallMover.
518  Rigid members, on the other hand, are assumed to have fixed
519  internal coordinates.
520 
521  The radius of the rigid body is updated to reflect this change.
522  */
523  void set_is_rigid_member(ParticleIndex pi, bool tf);
524 
525  //! Remove the member from this rigid body.
526  /** The member can be either a rigid body member or a point
527  member, either rigid or non-rigid.
528 
529  The radius of the rigid body is updated to reflect the removed member.
530 
531  \throw UsageException if the given particle is not a member of this body.
532  */
533  void remove_member(ParticleIndexAdaptor p);
534 };
535 
536 #ifndef IMP_DOXYGEN
537 // inline implementation
538 void RigidBody::add_to_rotational_derivatives(const algebra::Vector4D &qderiv,
539  DerivativeAccumulator &da) {
540  for (unsigned int i = 0; i < 4; ++i) {
541  get_model()->add_to_derivative(internal::rigid_body_data().quaternion_[i],
542  get_particle_index(), qderiv[i], da);
543  }
544 }
545 
546 
547 // inline implementation
548 void RigidBody::add_to_torque(const algebra::Vector3D &torque_local,
549  DerivativeAccumulator &da) {
550  get_model()->add_to_derivative(internal::rigid_body_data().torque_,
551  get_particle_index(), torque_local, da);
552 }
553 
554 #endif
555 
556 
557 /** It is often useful to store precalculated properties of the rigid body
558  for later use. These need to be cleared out when the rigid body changes.
559  To make sure this happens, register the key here.
560 */
561 void IMPCOREEXPORT add_rigid_body_cache_key(ObjectKey k);
562 
563 //! A member of a rigid body, it has internal (local) coordinates
564 class IMPCOREEXPORT RigidBodyMember : public XYZ {
566 
567  RigidBody get_rigid_body() const;
568 
569  //! Return the internal (local) coordinates of this member
570  /** These coordinates are relative to the reference frame of the
571  rigid body that owns it
572  */
574  return get_model()->get_internal_coordinates(get_particle_index());
575  }
576 
577  //! set the internal (local) coordinates for this member
579  get_model()->get_internal_coordinates(get_particle_index()) = v;
580  get_rigid_body().get_model()->clear_particle_caches(get_particle_index());
581  }
582 
583  //! Set the internal (local) coordinates of this member,
584  //! assuming it is a rigid body itself
585  /** Set the internal (local) coordinates of this rigid body
586  relative to the reference frame of the rigid body that owns it
587  */
590  get_model()->get_has_attribute(
591  internal::rigid_body_data().lquaternion_, get_particle_index()),
592  "Can only set the internal transformation if member is"
593  << " a rigid body itself.");
594  set_internal_coordinates(v.get_translation());
595 
596  get_model()->set_attribute(internal::rigid_body_data().lquaternion_,
599  get_rigid_body().get_model()->clear_particle_caches(get_particle_index());
600  }
601 
602  //! Return the internal (local) coordinates of this member,
603  //! assuming it is a rigid body itself
604  /** Return the internal (local) coordinates of this rigid body
605  relative to the reference frame of the rigid body that owns it
606  */
609  get_model()->get_has_attribute(
610  internal::rigid_body_data().lquaternion_, get_particle_index()),
611  "Can only get the internal transformation if member is a "
612  << "rigid body itself.");
613  algebra::Vector3D tr =
614  get_model()->get_internal_coordinates(get_particle_index());
616  get_model()->get_attribute(internal::rigid_body_data().lquaternion_,
617  get_particle_index()), true);
618  return algebra::Transformation3D(rot, tr);
619  }
620 
621  ~RigidBodyMember();
622  //! sets the global coordinates of this member using XYZ::set_coordinates()
623  // this is here since SWIG doesn't like "using" statements
624  void set_coordinates(const algebra::Vector3D &center) {
625  XYZ::set_coordinates(center);
626  }
627 
628 #ifndef IMP_DOXYGEN
629  //! Set the global coordinates from the internal coordinates,
630  //! using tr as a reference frame
632  set_coordinates(tr.get_transformed(get_internal_coordinates()));
633  }
634 #endif
635  IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(RigidBodyMember);
636 
637  //! return true if it is a rigid member
639  return internal::get_has_required_attributes_for_member(m, p);
640  }
641 
642  static FloatKeys get_internal_coordinate_keys() {
643  return internal::rigid_body_data().child_keys_;
644  }
645 
646  static Vector4DDerivKey get_internal_rotation_key() {
647  return internal::rigid_body_data().lquaternion_;
648  }
649 };
650 
651 //! A decorator for a particle that is part of a rigid body, and is
652 //! actually rigid
653 /**
654  RigidMember particles, as opposed to NonRigidMember particles, are
655  not expected to change their internal (local) coordinates or
656  reference frames, and their global coordinates are expected to
657  change only through setting the coordinates (or reference frame) of
658  the rigid body that owns them.
659 
660  \see RigidBody
661  */
662 class IMPCOREEXPORT RigidMember : public RigidBodyMember {
663  public:
665 
666  IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(RigidMember);
667  ~RigidMember();
668 
669  //! return true if it is a rigid member
671  return internal::get_has_required_attributes_for_rigid_member(m, p);
672  }
673 };
674 
675 //! A decorator for a particle that is part of a rigid body but not rigid
676 /** NonRigidMembers, like RigidMembers, have internal coordinates and move
677  along with the rigid body. However, it is expected that their internal
678  coordinates will change, and so they are not part of structures that
679  assume rigidity.
680 
681  \see RigidBody
682  */
683 class IMPCOREEXPORT NonRigidMember : public RigidBodyMember {
684  public:
686  IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(NonRigidMember);
687  ~NonRigidMember();
688 
689  //! return true if it is a rigid member
690  static bool get_is_setup(Model *m, ParticleIndex p) {
691  return internal::get_has_required_attributes_for_non_member(m, p);
692  }
693 
694  //! Add to derivatives of local coordinates.
695  /** @param deriv_parent The derivative vector in local coordinates of the
696  parent rigid body.
697  @param da Accumulates the derivative over the local translation.
698  */
700  DerivativeAccumulator &da) {
701  for (unsigned int i = 0; i < 3; ++i) {
702  get_model()->add_to_derivative(get_internal_coordinate_keys()[i],
703  get_particle_index(), deriv_parent[i], da);
704  }
705  }
706 
707  /** Add to internal quaternion derivatives of this non-rigid body
708 
709  @param qderiv Derivative wrt to quaternion taking local coordinates to
710  parent.
711  @param da Object for accumulating derivatives
712  */
714  DerivativeAccumulator &da) {
716  get_model()->get_has_attribute(
717  get_internal_rotation_key(), get_particle_index()),
718  "Can only set derivatives of internal rotation if member is a "
719  << "rigid body itself.");
720  get_model()->add_to_derivative(get_internal_rotation_key(),
721  get_particle_index(), qderiv, da);
722  }
723 
724 
725  //! Get derivatives wrt translation component of internal transformation.
727  algebra::Vector3D ret;
728  for (unsigned int i = 0; i < 3; ++i) {
729  ret[i] = get_model()->get_derivative(
730  get_internal_coordinate_keys()[i], get_particle_index());
731  }
732  return ret;
733  }
734 
735  //! Get derivatives wrt quaternion component of internal transformation.
737  return get_model()->get_derivative(
738  get_internal_rotation_key(), get_particle_index());
739  }
740 };
741 
742 #ifndef IMP_DOXYGEN
743 
744 class IMPCOREEXPORT RigidMembersRefiner : public Refiner {
745  public:
746  RigidMembersRefiner(std::string name = "RigidMembersRefiner%d")
747  : Refiner(name) {}
748  virtual bool get_can_refine(Particle *) const override;
749 #ifndef SWIG
750  using Refiner::get_refined;
751 #endif
752  virtual const ParticlesTemp get_refined(Particle *) const
753  override;
755  Model *m, const ParticleIndexes &pis) const override;
756  IMP_OBJECT_METHODS(RigidMembersRefiner);
757 };
758 
759 namespace internal {
760 IMPCOREEXPORT RigidMembersRefiner *get_rigid_members_refiner();
761 }
762 #endif
763 
764 //! Transform a rigid body
765 /** The transformation is applied current conformation of the rigid
766  body, as opposed to replacing the current conformation, as in
767  RigidBody::set_reference_frame().
768 
769  \see RigidBody
770  \see algebra::Transformation3D
771 */
772 inline void transform(RigidBody a, const algebra::Transformation3D &tr) {
774 }
775 
776 /** Compute the rigid body reference frame given a set of input particles.
777  */
778 IMPCOREEXPORT algebra::ReferenceFrame3D get_initial_reference_frame(
779  Model *m, const ParticleIndexes &pis);
780 
781 inline algebra::ReferenceFrame3D get_initial_reference_frame(
782  const ParticlesTemp &ps) {
783  if (ps.empty()) {
784  return algebra::ReferenceFrame3D();
785  }
786  return get_initial_reference_frame(ps[0]->get_model(),
787  get_indexes(ps));
788 }
789 
790 /** Create a set of rigid bodies that are bound together for efficiency.
791  These rigid bodies cannot nest or have other dependencies among them.
792 
793  All rigid bodies have the default reference frame.
794 
795  \note Do not use this with DOMINO as all the rigid bodies use the same
796  ScoreState and so will be considered inter-dependent.
797 */
798 IMPCOREEXPORT ParticlesTemp create_rigid_bodies(Model *m,
799  unsigned int n,
800  bool no_members =
801  false);
802 
803 IMP_DECORATORS_DEF(RigidMember, RigidMembers);
804 IMP_DECORATORS(RigidBody, RigidBodies, XYZs);
805 
806 /** Show the rigid body hierarchy rooted at passed body. */
807 IMPCOREEXPORT void show_rigid_body_hierarchy(RigidBody rb,
808  TextOutput out =
809  TextOutput(std::cout));
810 
811 //! Return the index of the outer-most rigid body containing the member.
812 /** Use this to, for example, group particles into rigid bodies. */
813 IMPCOREEXPORT ParticleIndex get_root_rigid_body(RigidMember m);
814 
815 IMPCORE_END_NAMESPACE
816 
817 #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:578
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:726
A Cartesian vector in D-dimensions.
Definition: VectorD.h:38
algebra::Vector4D get_internal_rotational_derivatives() const
Get derivatives wrt quaternion component of internal transformation.
Definition: rigid_bodies.h:736
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:564
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
void add_to_internal_rotational_derivatives(const algebra::Vector4D &qderiv, DerivativeAccumulator &da)
Definition: rigid_bodies.h:713
ParticlesTemp create_rigid_bodies(Model *m, unsigned int n, bool no_members=false)
Index< ParticleIndexTag > ParticleIndex
Definition: base_types.h:194
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)
VectorD< 4 > Vector4D
Definition: VectorD.h:411
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.
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:122
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.
algebra::Vector3D get_torque() const
Definition: rigid_bodies.h:419
static bool get_is_setup(Model *m, ParticleIndexAdaptor p)
return true if it is a rigid member
Definition: rigid_bodies.h:670
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.
Refine a particle into a list of particles.
VectorD< 3 > Vector3D
Definition: VectorD.h:407
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:638
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
Simple 3D vector class.
void add_to_internal_derivatives(const algebra::Vector3D &deriv_parent, DerivativeAccumulator &da)
Add to derivatives of local coordinates.
Definition: rigid_bodies.h:699
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:683
Simple 3D rotation class.
void set_internal_transformation(const algebra::Transformation3D &v)
Definition: rigid_bodies.h:588
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:624
#define IMP_DECORATOR_METHODS(Name, Parent)
Abstract class to implement hierarchical methods.
Definition: Refiner.h:34
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:772
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:607
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:690
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:573
IMP::algebra::ReferenceFrame3D get_reference_frame() const
Definition: rigid_bodies.h:213