IMP  2.2.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-2014 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 
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_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  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 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 create one rigid body
61  containing all of them.
62 
63  It is often desirable to randomize the orientation of a rigid
64  body:
65  \include randomize_rigid_body.py
66 
67  \usesconstraint
68 
69  \see RigidMember
70  \see NonRigidMember
71  \see RigidBodyMover
72  \see RigidClosePairsFinder
73  \see RigidBodyDistancePairScore
74  */
75 class IMPCOREEXPORT RigidBody : public XYZ {
76  private:
77  /* Computes the coordinates of p given its internal (local)
78  coordinates and the current position and orientation of the
79  rigid body.
80  */
82 
83  void add_member_internal(kernel::Particle *p,
84  const algebra::ReferenceFrame3D &rf);
85 
86  void on_change();
87 
88  static void teardown_constraints(kernel::Particle *p);
89 
90  static ObjectKey get_constraint_key_0();
91 
92  static ObjectKey get_constraint_key_1();
93 
94  // setup rigid body atrributes with particles in ps, using their
95  // center of mass, inertia tensor to initialize the reference frame
96  static void do_setup_particle(kernel::Model *m, kernel::ParticleIndex pi,
98 
99  // setup a rigid body with specified reference frame
100  static void do_setup_particle(kernel::Model *m, kernel::ParticleIndex pi,
101  const algebra::ReferenceFrame3D &rf);
102 
103  void setup_score_states();
104 
105  // add a member associated with xyz coords (if it has a ref frame,
106  // it is still being ignored)
107  void add_point_member(kernel::ParticleIndex pi);
108 
109  // add a member associated with a reference frame
110  void add_rigid_body_member(kernel::ParticleIndex pi);
111 
112  public:
113  /** This method does not return non-rigid members.
114 
115  \deprecated_at{2.2} Use get_rigid_members() instead.
116  */
117  IMPCORE_DEPRECATED_FUNCTION_DECL(2.2)
118  RigidMembers get_members() const {
119  IMPCORE_DEPRECATED_FUNCTION_DEF(2.2, "Use get_rigid_members() instead.");
120  return get_rigid_members();
121  }
122 
123  RigidMembers get_rigid_members() const;
124 
125  //! Returns a list of all members that are not themselves decoared as
126  //! rigid bodies, in the form of particle indexes.
128  static kernel::ParticleIndexes empty;
129  if (get_model()->get_has_attribute(internal::rigid_body_data().members_,
130  get_particle_index())) {
131  return get_model()->get_attribute(internal::rigid_body_data().members_,
133  } else {
134  return empty;
135  }
136  }
137 
138  //! Get all members that are themselved decorated as rigid bodies,
139  //! as model particle indexes
141  static kernel::ParticleIndexes empty;
142  if (get_model()->get_has_attribute(
143  internal::rigid_body_data().body_members_, get_particle_index())) {
144  return get_model()->get_attribute(
145  internal::rigid_body_data().body_members_, get_particle_index());
146  } else {
147  return empty;
148  }
149  }
150 
151  //! Get the particle indexes of any member of this rigid body, regardless
152  //! of whether it is itself a rigid body or not
154  return get_member_particle_indexes() + get_body_member_particle_indexes();
155  }
156 
158 
159  /**
160  Create a rigid body for pi with the particle indexes ps as its members.
161  The coordinates of pi are set to the center of mass of ps and the rotation
162  of its reference frame is based on the diagnolized intertia tensor of ps.
163 
164  @note If size(ps)=1, then its reference frame is copied if it is a rigid body, \
165  or its rotation is set to identity if it is not a rigid body.
166 
167  */
169 
170  /**
171  Create a rigid body with the passed reference frame as its initial
172  position.
173  */
175 
176  //! Make the rigid body no longer rigid.
177  static void teardown_particle(RigidBody rb);
178 
179  IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(RigidBody);
180  ~RigidBody();
181 
182  /** Return true if the particle is a rigid body */
184  return internal::get_has_required_attributes_for_body(m, pi);
185  }
186 
187  // swig doesn't support using, so the method is wrapped
188  //! Get the coordinates of the particle
190 
191  //! Get the reference frame for the local coordinates
194  get_model()->get_attribute(internal::rigid_body_data().quaternion_[0],
196  get_model()->get_attribute(internal::rigid_body_data().quaternion_[1],
198  get_model()->get_attribute(internal::rigid_body_data().quaternion_[2],
200  get_model()->get_attribute(internal::rigid_body_data().quaternion_[3],
201  get_particle_index()));
202  IMP_USAGE_CHECK_FLOAT_EQUAL(v.get_squared_magnitude(), 1,
203  "Rotation is not a unit vector: " << v);
204  /*if (v.get_squared_magnitude() > 0){
205  v = v.get_unit_vector();
206  } else {
207  v = algebra::VectorD<4>(1,0,0,0);
208  }*/
209  bool assume_normalized = true;
210  IMP::algebra::Rotation3D rot(v, assume_normalized);
213  }
214 
215  //! Set the current reference frame
216  /** All members of the rigid body will have their coordinates updated
217  immediately.
218  \see IMP::core::transform(RigidBody,const algebra::Transformation3D&)
219  \see lazy_set_reference_frame()
220  */
221  void set_reference_frame(const IMP::algebra::ReferenceFrame3D &tr);
222 
223  //! Change the reference, delay updating the members until evaluate
224  /** See set_reference_frame()
225  */
226  void set_reference_frame_lazy(const IMP::algebra::ReferenceFrame3D &tr);
227 
228  /** Update the reference frame of the rigid body based on aligning
229  the current global coordinates of the passed rigid body members
230  onto their old local coordinates. Non-passed members are ignored.
231 
232  This method is useful for updating the rigid body after new
233  global coordinates were loaded for the members. The members are
234  passed explictily since, typically, some are desired to just
235  move along with the newly loaded rigid body.
236 
237  \note This requires at least three members that are not collinear
238  to work.
239  */
240  void set_reference_frame_from_members(const kernel::ParticleIndexes &members);
241 
242 #ifndef IMP_DOXYGEN
243  /** This takes a cartesian derivative, and a location in internal coordinates.
244 
245  It is currently hidden since the function signature is highly ambiguous.
246  */
247  void add_to_derivatives(const algebra::Vector3D &derivative,
248  const algebra::Vector3D &local_location,
250 
251  void add_to_derivatives(const algebra::Vector3D &derivative,
252  const algebra::Vector3D &global_derivative,
253  const algebra::Vector3D &local_location,
254  const algebra::Rotation3D &rot,
256 #endif
257 
258  /** The units are kCal/Mol/Radian */
260  algebra::Vector3D ret;
261  for (unsigned int i = 0; i < 3; ++i) {
262  ret[i] = get_model()->get_derivative(
263  internal::rigid_body_data().torque_[i], get_particle_index());
264  }
265  return ret;
266  }
267 
268  //! Returns true if the rigid body coordinates are flagged as
269  //! optimized for Optimizer objects
270  bool get_coordinates_are_optimized() const;
271 
272  //! Set whether the rigid body coordinates are flagged as optimized
273  //! for Optimizer objects
274  void set_coordinates_are_optimized(bool tf);
275 
276  //! Normalize the quaternion
277  void normalize_rotation();
278 
279  //! Update the global coordinates of the members based on
280  //! their local coordinates and this rigid body's reference frame
281  void update_members();
282 
283  //! Get the derivatives of the quaternion
284  algebra::VectorD<4> get_rotational_derivatives() const;
285 
286 #ifndef IMP_DOXYGEN
287  unsigned int get_number_of_members() const {
288  return get_body_member_particle_indexes().size() +
289  get_member_particle_indexes().size();
290  }
291 
292  RigidMember get_member(unsigned int i) const;
293 #endif
294  //! Add a proper member that moves rigidly with this rigid body,
295  //! properly handling rigid bodies and XYZ particles.
296  /**
297  Add p to the list of members. If p is a valid RigidBody, it is added
298  as a rigid body member, otherwise it is added as a point member
299  (for which the rotation is not tracked). By default, p is considered
300  a strictly rigid member, in that its local coordinates are not expected
301  to change independetly.
302 
303  \see add_non_rigid_member
304  */
305  void add_member(kernel::ParticleIndexAdaptor p);
306 
307  /** Add a non-rigid member, for which internal coordinates may change
308  independently.
309 
310  @note Currently RigidBody non-rigid members are not handled properly.
311  */
312  void add_non_rigid_member(kernel::ParticleIndex pi);
313 
314  /** Set whether a particular member is flagged as a rigid member
315  or as a non-rigid member. This affects the way the rigid body
316  updates the coordinates and / or reference frame of its members.
317  */
318  void set_is_rigid_member(kernel::ParticleIndex pi, bool tf);
319 };
320 
321 /** It is often useful to store precalculated properties of the rigid body
322  for later use. These need to be cleared out when the rigid body changes.
323  To make sure this happens, register the key here.
324 */
325 void IMPCOREEXPORT add_rigid_body_cache_key(ObjectKey k);
326 
327 //! A member of a rigid body, it has internal (local) coordinates
328 class IMPCOREEXPORT RigidBodyMember : public XYZ {
330 
331  RigidBody get_rigid_body() const;
332 
333  //! Return the internal (local) coordinates of this member
334  /** Return the internal (local) coordinates of this member
335  relative to the reference frame of the rigid body that owns it
336  */
338  return get_model()->get_internal_coordinates(get_particle_index());
339  }
340 
341  //! set the internal (local) coordinates for this member
343  get_model()->get_internal_coordinates(get_particle_index()) = v;
344  get_rigid_body().get_model()->clear_particle_caches(get_particle_index());
345  }
346 
347  //! Set the internal (local) coordinates of this member,
348  //! assuming it is a rigid body itself
349  /** Set the internal (local) coordinates of this rigid body
350  relative to the reference frame of the rigid body that owns it
351  */
354  get_model()->get_has_attribute(
355  internal::rigid_body_data().lquaternion_[0], get_particle_index()),
356  "Can only set the internal transformation if member is"
357  << " a rigid body itself.");
358  set_internal_coordinates(v.get_translation());
359 
360  get_model()->set_attribute(internal::rigid_body_data().lquaternion_[0],
362  v.get_rotation().get_quaternion()[0]);
363  get_model()->set_attribute(internal::rigid_body_data().lquaternion_[1],
365  v.get_rotation().get_quaternion()[1]);
366  get_model()->set_attribute(internal::rigid_body_data().lquaternion_[2],
368  v.get_rotation().get_quaternion()[2]);
369  get_model()->set_attribute(internal::rigid_body_data().lquaternion_[3],
371  v.get_rotation().get_quaternion()[3]);
372  get_rigid_body().get_model()->clear_particle_caches(get_particle_index());
373  }
374 
375  //! Return the internal (local) coordinates of this member,
376  //! assuming it is a rigid body itself
377  /** Return the internal (local) coordinates of this rigid body
378  relative to the reference frame of the rigid body that owns it
379  */
382  get_model()->get_has_attribute(
383  internal::rigid_body_data().lquaternion_[0], get_particle_index()),
384  "Can only set the internal transformation if member is a "
385  << "rigid body itself.");
386  algebra::Vector3D tr =
387  get_model()->get_internal_coordinates(get_particle_index());
389  get_model()->get_attribute(internal::rigid_body_data().lquaternion_[0],
391  get_model()->get_attribute(internal::rigid_body_data().lquaternion_[1],
393  get_model()->get_attribute(internal::rigid_body_data().lquaternion_[2],
395  get_model()->get_attribute(internal::rigid_body_data().lquaternion_[3],
396  get_particle_index()));
397  return algebra::Transformation3D(rot, tr);
398  }
399 
400  ~RigidBodyMember();
401  //! sets the global coordinates of this member using XYZ::set_coordiantes()
402  // this is here since swig does like using statements
403  void set_coordinates(const algebra::Vector3D &center) {
404  XYZ::set_coordinates(center);
405  }
406 
407 #ifndef IMP_DOXYGEN
408  //! Set the global coordinates from the internal coordinates,
409  //! using tr as a reference frame
411  set_coordinates(tr.get_transformed(get_internal_coordinates()));
412  }
413 #endif
414  IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(RigidBodyMember);
415 
416  //! return true if it is a rigid member
418  return internal::get_has_required_attributes_for_member(m, p);
419  }
420 
421  static FloatKeys get_internal_coordinate_keys() {
422  return internal::rigid_body_data().child_keys_;
423  }
424 };
425 
426 //! A decorator for a particle that is part of a rigid body, and is
427 //! actually rigid
428 /**
429  RigidMember particles, as opposed to NonRigidMember particles, are
430  not expected to change their internal (local) coordinates or
431  reference frames, and their global coordinates are expected to
432  change only through setting the cooridnates (or reference frame) of
433  the rigid body that owns them.
434 
435  \see RigidBody
436  */
437 class IMPCOREEXPORT RigidMember : public RigidBodyMember {
438  public:
440 
441  IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(RigidMember);
442  ~RigidMember();
443 
444  //! return true if it is a rigid member
446  return internal::get_has_required_attributes_for_rigid_member(m, p);
447  }
448 };
449 
450 //! A decorator for a particle that is part of a rigid body but not rigid
451 /** NonRigidMembers, like RigidMembers have internal coordinates and move
452  along with the rigid body. However, it is expected that their internal
453  coordinates will change, and so they are not part of structures that
454  assume rigidity.
455 
456  \see RigidBody
457  */
458 class IMPCOREEXPORT NonRigidMember : public RigidBodyMember {
459  public:
461  IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(NonRigidMember);
462  ~NonRigidMember();
463 
464  //! return true if it is a rigid member
466  return internal::get_has_required_attributes_for_non_member(m, p);
467  }
468 };
469 
470 #ifndef IMP_DOXYGEN
471 
472 class IMPCOREEXPORT RigidMembersRefiner : public Refiner {
473  public:
474  RigidMembersRefiner(std::string name = "RigidMembersRefiner%d")
475  : Refiner(name) {}
476  virtual bool get_can_refine(kernel::Particle *) const IMP_OVERRIDE;
477 #ifndef SWIG
478  using Refiner::get_refined;
479 #endif
480  virtual const kernel::ParticlesTemp get_refined(kernel::Particle *) const
481  IMP_OVERRIDE;
482  virtual kernel::ModelObjectsTemp do_get_inputs(
483  kernel::Model *m, const kernel::ParticleIndexes &pis) const IMP_OVERRIDE;
484  IMP_OBJECT_METHODS(RigidMembersRefiner);
485 };
486 
487 namespace internal {
488 IMPCOREEXPORT RigidMembersRefiner *get_rigid_members_refiner();
489 }
490 #endif
491 
492 //! Transform a rigid body
493 /** The transformation is applied current conformation of the rigid
494  body, as opposed to replacing the current conformation, as in
495  RigidBody::set_reference_frame().
496 
497  See RigidBody
498  algebra::Transformation3D
499 */
500 inline void transform(RigidBody a, const algebra::Transformation3D &tr) {
501  a.set_reference_frame(get_transformed(a.get_reference_frame(), tr));
502 }
503 
504 /** Compute the rigid body reference frame given a set of input particles.
505  */
506 IMPCOREEXPORT algebra::ReferenceFrame3D get_initial_reference_frame(
507  kernel::Model *m, const kernel::ParticleIndexes &pis);
508 
509 inline algebra::ReferenceFrame3D get_initial_reference_frame(
510  const kernel::ParticlesTemp &ps) {
511  if (ps.empty()) {
512  return algebra::ReferenceFrame3D();
513  }
514  return get_initial_reference_frame(ps[0]->get_model(),
515  kernel::get_indexes(ps));
516 }
517 
518 /** Create a set of rigid bodies that are bound together for efficiency.
519  These rigid bodies cannot nest or have other dependencies amongst them.
520 
521  All rigid bodies have the default reference frame.
522 
523  \note Do not use this with DOMINO as all the rigid bodies use the same
524  ScoreState and so will be considered inter-dependent.
525 */
526 IMPCOREEXPORT kernel::ParticlesTemp create_rigid_bodies(kernel::Model *m,
527  unsigned int n,
528  bool no_members =
529  false);
530 
531 IMP_DECORATORS_DEF(RigidMember, RigidMembers);
532 IMP_DECORATORS(RigidBody, RigidBodies, XYZs);
533 
534 /** Show the rigid body hierarchy rooted at passed body. */
535 IMPCOREEXPORT void show_rigid_body_hierarchy(RigidBody rb,
536  base::TextOutput out =
537  base::TextOutput(std::cout));
538 
539 /** Return the particle index of the outer-most rigid body containing the
540  member.
541 
542  Use this to, for example, group particles into rigid bodies. */
543 IMPCOREEXPORT kernel::ParticleIndex get_root_rigid_body(RigidMember m);
544 
545 IMPCORE_END_NAMESPACE
546 
547 #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:79
void set_internal_coordinates(const algebra::Vector3D &v) const
set the internal (local) coordinates for this member
Definition: rigid_bodies.h:342
Import IMP/kernel/SingletonModifier.h in the namespace.
ParticleIndex get_particle_index() const
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 (local) coordinates.
Definition: rigid_bodies.h:328
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:189
static bool get_is_setup(kernel::Model *m, kernel::ParticleIndex pi)
Definition: rigid_bodies.h:183
const kernel::ParticleIndexes & get_member_particle_indexes() const
Definition: rigid_bodies.h:127
#define IMP_DECORATOR_METHODS(Name, Parent)
Model * get_model() const
Returns the Model containing the particle.
bool get_coordinates_are_optimized() const
Get whether the coordinates are optimized.
Definition: XYZ.h:86
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:192
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:259
void set_reference_frame(const IMP::algebra::ReferenceFrame3D &tr)
Set the current reference frame.
A Cartesian vector in D-dimensions.
Definition: VectorD.h:52
Import IMP/kernel/Refiner.h in the namespace.
void set_coordinates(const algebra::Vector3D &v)
set all coordinates from a vector
Definition: XYZ.h:62
IMP::kernel::Model Model
kernel::ParticleIndexes get_member_indexes() const
Definition: rigid_bodies.h:153
Represent an XYZR particle with a sphere.
A decorator for a particle with x,y,z coordinates.
Definition: XYZ.h:30
#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:445
const algebra::Vector3D & get_coordinates() const
Convert it to a vector.
Definition: XYZ.h:107
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:458
Simple 3D rotation class.
void set_internal_transformation(const algebra::Transformation3D &v)
Definition: rigid_bodies.h:352
3D rotation class.
Definition: Rotation3D.h:46
void set_coordinates_are_optimized(bool tf) const
Set whether the coordinates are optimized.
Definition: XYZ.h:92
static bool get_is_setup(kernel::Model *m, kernel::ParticleIndexAdaptor p)
return true if it is a rigid member
Definition: rigid_bodies.h:417
base::Index< ParticleIndexTag > ParticleIndex
Key< 4, true > ObjectKey
The type used to identify an Object attribute.
void set_coordinates(const algebra::Vector3D &center)
sets the global coordinates of this member using XYZ::set_coordiantes()
Definition: rigid_bodies.h:403
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:465
void show_rigid_body_hierarchy(RigidBody rb, base::TextOutput out=base::TextOutput(std::cout))
kernel::ParticlesTemp create_rigid_bodies(kernel::Model *m, unsigned int n, bool no_members=false)
VectorD< 3 > Vector3D
Definition: VectorD.h:395
kernel::ParticleIndex get_root_rigid_body(RigidMember m)
Simple 3D vector class.
void transform(RigidBody a, const algebra::Transformation3D &tr)
Transform a rigid body.
Definition: rigid_bodies.h:500
Simple 3D rotation class.
void clear_particle_caches(ParticleIndex pi)
A decorator for a rigid body.
Definition: rigid_bodies.h:75
algebra::Transformation3D get_internal_transformation() const
Definition: rigid_bodies.h:380
Abstract class to implement hierarchical methods.
#define IMP_DECORATOR_SETUP_1(Name, FirstArgumentType, first_argument_name)
Decorator for a sphere-like particle.
const kernel::ParticleIndexes & get_body_member_particle_indexes() const
Definition: rigid_bodies.h:140
#define IMP_DECORATORS(Name, PluralName, Parent)
Define the types for storing sets of decorators.
const algebra::Vector3D & get_internal_coordinates() const
Return the internal (local) coordinates of this member.
Definition: rigid_bodies.h:337
Class for storing model, its restraints, constraints, and particles.
Definition: kernel/Model.h:72
IMP::algebra::ReferenceFrame3D get_reference_frame() const
Get the reference frame for the local coordinates.
Definition: rigid_bodies.h:192