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