IMP logo
rigid_bodies.h
Go to the documentation of this file.
1 /**
2  * \file core/rigid_bodies.h
3  * \brief functionality for defining rigid bodies
4  *
5  * Copyright 2007-2012 IMP Inventors. All rights reserved.
6  */
7 
8 #ifndef IMPCORE_RIGID_BODIES_H
9 #define IMPCORE_RIGID_BODIES_H
10 
11 #include "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 
24 IMPCORE_BEGIN_NAMESPACE
25 
26 IMP_DECORATORS_DECL(RigidMember, RigidMembers);
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_local_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 also take a Refiner
44  to map from the rigid body to the set of particles
45  defining the geometry of interest.
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  RigidBodies can be nested (that is, a RigidBody can have
53  another RigidBody as a member). This can be useful for
54  organizational reasons as well as for accelerating
55  computations since since operations are affected by
56  the total number of children contained in the rigid body
57  being operated on. Examples of this include collision detection
58  where if you have multiple representations of geometry at
59  different resolutions it is faster to put each of them
60  in a separate rigid body and then creat one rigid body
61  containing all of them.
62 
63  It is often desirable to randomize the orientation of a rigid
64  body:
65  \pythonexample{randomize_rigid_body}
66 
67  \usesconstraint
68 
69  \see RigidMember
70  \see RigidBodyMover
71  \see RigidClosePairsFinder
72  \see RigidBodyDistancePairScore
73  */
74 class IMPCOREEXPORT RigidBody: public XYZ {
75  //! Return the location of a member particle given the current position
76  /** This method computes the coordinates of p given its internal coordinates
77  and the current position and orientation of the rigid body.
78  */
80 
81  void add_member_internal(Particle *p,
82  const algebra::ReferenceFrame3D &rf);
83  void on_change();
84  static void teardown_constraints(Particle *p);
85  static ObjectKey get_constraint_key_0();
86  static ObjectKey get_constraint_key_1();
87 public:
88 
89  RigidMembers get_members() const;
90 
91  //! Return the members as particle pointers
92  /** This member function is here
93  for efficiency.*/
94  const ParticleIndexes& get_member_particle_indexes() const {
95  static ParticleIndexes empty;
96  if (get_model()->get_has_attribute(internal::rigid_body_data().members_,
97  get_particle_index())) {
98  return get_model()->get_attribute(internal::rigid_body_data().members_,
99  get_particle_index());
100  } else {
101  return empty;
102  }
103  }
104 
105  const ParticleIndexes& get_body_member_particle_indexes() const {
106  static ParticleIndexes empty;
107  if (get_model()
108  ->get_has_attribute(internal::rigid_body_data().body_members_,
109  get_particle_index())) {
110  return get_model()
111  ->get_attribute(internal::rigid_body_data().body_members_,
112  get_particle_index());
113  } else {
114  return empty;
115  }
116  }
117 
118  IMP_DECORATOR(RigidBody, XYZ);
119 
120  //! Create a new rigid body from a set of particles.
121  /** \param[in] p The particle to make into a rigid body
122  \param[in] ps The particles to use as members of the rigid body
123 
124  The initial position and orientation of p is computed, as are the
125  relative positions of the member particles. The member particles
126  do not already need to be RigidMember particles, only
127  XYZ particles.
128  */
129  static RigidBody setup_particle(Particle *p,
130  const ParticlesTemp &ps);
131 
132 
133  /** Set it up with the provided initial reference frame.*/
135  const algebra::ReferenceFrame3D &rf);
136 
137  //! Make the rigid body no longer rigid.
138  static void teardown_particle(RigidBody rb);
139 
141 
142  //!Return true of the particle is a rigid body
143  static bool particle_is_instance(Particle *p) {
144  return internal::get_has_required_attributes_for_body(p->get_model(),
145  p->get_index());
146  }
147 
148  //!Return true of the particle is a rigid body
149  static bool particle_is_instance(Model *m, ParticleIndex pi) {
150  return internal::get_has_required_attributes_for_body(m, pi);
151  }
152 
153  // swig doesn't support using, so the method is wrapped
154  //! Get the coordinates of the particle
156  return XYZ::get_coordinates();
157  }
158 
159  //! Get the reference frame for the local coordinates
160  IMP::algebra::ReferenceFrame3D get_reference_frame() const {
162  v(get_particle()->get_value(internal::rigid_body_data().quaternion_[0]),
163  get_particle()->get_value(internal::rigid_body_data().quaternion_[1]),
164  get_particle()->get_value(internal::rigid_body_data().quaternion_[2]),
165  get_particle()->get_value(internal::rigid_body_data().quaternion_[3]));
166  IMP_USAGE_CHECK(std::abs(v.get_squared_magnitude() -1) < .1,
167  "Rotation is not a unit vector: " << v);
168  /*if (v.get_squared_magnitude() > 0){
169  v = v.get_unit_vector();
170  } else {
171  v = algebra::VectorD<4>(1,0,0,0);
172  }*/
175  get_coordinates()));
176  }
177 
178  //! Set the current reference frame
179  /** All members of the rigid body will have their coordinates updated
180  immediately.
181  \see IMP::core::transform(RigidBody,const algebra::Transformation3D&)
182  \see lazy_set_reference_frame()
183  */
184  void set_reference_frame(const IMP::algebra::ReferenceFrame3D &tr);
185 
186  //! Change the reference, delay updating the members until evaluate
187  /** See set_transformation()
188  */
189  void set_reference_frame_lazy(const IMP::algebra::ReferenceFrame3D &tr);
190 
191 #ifndef IMP_DOXYGEN
192  /** This takes a cartesian derivative, and a location in internal coordinates.
193 
194  It is currently hidden since the function signature is highly ambiguous.
195  */
196  void add_to_derivatives(const algebra::Vector3D &derivative,
197  const algebra::Vector3D &local_location,
198  DerivativeAccumulator &da);
199 
200  void add_to_derivatives(const algebra::Vector3D &derivative,
201  const algebra::Vector3D &global_derivative,
202  const algebra::Vector3D &local_location,
203  const algebra::Rotation3D &rot,
204  DerivativeAccumulator &da);
205 
206  /** The units are kCal/Mol/Radian */
207  algebra::Vector3D get_torque() const {
208  algebra::Vector3D ret;
209  for (unsigned int i=0; i< 3; ++i) {
210  ret[i]
211  =get_particle()
212  ->get_derivative(internal::rigid_body_data().torque_[i]);
213  }
214  return ret;
215  }
216 #endif
217 
218  bool get_coordinates_are_optimized() const;
220  //! Set whether the rigid body coordinates are optimized
221  void set_coordinates_are_optimized(bool tf);
222 
223  //! Normalized the quaternion
224  void normalize_rotation();
225 
226  //! Update the coordinates of the members
227  void update_members();
228 
229  //! Get the derivatives of the quaternion
230  algebra::VectorD<4> get_rotational_derivatives() const;
232  unsigned int get_number_of_members() const {
233  return get_body_member_particle_indexes().size()
234  + get_member_particle_indexes().size();
235  }
237  RigidMember get_member(unsigned int i) const;
238 
239  /** Add a member, properly handle rigid bodies and XYZ particles.
240  */
241  void add_member(Particle *p);
242 };
243 
244 
245 /** It is often useful to store precalculated properties of the rigid body
246  for later use. These need to be cleared out when the rigid body changes.
247  To make sure this happens, register the key here.
248 */
249 void IMPCOREEXPORT add_rigid_body_cache_key(ObjectKey k);
250 
251 
252 //! A decorator for a particle that is part of a rigid body
253 /**
254  \see RigidBody
255  */
256 class IMPCOREEXPORT RigidMember: public XYZ {
257  public:
259 
260  RigidBody get_rigid_body() const;
261 
262  //! Return the current orientation of the body
263  const algebra::Vector3D& get_internal_coordinates() const {
264  return get_model()->get_internal_coordinates(get_particle_index());
265  }
266 
267  //! set the internal coordinates for this member
268  void set_internal_coordinates(const algebra::Vector3D &v) const {
269  get_model()->get_internal_coordinates(get_particle_index())=v;
270  get_rigid_body().get_particle()->clear_caches();
271  }
272  //! Member must be a rigid body
273  void set_internal_transformation(const algebra::Transformation3D& v) {
275  get_particle()->has_attribute(internal::rigid_body_data().lquaternion_[0]),
276  "Can only set the internal transformation if member is"
277  << " a rigid body itself.");
278  set_internal_coordinates(v.get_translation());
279 
280  get_particle()->set_value(internal::rigid_body_data().lquaternion_[0],
281  v.get_rotation().get_quaternion()[0]);
282  get_particle()->set_value(internal::rigid_body_data().lquaternion_[1],
283  v.get_rotation().get_quaternion()[1]);
284  get_particle()->set_value(internal::rigid_body_data().lquaternion_[2],
285  v.get_rotation().get_quaternion()[2]);
286  get_particle()->set_value(internal::rigid_body_data().lquaternion_[3],
287  v.get_rotation().get_quaternion()[3]);
288  get_rigid_body().get_particle()->clear_caches();
289  }
290 
291  algebra::Transformation3D get_internal_transformation() const {
293  get_particle()->has_attribute(internal::rigid_body_data().lquaternion_[0]),
294  "Can only set the internal transformation if member is a "
295  << "rigid body itself.");
297  =get_model()->get_internal_coordinates(get_particle_index());
299  rot(get_particle()->get_value(internal::rigid_body_data()
300  .lquaternion_[0]),
301  get_particle()->get_value(internal::rigid_body_data()
302  .lquaternion_[1]),
303  get_particle()->get_value(internal::rigid_body_data()
304  .lquaternion_[2]),
305  get_particle()->get_value(internal::rigid_body_data()
306  .lquaternion_[3]));
307  return algebra::Transformation3D(rot, tr);
308  }
309 
310  //! XYZ::set_coordiantes()
311  // this is here since swig does like using statements
312  void set_coordinates(const algebra::Vector3D &center) {
313  XYZ::set_coordinates(center);
314  }
315 #ifndef IMP_DOXYGEN
316  //! Set the coordinates from the internal coordinates
317  void set_coordinates(const algebra::Transformation3D &tr) {
318  set_coordinates(tr.get_transformed(get_internal_coordinates()));
319  }
320 #endif
321  ~RigidMember();
322 
323  //! return true if it is a rigid member
324  static bool particle_is_instance(Particle *p) {
325  return particle_is_instance(p->get_model(), p->get_index());
326  }
327  //! return true if it is a rigid member
328  static bool particle_is_instance(Model *m, ParticleIndex p) {
329  return internal::get_has_required_attributes_for_member(m, p);
330  }
331 };
332 
333 #ifndef IMP_DOXYGEN
334 
335 class IMPCOREEXPORT RigidMembersRefiner: public Refiner {
336  public:
337  RigidMembersRefiner(std::string name="RigidMembersRefiner%d"):Refiner(name){}
338  IMP_SIMPLE_REFINER(RigidMembersRefiner);
339 };
340 
341 namespace internal {
342  IMPCOREEXPORT RigidMembersRefiner* get_rigid_members_refiner();
343 }
344 #endif
345 
346 //! Transform a rigid body
347 /** The transformation is applied current conformation of the rigid
348  body, as opposed to replacing the current conformation, as in
349  RigidBody::set_transformation().
350 
351  \relatesalso RigidBody
352  algebra::Transformation3D
353 */
354 inline void transform(RigidBody a, const algebra::Transformation3D&tr) {
355  a.set_reference_frame(get_transformed(a.get_reference_frame(), tr));
356 }
357 
358 /** Compute the rigid body reference frame given a set of input particles.
359  */
360 IMPCOREEXPORT algebra::ReferenceFrame3D
361 get_initial_reference_frame(const ParticlesTemp &ps);
362 
363 /** Create a set of rigid bodies that are bound together for efficiency.
364  These rigid bodies cannot nest or have other dependencies amongst them.
365 
366  All rigid bodies have the default reference frame.
367 */
368 IMPCOREEXPORT ParticlesTemp create_rigid_bodies(Model *m,
369  unsigned int n,
370  bool no_members=false);
371 
372 
373 IMP_DECORATORS_DEF(RigidMember,RigidMembers);
374 IMP_DECORATORS(RigidBody,RigidBodies, XYZs);
375 
376 IMPCORE_END_NAMESPACE
377 
378 #endif /* IMPCORE_RIGID_BODIES_H */

Generated on Tue May 22 2012 23:33:16 for IMP by doxygen 1.8.1