IMP  2.0.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  \pythonexample{randomize_rigid_body}
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(Particle *p,
83  const algebra::ReferenceFrame3D &rf);
84  void on_change();
85  static void teardown_constraints(Particle *p);
86  static ObjectKey get_constraint_key_0();
87  static ObjectKey get_constraint_key_1();
88 public:
89 #ifndef IMP_DOXYGEN
90  RigidMembers get_members() const;
91 #endif
92  //! Return the members as particle pointers
93  /** This member function is here
94  for efficiency.*/
96  static ParticleIndexes empty;
97  if (get_model()->get_has_attribute(internal::rigid_body_data().members_,
98  get_particle_index())) {
99  return get_model()->get_attribute(internal::rigid_body_data().members_,
100  get_particle_index());
101  } else {
102  return empty;
103  }
104  }
105 
106  const ParticleIndexes& get_body_member_particle_indexes() const {
107  static ParticleIndexes empty;
108  if (get_model()
109  ->get_has_attribute(internal::rigid_body_data().body_members_,
110  get_particle_index())) {
111  return get_model()
112  ->get_attribute(internal::rigid_body_data().body_members_,
113  get_particle_index());
114  } else {
115  return empty;
116  }
117  }
118 
119  IMP_DECORATOR(RigidBody, XYZ);
120 
121  //! Create a new rigid body from a set of particles.
122  /** \param[in] p The particle to make into a rigid body
123  \param[in] ps The particles to use as members of the rigid body
124 
125  The initial position and orientation of p is computed, as are the
126  relative positions of the member particles. The member particles
127  do not already need to be RigidMember particles, only
128  XYZ particles.
129  */
130  static RigidBody setup_particle(Particle *p,
131  const ParticlesTemp &ps);
132 
133 
134  /** Set it up with the provided initial reference frame.*/
135  static RigidBody setup_particle(Particle *p,
136  const algebra::ReferenceFrame3D &rf);
137 
138  //! Make the rigid body no longer rigid.
139  static void teardown_particle(RigidBody rb);
140 
141  ~RigidBody();
142 
143  //!Return true of the particle is a rigid body
144  static bool particle_is_instance(Particle *p) {
145  return internal::get_has_required_attributes_for_body(p->get_model(),
146  p->get_index());
147  }
148 
149  //!Return true of the particle is a rigid body
151  return internal::get_has_required_attributes_for_body(m, pi);
152  }
153 
154  // swig doesn't support using, so the method is wrapped
155  //! Get the coordinates of the particle
157  return XYZ::get_coordinates();
158  }
159 
160  //! Get the reference frame for the local coordinates
163  v(get_particle()->get_value(internal::rigid_body_data().quaternion_[0]),
164  get_particle()->get_value(internal::rigid_body_data().quaternion_[1]),
165  get_particle()->get_value(internal::rigid_body_data().quaternion_[2]),
166  get_particle()->get_value(internal::rigid_body_data().quaternion_[3]));
167  IMP_USAGE_CHECK_FLOAT_EQUAL(v.get_squared_magnitude(), 1,
168  "Rotation is not a unit vector: " << v);
169  /*if (v.get_squared_magnitude() > 0){
170  v = v.get_unit_vector();
171  } else {
172  v = algebra::VectorD<4>(1,0,0,0);
173  }*/
176  get_coordinates()));
177  }
178 
179  //! Set the current reference frame
180  /** All members of the rigid body will have their coordinates updated
181  immediately.
182  \see IMP::core::transform(RigidBody,const algebra::Transformation3D&)
183  \see lazy_set_reference_frame()
184  */
185  void set_reference_frame(const IMP::algebra::ReferenceFrame3D &tr);
186 
187  //! Change the reference, delay updating the members until evaluate
188  /** See set_reference_frame()
189  */
190  void set_reference_frame_lazy(const IMP::algebra::ReferenceFrame3D &tr);
191 
192  /** Update the reference frame of the rigid body based on the current
193  coordinates of the passed members (nonpassed members are ignored).
194  This can be used to update the rigid
195  body after new coordinates were loaded for the members. The members
196  are passed explictily since, typically, some are desired to just
197  move along with the newly loaded rigid body.
198 
199  \note This requires at least three members that are not collinear
200  to work.
201  */
202  void set_reference_frame_from_members(const ParticleIndexes &members);
203 
204 #ifndef IMP_DOXYGEN
205  /** This takes a cartesian derivative, and a location in internal coordinates.
206 
207  It is currently hidden since the function signature is highly ambiguous.
208  */
209  void add_to_derivatives(const algebra::Vector3D &derivative,
210  const algebra::Vector3D &local_location,
212 
213  void add_to_derivatives(const algebra::Vector3D &derivative,
214  const algebra::Vector3D &global_derivative,
215  const algebra::Vector3D &local_location,
216  const algebra::Rotation3D &rot,
218 #endif
219 
220  /** The units are kCal/Mol/Radian */
222  algebra::Vector3D ret;
223  for (unsigned int i=0; i< 3; ++i) {
224  ret[i]
225  =get_particle()
226  ->get_derivative(internal::rigid_body_data().torque_[i]);
227  }
228  return ret;
229  }
230 
231  bool get_coordinates_are_optimized() const;
232 
233  //! Set whether the rigid body coordinates are optimized
234  void set_coordinates_are_optimized(bool tf);
235 
236  //! Normalized the quaternion
237  void normalize_rotation();
238 
239  //! Update the coordinates of the members
240  void update_members();
241 
242  //! Get the derivatives of the quaternion
243  algebra::VectorD<4> get_rotational_derivatives() const;
244 
245 #ifndef IMP_DOXYGEN
246  unsigned int get_number_of_members() const {
247  return get_body_member_particle_indexes().size()
248  + get_member_particle_indexes().size();
249  }
250 
251  RigidMember get_member(unsigned int i) const;
252 
253  /** Add a member, properly handle rigid bodies and XYZ particles.
254  */
255  void add_member(Particle *p);
256 #endif
257  /** Add a member, properly handle rigid bodies and XYZ particles.
258  */
260  add_member(get_model()->get_particle(p));
261  }
262 
263  /** Add a NonRigidMember. Currently RigidBody non-rigid members are
264  not handler properly.*/
265  void add_non_rigid_member(ParticleIndex pi);
266 
267  /** Set whether a particular member is a rigid member or a non-rigid member.*/
268  void set_is_rigid_member(ParticleIndex pi, bool tf);
269 };
270 
271 
272 /** It is often useful to store precalculated properties of the rigid body
273  for later use. These need to be cleared out when the rigid body changes.
274  To make sure this happens, register the key here.
275 */
276 void IMPCOREEXPORT add_rigid_body_cache_key(ObjectKey k);
277 
278 
279 //! A decorator for a particle that is part of a rigid body
280 /**
281  \see RigidBody
282  */
283 class IMPCOREEXPORT RigidMember: public XYZ {
284  public:
286 
287  RigidBody get_rigid_body() const;
288 
289  //! Return the current orientation of the body
291  return get_model()->get_internal_coordinates(get_particle_index());
292  }
293 
294  //! set the internal coordinates for this member
296  get_model()->get_internal_coordinates(get_particle_index())=v;
297  get_rigid_body().get_particle()->clear_caches();
298  }
299  //! Member must be a rigid body
302  get_particle()->has_attribute(internal::rigid_body_data().lquaternion_[0]),
303  "Can only set the internal transformation if member is"
304  << " a rigid body itself.");
305  set_internal_coordinates(v.get_translation());
306 
307  get_particle()->set_value(internal::rigid_body_data().lquaternion_[0],
308  v.get_rotation().get_quaternion()[0]);
309  get_particle()->set_value(internal::rigid_body_data().lquaternion_[1],
310  v.get_rotation().get_quaternion()[1]);
311  get_particle()->set_value(internal::rigid_body_data().lquaternion_[2],
312  v.get_rotation().get_quaternion()[2]);
313  get_particle()->set_value(internal::rigid_body_data().lquaternion_[3],
314  v.get_rotation().get_quaternion()[3]);
315  get_rigid_body().get_particle()->clear_caches();
316  }
317 
318  algebra::Transformation3D get_internal_transformation() const {
320  get_particle()->has_attribute(internal::rigid_body_data().lquaternion_[0]),
321  "Can only set the internal transformation if member is a "
322  << "rigid body itself.");
324  =get_model()->get_internal_coordinates(get_particle_index());
326  rot(get_particle()->get_value(internal::rigid_body_data()
327  .lquaternion_[0]),
328  get_particle()->get_value(internal::rigid_body_data()
329  .lquaternion_[1]),
330  get_particle()->get_value(internal::rigid_body_data()
331  .lquaternion_[2]),
332  get_particle()->get_value(internal::rigid_body_data()
333  .lquaternion_[3]));
334  return algebra::Transformation3D(rot, tr);
335  }
336 
337  //! XYZ::set_coordiantes()
338  // this is here since swig does like using statements
339  void set_coordinates(const algebra::Vector3D &center) {
340  XYZ::set_coordinates(center);
341  }
342 #ifndef IMP_DOXYGEN
343  //! Set the coordinates from the internal coordinates
345  set_coordinates(tr.get_transformed(get_internal_coordinates()));
346  }
347 #endif
348  ~RigidMember();
349 
350  //! return true if it is a rigid member
351  static bool particle_is_instance(Particle *p) {
352  return particle_is_instance(p->get_model(), p->get_index());
353  }
354  //! return true if it is a rigid member
356  return internal::get_has_required_attributes_for_member(m, p);
357  }
358 
359  static FloatKeys get_internal_coordinate_keys() {
360  return internal::rigid_body_data().child_keys_;
361  }
362 };
363 
364 
365 
366 
367 //! A decorator for a particle that is part of a rigid body but not rigid
368 /** NonRigidMembers, like RigidMembers have internal coordinates and move
369  along with the rigid body. However, it is expected that their internal
370  coordinates will change, and so they are not part of structures that
371  assume rigidity.
372 
373  \see RigidBody
374  */
375 class IMPCOREEXPORT NonRigidMember: public XYZ {
376  public:
378 
379  RigidBody get_rigid_body() const;
380 
381  //! Return the current orientation of the body
383  return get_model()->get_internal_coordinates(get_particle_index());
384  }
385 
386  //! set the internal coordinates for this member
388  get_model()->get_internal_coordinates(get_particle_index())=v;
389  get_rigid_body().get_particle()->clear_caches();
390  }
391 
392  //! Member must be a rigid body
395  get_particle()->has_attribute(internal::rigid_body_data().lquaternion_[0]),
396  "Can only set the internal transformation if member is"
397  << " a rigid body itself.");
398  set_internal_coordinates(v.get_translation());
399 
400  get_particle()->set_value(internal::rigid_body_data().lquaternion_[0],
401  v.get_rotation().get_quaternion()[0]);
402  get_particle()->set_value(internal::rigid_body_data().lquaternion_[1],
403  v.get_rotation().get_quaternion()[1]);
404  get_particle()->set_value(internal::rigid_body_data().lquaternion_[2],
405  v.get_rotation().get_quaternion()[2]);
406  get_particle()->set_value(internal::rigid_body_data().lquaternion_[3],
407  v.get_rotation().get_quaternion()[3]);
408  get_rigid_body().get_particle()->clear_caches();
409  }
410 
411  algebra::Transformation3D get_internal_transformation() const {
413  get_particle()->has_attribute(internal::rigid_body_data().lquaternion_[0]),
414  "Can only set the internal transformation if member is a "
415  << "rigid body itself.");
417  =get_model()->get_internal_coordinates(get_particle_index());
419  rot(get_particle()->get_value(internal::rigid_body_data()
420  .lquaternion_[0]),
421  get_particle()->get_value(internal::rigid_body_data()
422  .lquaternion_[1]),
423  get_particle()->get_value(internal::rigid_body_data()
424  .lquaternion_[2]),
425  get_particle()->get_value(internal::rigid_body_data()
426  .lquaternion_[3]));
427  return algebra::Transformation3D(rot, tr);
428  }
429 
430  //! XYZ::set_coordiantes()
431  // this is here since swig does like using statements
432  void set_coordinates(const algebra::Vector3D &center) {
433  XYZ::set_coordinates(center);
434  }
435 
436 #ifndef IMP_DOXYGEN
437  //! Set the coordinates from the internal coordinates
439  set_coordinates(tr.get_transformed(get_internal_coordinates()));
440  }
441 #endif
442  ~NonRigidMember();
443 
444  //! return true if it is a rigid member
445  static bool particle_is_instance(Particle *p) {
446  return particle_is_instance(p->get_model(), p->get_index());
447  }
448  //! return true if it is a rigid member
450  return internal::get_has_required_attributes_for_non_member(m, p);
451  }
452 
453  static FloatKeys get_internal_coordinate_keys() {
454  return internal::rigid_body_data().child_keys_;
455  }
456 };
457 
458 #ifndef IMP_DOXYGEN
459 
460 class IMPCOREEXPORT RigidMembersRefiner: public Refiner {
461  public:
462  RigidMembersRefiner(std::string name="RigidMembersRefiner%d"):Refiner(name){}
463  IMP_SIMPLE_REFINER(RigidMembersRefiner);
464 };
465 
466 namespace internal {
467  IMPCOREEXPORT RigidMembersRefiner* get_rigid_members_refiner();
468 }
469 #endif
470 
471 //! Transform a rigid body
472 /** The transformation is applied current conformation of the rigid
473  body, as opposed to replacing the current conformation, as in
474  RigidBody::set_reference_frame().
475 
476  \relatesalso RigidBody
477  algebra::Transformation3D
478 */
481 }
482 
483 /** Compute the rigid body reference frame given a set of input particles.
484  */
485 IMPCOREEXPORT algebra::ReferenceFrame3D
486 get_initial_reference_frame(const ParticlesTemp &ps);
487 
488 /** Create a set of rigid bodies that are bound together for efficiency.
489  These rigid bodies cannot nest or have other dependencies amongst them.
490 
491  All rigid bodies have the default reference frame.
492 
493  \note Do not use this with DOMINO as all the rigid bodies use the same
494  ScoreState and so will be considered inter-dependent.
495 */
496 IMPCOREEXPORT ParticlesTemp create_rigid_bodies(Model *m,
497  unsigned int n,
498  bool no_members=false);
499 
500 
501 IMP_DECORATORS_DEF(RigidMember,RigidMembers);
502 IMP_DECORATORS(RigidBody,RigidBodies, XYZs);
503 
504 IMPCORE_END_NAMESPACE
505 
506 #endif /* IMPCORE_RIGID_BODIES_H */