IMP  2.1.1
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-2013 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 #include <IMP/refiner_macros.h>
14 
15 #include "XYZ.h"
16 #include "XYZR.h"
17 #include <IMP/SingletonContainer.h>
18 #include <IMP/SingletonModifier.h>
19 #include <IMP/Refiner.h>
20 #include <IMP/algebra/Vector3D.h>
21 #include <IMP/algebra/Rotation3D.h>
24 
25 IMPCORE_BEGIN_NAMESPACE
26 
27 IMP_DECORATORS_DECL(RigidMember, RigidMembers);
28 
29 //! A decorator for a rigid body
30 /** A rigid body particle describes a set of particles, known
31  as the members, which move rigidly together. The rigid body
32  is represented as an algebra::ReferenceFrame3D coupled
33  with local coordinates (RigidMember::get_internal_coordinates())
34  for the members expressed in that reference frame. The
35  global coordinates of the members are accessed, as with
36  other global coordinates, via the XYZ::get_coordinates().
37 
38  Since the
39  members are simply a set of particles which move together
40  they don't (necessarily) define a shape. For example,
41  the members of the rigid body made from a molecular hierarchy
42  would include particles corresponding to intermediate levels
43  of the hierarchy. As a result, methods
44  that use rigid bodies usually should simply take the list of
45  particles they are interested in and then check for rigid
46  bodies internally.
47 
48  The initial reference of the rigid body is computed from
49  the coordinates, masses and radii of the particles
50  passed to the constructor, based on diagonalizing the
51  inertial tensor (which is not stored, currently).
52 
53  RigidBodies can be nested (that is, a RigidBody can have
54  another RigidBody as a member). This can be useful for
55  organizational reasons as well as for accelerating
56  computations since since operations are affected by
57  the total number of children contained in the rigid body
58  being operated on. Examples of this include collision detection
59  where if you have multiple representations of geometry at
60  different resolutions it is faster to put each of them
61  in a separate rigid body and then creat one rigid body
62  containing all of them.
63 
64  It is often desirable to randomize the orientation of a rigid
65  body:
66  \include randomize_rigid_body.py
67 
68  \usesconstraint
69 
70  \see RigidMember
71  \see RigidBodyMover
72  \see RigidClosePairsFinder
73  \see RigidBodyDistancePairScore
74  */
75 class IMPCOREEXPORT RigidBody : public XYZ {
76  //! Return the location of a member particle given the current position
77  /** This method computes the coordinates of p given its internal coordinates
78  and the current position and orientation of the rigid body.
79  */
81 
82  void add_member_internal(kernel::Particle *p,
83  const algebra::ReferenceFrame3D &rf);
84  void on_change();
85  static void teardown_constraints(kernel::Particle *p);
86  static ObjectKey get_constraint_key_0();
87  static ObjectKey get_constraint_key_1();
88 
89  static void do_setup_particle(kernel::Model *m, kernel::ParticleIndex pi,
91 
92  static void do_setup_particle(kernel::Model *m, kernel::ParticleIndex pi,
93  const algebra::ReferenceFrame3D &rf);
94  void setup_score_states();
95  void add_point_member(kernel::ParticleIndex pi);
96  void add_rigid_body_member(kernel::ParticleIndex pi);
97  public:
98  RigidMembers get_members() const;
99 
100  //! Return the members as particle pointers
101  /** This member function is here for efficiency.*/
103  static kernel::ParticleIndexes empty;
104  if (get_model()->get_has_attribute(internal::rigid_body_data().members_,
105  get_particle_index())) {
106  return get_model()->get_attribute(internal::rigid_body_data().members_,
107  get_particle_index());
108  } else {
109  return empty;
110  }
111  }
112 
113  const kernel::ParticleIndexes &get_body_member_particle_indexes() const {
114  static kernel::ParticleIndexes empty;
115  if (get_model()->get_has_attribute(
116  internal::rigid_body_data().body_members_, get_particle_index())) {
117  return get_model()->get_attribute(
118  internal::rigid_body_data().body_members_, get_particle_index());
119  } else {
120  return empty;
121  }
122  }
123 
126  /** Create a rigid body with the passed reference frame as its initial
127  position. */
129 
130  //! Make the rigid body no longer rigid.
131  static void teardown_particle(RigidBody rb);
132 
133  IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(RigidBody);
134  ~RigidBody();
135 
136  /** Return true of the particle is a rigid body */
138  return internal::get_has_required_attributes_for_body(m, pi);
139  }
140 
141  // swig doesn't support using, so the method is wrapped
142  //! Get the coordinates of the particle
144 
145  //! Get the reference frame for the local coordinates
148  get_model()->get_attribute(internal::rigid_body_data().quaternion_[0],
149  get_particle_index()),
150  get_model()->get_attribute(internal::rigid_body_data().quaternion_[1],
151  get_particle_index()),
152  get_model()->get_attribute(internal::rigid_body_data().quaternion_[2],
153  get_particle_index()),
154  get_model()->get_attribute(internal::rigid_body_data().quaternion_[3],
155  get_particle_index()));
156  IMP_USAGE_CHECK_FLOAT_EQUAL(v.get_squared_magnitude(), 1,
157  "Rotation is not a unit vector: " << v);
158  /*if (v.get_squared_magnitude() > 0){
159  v = v.get_unit_vector();
160  } else {
161  v = algebra::VectorD<4>(1,0,0,0);
162  }*/
166  }
167 
168  //! Set the current reference frame
169  /** All members of the rigid body will have their coordinates updated
170  immediately.
171  \see IMP::core::transform(RigidBody,const algebra::Transformation3D&)
172  \see lazy_set_reference_frame()
173  */
174  void set_reference_frame(const IMP::algebra::ReferenceFrame3D &tr);
175 
176  //! Change the reference, delay updating the members until evaluate
177  /** See set_reference_frame()
178  */
179  void set_reference_frame_lazy(const IMP::algebra::ReferenceFrame3D &tr);
180 
181  /** Update the reference frame of the rigid body based on the current
182  coordinates of the passed members (nonpassed members are ignored).
183  This can be used to update the rigid
184  body after new coordinates were loaded for the members. The members
185  are passed explictily since, typically, some are desired to just
186  move along with the newly loaded rigid body.
187 
188  \note This requires at least three members that are not collinear
189  to work.
190  */
191  void set_reference_frame_from_members(const kernel::ParticleIndexes &members);
192 
193 #ifndef IMP_DOXYGEN
194  /** This takes a cartesian derivative, and a location in internal coordinates.
195 
196  It is currently hidden since the function signature is highly ambiguous.
197  */
198  void add_to_derivatives(const algebra::Vector3D &derivative,
199  const algebra::Vector3D &local_location,
201 
202  void add_to_derivatives(const algebra::Vector3D &derivative,
203  const algebra::Vector3D &global_derivative,
204  const algebra::Vector3D &local_location,
205  const algebra::Rotation3D &rot,
207 #endif
208 
209  /** The units are kCal/Mol/Radian */
211  algebra::Vector3D ret;
212  for (unsigned int i = 0; i < 3; ++i) {
213  ret[i] = get_model()->get_derivative(
214  internal::rigid_body_data().torque_[i], get_particle_index());
215  }
216  return ret;
217  }
218 
219  bool get_coordinates_are_optimized() const;
220 
221  //! Set whether the rigid body coordinates are optimized
222  void set_coordinates_are_optimized(bool tf);
223 
224  //! Normalized the quaternion
225  void normalize_rotation();
226 
227  //! Update the coordinates of the members
228  void update_members();
229 
230  //! Get the derivatives of the quaternion
231  algebra::VectorD<4> get_rotational_derivatives() const;
232 
233 #ifndef IMP_DOXYGEN
234  unsigned int get_number_of_members() const {
235  return get_body_member_particle_indexes().size() +
236  get_member_particle_indexes().size();
237  }
238 
239  RigidMember get_member(unsigned int i) const;
240 #endif
241  /** Add a member, properly handle rigid bodies and XYZ particles.
242  */
243  void add_member(kernel::ParticleIndexAdaptor p);
244 
245  /** Add a NonRigidMember. Currently RigidBody non-rigid members are
246  not handler properly.*/
247  void add_non_rigid_member(kernel::ParticleIndex pi);
248 
249  /** Set whether a particular member is a rigid member or a non-rigid member.*/
250  void set_is_rigid_member(kernel::ParticleIndex pi, bool tf);
251 };
252 
253 /** It is often useful to store precalculated properties of the rigid body
254  for later use. These need to be cleared out when the rigid body changes.
255  To make sure this happens, register the key here.
256 */
257 void IMPCOREEXPORT add_rigid_body_cache_key(ObjectKey k);
258 
259 //! A member of a rigid body, it has internal coordinates
260 class IMPCOREEXPORT RigidBodyMember: public XYZ {
262 
263  RigidBody get_rigid_body() const;
264 
265  //! Return the current orientation of the body
267  return get_model()->get_internal_coordinates(get_particle_index());
268  }
269 
270  //! set the internal coordinates for this member
272  get_model()->get_internal_coordinates(get_particle_index()) = v;
273  get_rigid_body().get_model()->clear_particle_caches(get_particle_index());
274  }
275 
276  //! Member must be a rigid body
279  get_model()->get_has_attribute(
280  internal::rigid_body_data().lquaternion_[0], get_particle_index()),
281  "Can only set the internal transformation if member is"
282  << " a rigid body itself.");
283  set_internal_coordinates(v.get_translation());
284 
285  get_model()->set_attribute(internal::rigid_body_data().lquaternion_[0],
286  get_particle_index(),
287  v.get_rotation().get_quaternion()[0]);
288  get_model()->set_attribute(internal::rigid_body_data().lquaternion_[1],
289  get_particle_index(),
290  v.get_rotation().get_quaternion()[1]);
291  get_model()->set_attribute(internal::rigid_body_data().lquaternion_[2],
292  get_particle_index(),
293  v.get_rotation().get_quaternion()[2]);
294  get_model()->set_attribute(internal::rigid_body_data().lquaternion_[3],
295  get_particle_index(),
296  v.get_rotation().get_quaternion()[3]);
297  get_rigid_body().get_model()->clear_particle_caches(get_particle_index());
298  }
299 
300  algebra::Transformation3D get_internal_transformation() const {
302  get_model()->get_has_attribute(
303  internal::rigid_body_data().lquaternion_[0], get_particle_index()),
304  "Can only set the internal transformation if member is a "
305  << "rigid body itself.");
306  algebra::Vector3D tr =
307  get_model()->get_internal_coordinates(get_particle_index());
309  get_model()->get_attribute(internal::rigid_body_data().lquaternion_[0],
310  get_particle_index()),
311  get_model()->get_attribute(internal::rigid_body_data().lquaternion_[1],
312  get_particle_index()),
313  get_model()->get_attribute(internal::rigid_body_data().lquaternion_[2],
314  get_particle_index()),
315  get_model()->get_attribute(internal::rigid_body_data().lquaternion_[3],
316  get_particle_index()));
317  return algebra::Transformation3D(rot, tr);
318  }
319  ~RigidBodyMember();
320  //! XYZ::set_coordiantes()
321  // this is here since swig does like using statements
322  void set_coordinates(const algebra::Vector3D &center) {
323  XYZ::set_coordinates(center);
324  }
325 
326 #ifndef IMP_DOXYGEN
327  //! Set the coordinates from the internal coordinates
329  set_coordinates(tr.get_transformed(get_internal_coordinates()));
330  }
331 #endif
332  IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(RigidBodyMember);
333 
334  //! return true if it is a rigid member
336  return internal::get_has_required_attributes_for_member(m, p);
337  }
338 
339  static FloatKeys get_internal_coordinate_keys() {
340  return internal::rigid_body_data().child_keys_;
341  }
342 
343 };
344 
345 //! A decorator for a particle that is part of a rigid body
346 /**
347  \see RigidBody
348  */
349 class IMPCOREEXPORT RigidMember : public RigidBodyMember {
350  public:
352 
353 
354  IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(RigidMember);
355  ~RigidMember();
356 
357  //! return true if it is a rigid member
359  return internal::get_has_required_attributes_for_rigid_member(m, p);
360  }
361 };
362 
363 //! A decorator for a particle that is part of a rigid body but not rigid
364 /** NonRigidMembers, like RigidMembers have internal coordinates and move
365  along with the rigid body. However, it is expected that their internal
366  coordinates will change, and so they are not part of structures that
367  assume rigidity.
368 
369  \see RigidBody
370  */
371 class IMPCOREEXPORT NonRigidMember : public RigidBodyMember {
372  public:
374  IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(NonRigidMember);
375  ~NonRigidMember();
376 
377  //! return true if it is a rigid member
379  return internal::get_has_required_attributes_for_non_member(m, p);
380  }
381 };
382 
383 #ifndef IMP_DOXYGEN
384 
385 class IMPCOREEXPORT RigidMembersRefiner : public Refiner {
386  public:
387  RigidMembersRefiner(std::string name = "RigidMembersRefiner%d")
388  : Refiner(name) {}
389  virtual bool get_can_refine(kernel::Particle *) const IMP_OVERRIDE;
390 #ifndef SWIG
391  using Refiner::get_refined;
392 #endif
393  virtual const kernel::ParticlesTemp get_refined(kernel::Particle *) const
394  IMP_OVERRIDE;
395  virtual kernel::ModelObjectsTemp do_get_inputs(
396  kernel::Model *m, const kernel::ParticleIndexes &pis) const IMP_OVERRIDE;
397  IMP_OBJECT_METHODS(RigidMembersRefiner);
398 };
399 
400 namespace internal {
401 IMPCOREEXPORT RigidMembersRefiner *get_rigid_members_refiner();
402 }
403 #endif
404 
405 //! Transform a rigid body
406 /** The transformation is applied current conformation of the rigid
407  body, as opposed to replacing the current conformation, as in
408  RigidBody::set_reference_frame().
409 
410  See RigidBody
411  algebra::Transformation3D
412 */
413 inline void transform(RigidBody a, const algebra::Transformation3D &tr) {
414  a.set_reference_frame(get_transformed(a.get_reference_frame(), tr));
415 }
416 
417 /** Compute the rigid body reference frame given a set of input particles.
418  */
420  kernel::Model *m, const kernel::ParticleIndexes &pis);
421 
423  const kernel::ParticlesTemp &ps) {
424  if (ps.empty()) {
425  return algebra::ReferenceFrame3D();
426  }
427  return get_initial_reference_frame(ps[0]->get_model(),
428  kernel::get_indexes(ps));
429 }
430 
431 /** Create a set of rigid bodies that are bound together for efficiency.
432  These rigid bodies cannot nest or have other dependencies amongst them.
433 
434  All rigid bodies have the default reference frame.
435 
436  \note Do not use this with DOMINO as all the rigid bodies use the same
437  ScoreState and so will be considered inter-dependent.
438 */
439 IMPCOREEXPORT kernel::ParticlesTemp create_rigid_bodies(kernel::Model *m,
440  unsigned int n,
441  bool no_members =
442  false);
443 
444 IMP_DECORATORS_DEF(RigidMember, RigidMembers);
445 IMP_DECORATORS(RigidBody, RigidBodies, XYZs);
446 
447 IMPCORE_END_NAMESPACE
448 
449 #endif /* IMPCORE_RIGID_BODIES_H */
void add_to_derivatives(const algebra::Vector3D &v, DerivativeAccumulator &d)
Add something to the derivative of the coordinates.
Definition: XYZ.h:81
void set_internal_coordinates(const algebra::Vector3D &v) const
set the internal coordinates for this member
Definition: rigid_bodies.h:271
Import IMP/kernel/SingletonModifier.h in the namespace.
Simple 3D transformation class.
ParticleIndexes get_indexes(const ParticlesTemp &ps)
A base class for Keys.
Definition: kernel/Key.h:46
Class for adding derivatives from restraints to the model.
virtual const ParticlesTemp get_refined(Particle *a) const =0
Refine the passed particle into a set of particles.
A member of a rigid body, it has internal coordinates.
Definition: rigid_bodies.h:260
IMP::base::Vector< IMP::base::WeakPointer< kernel::ModelObject > > ModelObjectsTemp
Import IMP/kernel/SingletonContainer.h in the namespace.
algebra::Vector3D get_coordinates() const
Get the coordinates of the particle.
Definition: rigid_bodies.h:143
static bool get_is_setup(kernel::Model *m, kernel::ParticleIndex pi)
Definition: rigid_bodies.h:137
const kernel::ParticleIndexes & get_member_particle_indexes() const
Return the members as particle pointers.
Definition: rigid_bodies.h:102
#define IMP_DECORATOR_METHODS(Name, Parent)
algebra::ReferenceFrame3D get_initial_reference_frame(kernel::Model *m, const kernel::ParticleIndexes &pis)
Model * get_model() const
Returns the Model containing the particle.
A decorator for a particle that is part of a rigid body.
Definition: rigid_bodies.h:349
bool get_coordinates_are_optimized() const
Get whether the coordinates are optimized.
Definition: XYZ.h:88
void add_rigid_body_cache_key(ObjectKey k)
#define IMP_USAGE_CHECK_FLOAT_EQUAL(expra, exprb, message)
Type get_attribute(TypeKey attribute_key, ParticleIndex particle)
const Vector4D & get_quaternion() const
Return the quaternion so that it can be stored.
Definition: Rotation3D.h:187
Simple xyz decorator.
#define IMP_USAGE_CHECK(expr, message)
A runtime test for incorrect usage of a class or method.
A reference frame in 3D.
virtual bool get_can_refine(Particle *) const
Return true if this refiner can refine that particle.
algebra::Vector3D get_torque() const
Definition: rigid_bodies.h:210
void transform(Hierarchy h, const algebra::Transformation3D &tr)
void set_reference_frame(const IMP::algebra::ReferenceFrame3D &tr)
Set the current reference frame.
Import IMP/kernel/Refiner.h in the namespace.
void set_coordinates(const algebra::Vector3D &v)
set all coordinates from a vector
Definition: XYZ.h:64
IMP::kernel::Model Model
Represent an XYZR particle with a sphere.
A decorator for a particle with x,y,z coordinates.
Definition: XYZ.h:32
#define IMP_OBJECT_METHODS(Name)
Define the basic things needed by any Object.
void set_attribute(TypeKey attribute_key, ParticleIndex particle, Type value)
static bool get_is_setup(kernel::Model *m, kernel::ParticleIndexAdaptor p)
return true if it is a rigid member
Definition: rigid_bodies.h:358
const algebra::Vector3D & get_coordinates() const
Convert it to a vector.
Definition: XYZ.h:109
Class to handle individual model 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:371
Import IMP/kernel/refiner_macros.h in the namespace.
Simple 3D rotation class.
void set_internal_transformation(const algebra::Transformation3D &v)
Member must be a rigid body.
Definition: rigid_bodies.h:277
3D rotation class.
Definition: Rotation3D.h:45
void set_coordinates_are_optimized(bool tf) const
Set whether the coordinates are optimized.
Definition: XYZ.h:94
static bool get_is_setup(kernel::Model *m, kernel::ParticleIndexAdaptor p)
return true if it is a rigid member
Definition: rigid_bodies.h:335
Key< 4, true > ObjectKey
The type used to identify an Object attribute.
void set_coordinates(const algebra::Vector3D &center)
XYZ::set_coordiantes()
Definition: rigid_bodies.h:322
IMP::kernel::Particle Particle
static bool get_is_setup(kernel::Model *m, kernel::ParticleIndex p)
return true if it is a rigid member
Definition: rigid_bodies.h:378
kernel::ParticlesTemp create_rigid_bodies(kernel::Model *m, unsigned int n, bool no_members=false)
Simple 3D vector class.
Simple 3D rotation class.
A decorator for a rigid body.
Definition: rigid_bodies.h:75
Abstract class to implement hierarchical methods.
#define IMP_DECORATOR_SETUP_1(Name, FirstArgumentType, first_argument_name)
Decorator for a sphere-like particle.
#define IMP_DECORATORS(Name, PluralName, Parent)
Define the types for storing sets of decorators.
const algebra::Vector3D & get_internal_coordinates() const
Return the current orientation of the body.
Definition: rigid_bodies.h:266
Class for storing model, its restraints, constraints, and particles.
IMP::algebra::ReferenceFrame3D get_reference_frame() const
Get the reference frame for the local coordinates.
Definition: rigid_bodies.h:146